PHPでHTMLメールを送信する – MIMEを知れば怖くない!

今進めているウェブアプリケーションの開発案件に、SPA(シングル・ページ・アプリケーション)型の診断サイトがあります。

そして、この診断サイトですが、アンケート型の設問に答えて行くと、最後に診断結果が受け取れるのですが、この診断結果ページのリンクはメールで届く仕様なんです。

ここで問題になるのが、URLリンク付きのメール、つまりHTMLメールの送信が必要なものとなります。

普段、何気にメーラーでメールを受信したり、送信したりしている一般ユーザーの方は、「そんなの当たり前じゃん!」と思うかもしれませんね。

でも、実はインターネットを利用したメールの送受信技術はとても奥深く、簡単ではないんです。

よくホームページに問い合わせフォームが設置されていますが、あれって大抵がHTML形式のメールは送れないんですよね。プレーンテキストタイプのメールフォームなんです。

メールのヘッダーを見て頂くと分かりますが、「Content-type」が「plain/text」になっている筈です。

実はインターネットを利用したメールの送受信の技術は、MIME(Multipurpose Internet Mail Extensions、通称マイム)という国際仕様に基づいて送受信しないといけません。

元々は、インターネットメールは、日本語や一般的なアルファベット以外の言語には対応しておらず、全てASCII文字(American Standard Code for Information Interchange)という、英語や西ヨーロッパ言語で使われるラテン文字を中心とした文字コードにしか対応していませんでした。

パソコンにおいて、バイトという容量の単位がありますが、1バイトは8ビットという基準が定められたのも、このASCIIコードが基準だからです。ASCIIコードで定められたアルファベットやその他記号(+ , – ! *等)を2進数で表現しようとすると8ビット(2の8乗とおり、256通り)必要だからです。半角文字は1バイトの理由です。

話がそれましたが、インターネットが始まった頃は、先のとおり、メールはASCII文字しか送れなかったわけです。また、画像や音声等のバイナリーデータも送信できませんでした。

しかし、これはASCIIコード文字体系以外の地域では非常に困りますし、インターネットの技術が発展するにつれて画像や音声も送信する必要も出てきたわけです。そこで考えられたのが先のMIMEという国際規格です。

MIMEでは本文を複数のパートに分割し、複数の種類のコンテンツを送信できるように考えられており、これをマルチパートフォーマットと呼びます。

また、MIME仕様で送信されたメールであると受信メーラーが判別できるように、メールヘッダーに記載する内容も仕様で決まっています。

また、メールヘッダーもMIMEメッセージヘッダとMIMEパートヘッダの二種類あり、MIMEメッセージヘッダがマルチパートフォーマット全体に適用され、MIMEパートヘッダはマルチパートフォーマットの各部分に記述の必要があります。

1.MIMEメッセージヘッダへの記載事項

いわゆるメールヘッダー(From、to、Reply-to、Subject等)以外に、MIME仕様独特のヘッダーを記載する必要があります。

Mime-Version: 1.0

MIME仕様でメールを送っているよ、という意味で、ヘッダーの冒頭に記載します。現在のバージョンは1.0しかありません。これはお決まりでそのまま記載します。

Content-Type: Multipart/Mixed

先のとおり、MIMEはマルチパート構成で複数の種類のデータを送信するわけですが、このマルチパートの構成(フォーマット)を示すための記述です。上の例では「Multipart/Mixed」にしていますが、これは、plain/textやHTML/text以外に、添付画像等のバイナリデータのパートを含んでいることを示します。

これ以外にも、

Content-Type: Multipart/Alternative

等があります。HTMLメールを送るだけならば、このContent-Type: Multipart/AlternativeでOKです。

他にもいくつかありますが、ここではHTMLメールの送信技術の解説なので割愛いたします。

このMIMEメッセージヘッダに記載するContent-Type(マルチパートのフォーマット)部分ですが、MIMEメッセージヘッダにおいては、このContent-Typeに並んで重要なパラメーターの記述が必要です。そのパラメーターとは、boudaryパラメーターです。

このboudaryパラメーターは、マルチパートの区切りを示す符号です。この符号は自由につけれます。以下、参考例。

Content-Type: Multipart/Alternative; boudary="exampleboudary"

後ほど使い方は記述しますが、このboudaryはマルチパートを区切るための符号です。

次に、ASCII文字以外の文字をどの符号方式にエンコードして送っているのかを受信メーラーに伝える必要があり、

Content-Transfer-Encoding: 7bit

のようなヘッダーの記載も必要です。上記の7bit以外にも、8bitやbase64といったエンコード方式もあります。このあたり、かなり文字コードに詳しくないとどれを選べばいいのか分からないと思います。今回はHTMLメールを送信する技術の解説ですので、今回は7bitにしましょう(とりあえず7bitで十分です)。

とりあえず、HTMLメールを送信する際のMIMEメッセージヘッダはこれだけでOKです。

2.MIMEパートヘッダへの記載事項

これは、各パートごとにヘッダーが必要な事を意味します。そのパートの中身が単なるテキストなのか、テキストはテキストでもHTML形式のテキストなのか、それとも画像なのかといったコンテンツの中身を示すために、先の1.MIMEメッセージヘッダと同じように、Content-Typeを記載します。ここで記載するContent-Typeは、マルチパート全体のフォーマットではなく、各部分のパートの中身のフォーマットを記載します。以下、記載例。

Content-Type: text/plain

これは一般的なテキストのみのメールの場合ですね。他に、

Content-Type: text/html

これはHTML形式のテキストであることを示します。HTMLメールはこの形式で送ります。

その他、

Content-Type: Image/Gif

このヘッダーがあるパートの中身はGIF画像であることを示します。いわゆる添付画像ですね。

MIMEメッセージヘッダにおいては、Content-Typeと並んでboudaryというパラメータを併記しましたが、MIMEパートヘッダには、そのパートの中身がtext/plainかtext/htmlの場合は、charsetというパラメーターの併記が必要です。

Content-Type: Text/HTML; charset=ISO-2022-JP

以上のように併記します。私は日本語圏の人間ですので、受け取る側も日本語圏です。なのでcharsetは日本語文字コードであるISO-2022-JP(いわゆるJISコード)を指定しているわけです。「JISコードでデータ送るよ!」と受信側メーラーに伝えているわけです。

その他、MIMEパートヘッダにはMIMEメッセージヘッダと同じようにエンコード方式の記載も必要です。エンコード方式の種類はMIMEメッセージヘッダで説明したとおり、7bit、8bit、base64等があります。パートの中身に応じてエンコード方式が異なりますが、HTMLメールを送信する場合は、MIMEメッセージヘッダと同じく、7bitでOKです。

Content-Transfer-Encoding: 7bit

これでOK。

3.文字コードのエンコードに注意

既に解説したとおり、インターネットメールの技術ではASCIIコードでしか送信できません。

いやおかしい、だからMIMEって仕様があるんでしょ?と思う方もいる筈です。確かに今や、インターネットメールはMIME仕様というASCIIコード以外の文字体系やバイナリーデータに対応した拡張された規格が流通しているので、ASCIIコード文字以外の文字やバイナリーも送信できます。しかし、これは日本語や画像を送る場合は、エンコードと言って文字コードをASCII文字列の並びに変換して送っているだけで、結局はASCIIコードでやり取りしています。

だから、先のメッセージヘッダやパートヘッダにはContent-Transfer-Encodingやcharsetといったパラメータで、受信側メーラーがデコード(復号化)できるようにエンコード(符号化)方式を記述するわけです。

そして、ヘッダーやメッセージボディ部分にASCII文字体系以外のデータ、例えば日本語やバイナリー等が存在するパートである場合、ヘッダーで指定したエンコード方式でエンコードしておかなくてはなりません。

ヘッダーで、文字コードをISO-2022-JPに指定しているのに、メッセージボディ部分の文字コードががUTF-8であった場合、受信したメーラーで文字化けします。

ヘッダーのエンコードで注意が必要なのは、SubjectやFrom、toの部分でしょうか。Subject、いわゆるメールのタイトルには普通日本語を使いますし、From部分にも送信者名を日本語で記載したりしますよね。

このような部分は文字コードの変換が必要となります。PHP言語では、メールヘッダー部分の文字コード変換には、mb_encode_mimeheader()という関数がありますのでこれを使います。

メッセージボディ部分は、HTMLメールの場合、基本的に全てmb_convert_encoding()という関数で、ヘッダーで指定した文字コード(今回のケースだとISO-2022-JP、つまりはJISコードですね)に変換します。

4.サンプル

HTMLメールを送信するサンプルです。

このサンプルは、MIME仕様に準拠しておりますので、一通りの環境で受信出来る筈です。ヤフーメールやGMAIL、ドコモやau、ソフトバンクまで。

一部受信出来ない環境は、メールサーバー間の相性や迷惑メールフィルターが原因として考えられます。

正しくMIME仕様で送ってもこればかりはどうしようもありません。

<?php
/* ##### ユーザーに応じて、送信元メールアドレス、送信者の名前を書き替えてください ##### */
$mail_from = 'aaa@bbbbb.net';
$mail_to = 'ccc@ddddd.com';
$mail_from_name = '送信者の名前';
$subject = 'HTML形式のテストメールです';
/* ###################################################################################### */

$mail_from =mb_encode_mimeheader($mail_from,"jis");
$mail_to =mb_encode_mimeheader($mail_to,"jis");
$mail_from_name =mb_encode_mimeheader($mail_from_name,"jis");
$subject =mb_encode_mimeheader($subject,"jis");

$tmp =mb_convert_encoding('<p style="color:red; font-weight:bold;">HTMLメールを送ります</p>','jis');

$body_html =$tmp;

$parameter = "-f ".$mail_from;
$boundary = '--' . uniqid(rand(),1);

// ヘッダー情報
$headers = '';
$headers .= 'MIME-Version: 1.0' . "\r\n";
$headers .= 'Content-Type: multipart/alternative; boundary="' . $boundary . '"' . "\r\n";
$headers .= 'Content-Transfer-Encoding: 7bit' . "\r\n";
$headers .= "From: " . $mail_from_name . "<" . $mail_from . ">" . "\r\n";
$headers .= "Subject: ". $subject . "\r\n";

// メッセージ部分
//今回はマルチパートにしておらず、HTML形式のパートだけにしています。勿論これでもOKです
$message = '';
$message .= '--' . $boundary . "\r\n";

$message .= 'Content-Type: text/html; charset="iso-2022-jp"' . "\r\n";
$message .= 'Content-Transfer-Encoding: 7bit' . "\r\n";
$message .= "\r\n";
$message .= $body_html . "\r\n";

$message .= '--' . $boundary . '--' . "\r\n";

// 送信する
if(!mail($mail_to,$subject, $message, $headers, $parameter)){?>
<script>
alert('送信ができませんでした');
</script>
<?php
}
else{
<script>
alert('送信が完了しました');
</script>
<?php
}
?>

“PHPでHTMLメールを送信する – MIMEを知れば怖くない!” への1件の返信

コメントを残す

メールアドレスが公開されることはありません。