PHP5.6から、メール本文に「はしご高」や「たつ崎」などを含む
メールを送信したいと考えています。
Gmailなどからメールを送信し、ヘッダーを確認すると以下のようになっており、
UTF-8の「はしご高」や「たつ崎」を含むメールを、マルチパートメールで
送信できそうと考えました。
Content-Type: multipart/alternative; boundary=XXXX --XXXX Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: base64 メール本文
以下のサイトを参考にしながら、テストプログラムを作成してみましたが、
メール本文のみ、文字化けしてしまいます。
サーバーと、プログラム本体の文字コードは、UTF-8です。
(参考)phpメール送信例/メモ
http://qiita.com/KanaeYou/items/b096f8be1f5bbc5448fa
(参考)PHPで添付ファイル付きメールを送信
http://refirio.org/view/202
(参考)ソフトバンク メール開発ガイド(PDF)
http://creation.mb.softbank.jp/mc/tech/doc/A-089-011-Mail_ContentDevelopmentGuide_1.2.1.pdf
MIMEヘッダーや、エンコードの方式、Content-Typeや、Content-Transfer-Encodingを、
あちこちいじって、ぐちゃぐちゃ変えながら試しています。
PCメールソフト宛のみうまくいく組み合わせもあったのですが、
ソフトバンク宛に送信すると、常に文字化けです。
どこをどのように修正すべきでしょうか?
ご指導いただけたら、幸いです。
※ 参考にしたサイトが添付を送るためのコードだったので、
添付パートの部分がついていますが、実際には使用しないので、
コメントアウトになっています。
PHP
1<?php 2//mb_language() を使ってエンコー ディング方式を ISO-2022-JP/Base64 に設定。 3//この設定は、mb_encode_mimeheader() 関数で使用されます。 4mb_language("Japanese"); 5 6//内部文字コード指定 7mb_internal_encoding("UTF-8"); 8 9// SETUP 10$to[] = 'XXX@XXX.XX.XX'; 11$from_email= 'XXX@XXX.XX.XX'; 12$from_name = 'XXXXXXXX'; 13$subject = 'テストプログラムから送信'; 14 15$body = "これはテストです コレハテストデス 神と神 ①②③ 髙﨑黑神福 ㈱ ⅠⅡⅢ"; 16 17$attach_file = ""; 18 19// send the email 20foreach( $to as $to_email ) { 21 sendmail_jpn($to_email, $subject, $body, $from_email,$from_name, $attach_file); 22 sleep(1); 23} 24 25echo "送信完了"; 26 27 28 29//関数----------------------------------- 30 31function sendmail_jpn ($to, $subject, $message, $from_email,$from_name, $filepath) 32{ 33 $mime_type = "application/octet-stream"; 34 35 // 添付ファイルのエンコード 36 //$filename = basename( $filepath ); 37 38 // マルチパートのパートの区切り文字列を指定 39 $boundary = '----=_Boundary_' . uniqid(rand(1000,9999) . '_') . '_'; 40 41 // 件名のエンコード 42 $subject = mb_convert_encoding($subject, "ISO-2022-JP", "UTF-8"); //UTF-8 → ISO-2022-JP 43 $subject = mb_encode_mimeheader_ex($subject); 44 45 // 差出人のエンコード 46 $from_name = mb_convert_encoding($from_name, "ISO-2022-JP", "UTF-8"); //UTF-8 → ISO-2022-JP 47 $from_name = mb_encode_mimeheader_ex($from_name); 48 49 // toをエンコード 50 $to = "=?ISO-2022-JP?B?" . base64_encode($to) . '?= <' . $to . '>'; 51 52 // fromをエンコード 53 $from = "=?ISO-2022-JP?B?" . base64_encode($from_name) . '?= <' . $from_email . '>'; 54 55 // 本文(planeパート)のエンコード 56 $message = mb_convert_encoding($message, 'JIS', 'UTF-8'); 57 $message = "=?ISO-2022-JP?B?" . base64_encode($message) . "?="; 58 59 //本文(htmlパート) 60 $message_html = ""; 61 62 // 添付ファイルのエンコード 63 //$filename = "=?ISO-2022-JP?B?" . base64_encode($filename) . "?="; 64 65 66 // ヘッダーの指定 67 $head = ""; 68 $head .= "From: {$from}\n"; 69 $head .= "MIME-Version: 1.0\n"; 70 //$head .= "Content-Type: text/plain;" . "\n"; 71 //$head .= "Content-Type: multipart/mixed; boundary=\"{$boundary}\"\n"; 72 $head .= "Content-Type: multipart/alternative; boundary=\"{$boundary}\" Content-Transfer-Encoding: base64"; 73 74 $body = ""; 75 76// text/plainパート 77$body .= "--{$boundary}\n"; 78 79 // 本文 80 $body .= "Content-Type: text/plain; charset=\"ISO-2022-JP\"; Content-Transfer-Encoding: \"base64\"\n"; 81 82 $body .= "\n"; 83 $body .= "{$message}\n"; 84 $body .= "\n"; 85 86// text/htmlパート 87/* 88$body .= "--{$boundary}\n"; 89 90 // 本文 91 $body .= "Content-Type: text/html; charset=\"UTF-8\"" . "\n"; 92 $body .= "Content-Transfer-Encoding: \"base64\"" . "\n"; 93 $body .= "\n"; 94 $body .= "{$message_html}\n"; 95 $body .= "\n"; 96*/ 97 98// 添付ファイルパート 99/* 100 //$body .= "--{$boundary}\n"; 101 //$body .= "Content-Type: {$mime_type}; name=\"{$filename}\"\n" . 102 //"Content-Transfer-Encoding: base64\n" . 103 //"Content-Disposition: attachment; filename=\"{$filename}\"\n"; 104 //$body .= "\n"; 105 // 106 //$fp = fopen( $filepath, "r" ) or die("Error on mailing. (attachment file cannot open)"); 107 //$contents = fread( $fp, filesize($filepath) ); 108 //fclose( $fp ); 109 //$f_encoded = chunk_split(base64_encode($contents)); //添付ファイルをbase64エンコードする 110 //$body .= "{$f_encoded}\n"; 111 //$body .= "\n"; 112*/ 113 114//マルチパート終了 115$body .= "--{$boundary}--\n"; 116 117 // メール送信 118 if (mail($to, $subject, $body, $head)) { 119 echo 'sendmail_jpn : OK.'; 120 } else { 121 echo 'sendmail_jpn : FAILURE.'; 122 } 123 124} 125 126// mb_encode_mimeheader のバグ対策用 127function mb_encode_mimeheader_ex ($text, $split_count = 34) { 128 $position = 0; 129 $encorded = ''; 130 131 while ($position < mb_strlen($text, 'ISO-2022-JP')) { 132 if ($encorded != '') { 133 $encorded .= "\n "; 134 } 135 136 $output_temp = mb_strimwidth($text, $position, $split_count, '', 'ISO-2022-JP'); 137 $position = $position + mb_strlen($output_temp, 'ISO-2022-JP'); 138 $encorded .= "=?ISO-2022-JP?B?" . base64_encode($output_temp) . "?="; 139 } 140 return $encorded; 141} 142
文字化け時のスマホのスクショを追加します。
追記
皆さん、たくさんご回答いただき、ありがとうございます。
こちらでまとめてお返事させていただく失礼をお許しください。
参考にしたサイトが「添付を付ける例」だったので、
ちょっと小難しく考えすぎたのかと思いまして、
プログラムをシンプルなものにして、再検証してみました。
PHP
1 2<?php 3mb_language("Japanese"); 4mb_internal_encoding("UTF-8"); 5$to = 'XXX@XXXX.XXX'; 6$subject = 'これはテストプログラムから送信したメール!'; 7$message = 'これはテストです コレハテストデス 神と神 ①②③ 髙﨑黑神福 ㈱ Ⅰ Ⅱ Ⅲ'; 8$message = mb_convert_encoding($message, 'ISO-2022-JP-MS'); 9$headers = 'From: XXXX@XXXX.XXX' . "\r\n"; 10 11mb_send_mail ($to, $subject, $message, $headers);
mailではなく、mb_send_mail にしました。
ちなみに、mb_get_info()の結果は以下の通りです。
------------------------------------------------------------------------ mb_get_info()の出力結果(カゴヤ・ジャパン レンタルサーバー) ------------------------------------------------------------------------ Array ( [internal_encoding] => UTF-8 [http_input] => UTF-8 [http_output] => UTF-8 [http_output_conv_mimetypes] => ^(text/|application/xhtml\+xml) [func_overload] => 0 [func_overload_list] => no overload [mail_charset] => ISO-2022-JP [mail_header_encoding] => BASE64 [mail_body_encoding] => 7bit [illegal_chars] => 0 [encoding_translation] => On [language] => Japanese [detect_order] => Array ( [0] => ASCII [1] => JIS [2] => UTF-8 [3] => EUC-JP [4] => SJIS ) [substitute_character] => 63 [strict_detection] => Off )
エンコードせずにmb_send_mailした場合
全環境で、外字が?に化けました。
ISO-2022-JP-MS にエンコードしてmb_send_mailした場合
iPhone OK
Windows LiveMail OK
AL-Mail OK
Gmail OK
Android(HUAWEI P8lite) NG
となりました。惜しい。
以下のページで紹介されていますが、
PHPで外字を含む文字列のエンコードコンバート
PHP V5.2.1以降では『iso-2022-jp-ms』というエンコーディングが追加され、
このエンコーディングでサポートされている文字も変換する事が可能になりました。
$str = mb_convert_encoding( $str, 'ISO-2022-JP-MS');
これにより、$strに(サポートされている)外字が含まれていても、正常にコンバートすることが出来ます。
但し、文字エンコードを正しくコンバート出来る事と、端末で外字を表示出来る事はイコールではありません。いくら正常にコンバートしても、表示先の端末にその外字がサポートされていなければ表示されません。
HUAWEI P8lite は、iso-2022-jp-ms を表示できないのかも知れません。
以下の添付を参照していただきたいのですが、ISO-2022-JP-MS でコンバートして送っているけど、
ヘッダーのcharsetには、ISO-2022-JP と書かれています。
試しに、GmailからHUAWEI P8liteに送ってみると…
問題なく表示されました。(さすが…)
追記2
HUAWEI P8lite のみ、ヘッダー情報がメール本文内になだれ込んでいる件、
原因は、この行でした。
HUAWEI P8liteに届いたメールだけ、何故かメールの送信時間が
「1970年1月1日」になっていたので、ヘッダーが壊れてるなと…。
PHP
1$headers = 'From: XXXX@XXXX.XXX' . "\r\n"; //修正前 2$headers = 'From: XXXX@XXXX.XXX' . "\n"; //修正後
これでとりあえず、手持ちの端末では全てOKになりました!(ありがとうございます!)
自宅に戻らないと確認できませんが、Mac、古いガラケーなども確認したいと思います。
PHPからISO-2022-JP-MS でメールを送信されている方へ追加でお尋ね
ガラケーなど「ISO-2022-JP-MS」がサポートされていない端末も当然あるのではと
気になっています。
サーバ証明書が切り替わりますので、
「SHA-2」方式および「TLS1.0以上」に対応していない携帯端末
(2008年位より前に発売されたガラケー)は、サポート外にしようと思っていますが、
対応している機種で「ISO-2022-JP-MS」がサポートされていない機種って、
あるものなのでしょうか?(どうやって調べるんですか…こういうの…)
情報をお持ちでしたら、御知らせいただければ幸いです。
UTF-8の文字で、ISO-2022-JP-MSに含まれていない文字への対策
UTF-8の文字で、ISO-2022-JP-MSに含まれていない文字が入っていた場合にやはり化けるので、
以下の一行を追加しました。
PHP
1mb_substitute_character('entity');
追記3
imutakaoruさんからいただいたコードを、実行させてみました。
無事、UTF-8のままで送れました!!
(imutakaoruさん、ありがとうございます!)
受信したメールのヘッダーを確認したところ、
となっており、Gmailに近づいた気がします。(自分の理想に近い)
MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: BASE64
UTF-8をフルカバーできるか?
ISO-2022-JP-MS に変換しないので、ISO-2022-JP-MS に含まれていない文字が本文に入っていたら
どうなるかと思い、以下のサイトで紹介されていた二字を足してみました。
マルチバイト文字を扱う際に気をつけること
(U+29E3Dの「=ホッケ」と U+50AA「=さん」)
この2字がUTF-8かどうか、よく分かりませんが、
一応、UTF-8のファイルではちゃんと書けています。
$message = 'これはテストです コレハテストデス 神と神 ①②③ 髙﨑黑神福 ㈱ Ⅰ Ⅱ Ⅲ ???? 傪';
これを、imutakaoruさんからいただいたコードで送信した結果は、以下の通りでした。
iPhone OK
HUAWEI P8lite 「????」が文字化け
AL-Mail ???? 傪 とも文字化け
HUAWEI P8liteは フォントが省略されているのではないかと思います。
「Al-Mail」で受信したメールを外部エディタで確認してみると、
本文はちゃんとBASE64でエンコードされていました。
別のサイトで同じ文字列をBASE64エンコードして比較したところ、
合致しましたので、エンコードの問題ではなさそうです。
Gmailからも同じ文字列を、Al-Mail宛に送ってみましたが、
やっはり同じように、最後の2字が化けました。
Al-Mailの問題か、フォントの問題かなと思います。
Al-Mailは古すぎるので、もうサポート外で良いのですが、
HUAWEI P8liteは、表示して欲しかったなぁ…。
先ほど引用させていただいた、この一言に尽きるわけですね…。
文字エンコードを正しくコンバート出来る事と、
端末で外字を表示出来る事はイコールではありません。
UTF-8の全ての文字をサポートしようと思うと、
難しそうなので、(端末側のフォント事情になると、もうどうしようもない。)
サポート文字範囲は、「ISO-2022-JP-MS」に含まれている文字まで、
それ以外はエンティティするか、ゲタ文字に置き換える、という仕様の方が安心できそうです。
回答6件
あなたの回答
tips
プレビュー