PHPで文字化けしない日本語メールを送信する設定
これまでなんとなくの理解で使ってきたPHPで日本語のメールを送る方法についてまとめてみます。設定を正しく理解して日本語のメールが文字化けせずに送信できるようにします。
日本語のメールを送信するサンプルコード
$to = 'to@example.com'; $from = 'from@example.com'; $subject = "日本語の件名"; $body = "日本語の本文です"; $header = "From:".$from; mb_send_mail($to,$subject,$body,$header);
このシンプルなコードで文字化けしないメールを送る事が出来ます。しかし、このコードを見て次のような疑問が生じると思います。
- 文字コードの指定が全く無い
- どの文字コードでメールが作成されるのか?
サンプルコードで文字化けしない設定
実はこのサンプルコードで文字化けする可能性があります。サンプルコードを文字化けさせないためにはphp.iniを以下のように設定します。
mbstring.language = japanese mbstring.internal_encoding = UTF-8
PHPのマルチバイトに関する設定が重要
つまり、PHPで文字化けしない日本語のメールを送るためには、PHPのマルチバイトに関する設定を理解する事が重要です。という事が言いたい事です。
日本語メールに関わる最低限必要な設定は「mbstring.language」と「mbstring.internal_encoding」の2つの設定ディレクティブです。この2つの設定が適切に設定されていないと文字化けが起こります。
設定方法
設定は以下のいずれかの方法で設定する事がでます。
- 事前にphp.iniや.htaccessで設定する
- スクリプト内で関数を使って設定する
mbstring.languageの設定
mb_send_mailが送信するメールのエンコード方法。以下のいずれかを設定できます。日本語のメールを送信する場合は、'Japanese'または'uni'を指定します。
設定値 | エンコード方法 |
---|---|
'Japanese'または'ja' | ISO-2022-JP/Base64 |
'uni' | UTF-8/Base64 |
'English'または'en' | ISO-8859-1/quoted printable |
php.iniで設定
mbstring.language = japanese
スクリプトで設定する場合はmb_language関数を使います。
mb_language("japanese");
mbstring.internal_encodingの設定
mb_send_mail関数を含むマルチバイト関数が文字コードを変換する際にエンコード元として利用される文字コード。この文字コードが正しく設定されていないと文字化けが発生します。(mb_encode_mimeheaderでもこの設定使用されます。)通常ソースファイルの文字コードに合わせて設定します。'UTF-8'で書いたソースコードなら'UTF-8'に、'EUC-JP'で書いたのソースコードなら'EUC-JP'にします。
php.iniで設定
mbstring.internal_encoding = 'UTF-8'
スクリプトで設定する場合はmb_internal_encoding関数を使います。
mb_internal_encoding("UTF-8");
差出人名を日本語にしたい
mb_send_mail関数は、件名以外のヘッダ情報はエンコードしないので、mb_encode_mimeheader関数を使ってエンコードします。
mb_encode_mimeheader関数でエンコード方法を省略した場合はmbstring.languageで設定した文字コードが使用されます。変換元文字コードは引数として指定する事が出来ず、変換元文字コードとしてinternal_encodingの設定値が使われます。
//internal_encodingからmbstring.languageで設定した文字コードへ変換します $from = mb_encode_mimeheader('差出人').' <from@example.com>';
設定ファイル vs スクリプトで設定
マルチバイトの設定は、設定ファイルではなくスクリプト内で設定する事も出来ます。スクリプトが少し増えますが設定ファイルに依らないため再利用性が高く、また分かりやすくなります。いずれの場合もmbstring.languageとmbstring.internal_encodingについて正しく理解していれば、失敗が起こりにくくなります。
php.iniを適切に設定した場合の例
$to = 'to@example.com'; $from = mb_encode_mimeheader('差出人').' <from@example.com>'; $subject = "日本語の件名"; $body = "日本語の本文です"; $header = "From:".$from; mb_send_mail($to,$subject,$body,$header );
設定をスクリプトで上書きした場合の例
mb_language('Japanese'); //'ISO-2022-jp/Base64'のメールを作成 mb_internal_encoding('UTF-8'); //変換元の文字コードを指定 $to = 'to@example.com'; $from = mb_encode_mimeheader('差出人').' <from@example.com>'; //,mb_language('Japanese')で設定済みなので'ISO-2022-jp'の指定は不要 $subject = "日本語の件名"; $body = "日本語の本文です"; $header = "From:".$from; mb_send_mail($to,$subject,$body,$header );
まとめ
PHPのマルチバイトに関する設定が重要という事を覚えてもらうと良いと思います。ある人のコードでは問題なかったのに自分の環境でテストすると文字化けする、といった時にはそのサーバーでのphp.iniのマルチバイトに関する設定を確認してみて下さい。mb_send_mail関数は使わないでmail関数使うからいいよ、という人もmb_encode_mimeheader関数を使う事があるならマルチバイトに関する設定が関係するはずです。
おまけ:日本語メールに関連するマルチバイト関数の解説
mb_send_mail
- エンコード方法を指定する事ができない
- 変換元の文字コードを指定する事もできない
エンコード方法としてmbstring.languageを、変換元の文字コードとしてmbstring.internal_encodingが使用されます。
- エンコードを行なうのは件名と本文だけ
- 差出人など件名以外のヘッダ情報は自分でエンコードする必要あり
- 長い本文の自動的な改行処理はしない
mb_encode_mimeheader
- エンコード方法を指定する事ができる
- 変換元の文字コードは指定する事はできない
変換元の文字コードとしてmbstring.internal_encodingが使用されます。
mb_convert_encoding
- 変換後の文字コードを指定する必要がある
- 変換元の文字コードを指定する事も出来る(省略可)
変換元の文字コードを省略した場合はmbstring.internal_encodingが使用されます。
蛇足:マルチバイト変換の挙動の不思議
とあるWebサイトに以下のようなコードがあった。
mb_language("japanese"); mb_internal_encoding("EUC-JP"); $from = mb_encode_mimeheader(mb_convert_encoding("差出人名","JIS","EUC-JP"))."<from@example.com>";
これまでの説明で理解してきた理屈でいうと、このコードのmb_encode_mimeheaderの部分でinternal_encodingである"EUC-JP"から"ISO-2022-JP"への変換が行われるので、mb_convert_encodingは必要ない。しかしmb_convert_encodingで'JIS'に変換した文字列を渡している。つまりこのコードでは、'JIS'で渡された文字列を'EUC-JP'と解釈したものを"ISO-2022-JP"へ変換してしまうからきっと文字化けする、と考えれます。
ところが文字化けしない。
mb_convert_encodingの挙動を検証してみると、JIS文字列からJISへの文字コード変換する場合に限り、変換元の文字コードの指定が間違っていても無視され、文字列は正常に保たれようです。
$start= "日本語の文字列です。";//'UTF-8'の文字コード $subject = mb_convert_encoding($start,'EUC-JP','UTF-8'); $subject = mb_convert_encoding($subject ,'EUC-JP','JIS');//変換元の指定が間違い(ここでsubjectが壊れる) $result = mb_convert_encoding($subject ,'UTF-8','EUC-JP'); //当然falseになる var_dump($result ===$start); $subject = mb_convert_encoding($start ,'JIS','UTF-8'); $subject = mb_convert_encoding($subject ,'JIS','UTF-8');//変換元の指定が間違い $subject = mb_convert_encoding($subject ,'JIS','EUC-JP');//変換元の指定が間違い $subject = mb_convert_encoding($subject ,'JIS','ISO-8859-1');//変換元の指定が間違い $result = mb_convert_encoding($subject ,'UTF-8','JIS'); //これはなんとtrueになる var_dump($result ===$start); echo $result;
検索
最近の投稿
作ったもの
写真共有のTWINGAR
CakePHPのまとめノートCakePHP Note
CakePHPのAPIFramework API
About Me
@ZiSTA Tweets
CakePHPとかMacとか

コメント