[Zend Framework] Zend_Mail: 日本語をふくむメールを送る(長いsubjectと添付ファイルにも対応)
「Zend_Mail – 日本語文字化けに関してわからなかった点をメモしておく | deadwood」のつづき。
いちおう解決編です。
ZendFrameworkのバージョンは、1.12.3です。
Contents
解決しなかった点
最終的に独習で解決できなかった点です。
ご存じの方、ぜひ教えて下さい。
- 仕様に沿ったメールが作成できているかテストする方法
- メールまわりの仕様に関するまとまった情報
- setHeaderEncoding(Zend_Mime::ENCODING_BASE64)をすべきなのか
追記(2013/05/24)
電子メールあれこれ | 「インターネット・プロトコル詳説」最新記事一覧 – ITmedia Keywords | telnetでMIMEヘッダをきちんとつけて日本語メールを送信する | メールの基礎知識 | Takahiro Takano – M2 と RFC2231 と他 | エンコードマニアックス – 各種エンコードやハッシュを一発作成 | 直接関係ないけれどもメモ Message header analyzer
ソース
このように文字化けしない表示を実現できました。
ソースはこのような形。
コメントアウトしている setHeaderEncoding については後述します。
public function sendmailAction() { function mbCnv($string) { return mb_convert_encoding($string, 'ISO-2022-JP', 'UTF-8'); } function mbMime($string) { return mb_encode_mimeheader(mbCnv($string), 'ISO-2022-JP', 'B'); } $txt = '長い日本語のテキスト。文字化けるか確認します。元のアドレスのコピー。松本人志。さらに特定の文字が文字化けるか確認します。長い日本語のテキスト。文字化けるか確認します。元のアドレスのコピー。松本人志。さらに特定の文字が文字化けるか確認します。'; $short = '松本人志'; $mail = new Zend_Mail('ISO-2022-JP'); // $mail->setHeaderEncoding(Zend_Mime::ENCODING_BASE64); $mail->setSubject(mbCnv($txt)); $mail->addTo('to@test.com', mbMime($short)); $mail->addCc('copy@test.com', mbMime($txt)); $mail->setFrom('from@test.com', mbMime($short)); $mail->setBodyText(mbCnv($txt), null, Zend_Mime::ENCODING_7BIT); $mail->setBodyHtml(mbCnv($txt), null, Zend_Mime::ENCODING_7BIT); $atImage = file_get_contents('http://www.foo.com/logo.png'); $at = new Zend_Mime_Part($atImage); $at->type = 'image/png'; $at->mimeType = Zend_Mime::TYPE_OCTETSTREAM; $at->disposition = Zend_Mime::DISPOSITION_INLINE; $at->encoding = Zend_Mime::ENCODING_BASE64; $at->filename = mbMime('日本語.png'); $mail->addAttachment($at); $config = array('port' => 1025); $smtp = new Zend_Mail_Transport_Smtp('127.0.0.1', $config); try { $mail->send($smtp); echo '送信しました'; } catch (Zend_Exception $e) { echo "エラー: " . $e->getMessage(); } }
前回分からなかった点のうち、subject以外から確認します。
- 日本語の長い件名が途中から文字化けする
- To, From などに付けられるラベル?に日本語を使うと文字化ける
- 添付ファイル名に日本語が含まれると文字化ける
ISO-2022-JPにコンバート、ヘッダーはさらにbase64にエンコードする
結論的には、メールは「ISO-2022-JPにコンバート、ヘッダーはさらにbase64にエンコードする」ということでした。
「Zend_Mail(‘ISO-2022-JP’)」するだけでうまい事やってくれると期待しちゃうところですが、ひとつひとつ明示的に指定しなければいけないようです。
function mbCnv($string) { return mb_convert_encoding($string, 'ISO-2022-JP', 'UTF-8'); } function mbMime($string) { return mb_encode_mimeheader(mbCnv($string), 'ISO-2022-JP', 'B'); }
テキストが入る所は、mb_convert_encoding で「ISO-2022-JP」にコンバートしています。
さらにヘッダー部に関しては、mb_encode_mimeheader で「B(base64)」にエンコードしています。
mb_encode_mimeheader の「ISO-2022-JP」は、このcharsetで入ってくるよ、という指定。
これがなかったりでごちゃごちゃになっていたのが原因でした。
日本語の長い件名(subject)が途中から文字化けする
公式で「ヘッダ、特に subject のエンコーディングは、油断のならない話題です。」などと言われていましたが、最終的にここが問題でした。
「文字セット – Zend_Mail – Zend Framework」のサンプルソースが中途半端?なのも混乱に拍車をかけていました。
対処療法ですが、「setHeaderEncoding(Zend_Mime::ENCODING_BASE64)」がなければ、件名の文字化けが起きないことが分かりました。
これがない場合、「quotedprintable 方式でエンコード」として振る舞うとされています。
仕様としてなくてもかまわないのか、そもそもどの方式でエンコードされているのか確認できませんでした。
もうひとつの対処法は、Zend_Mailを継承したクラスを作成する方法です。
「setHeaderEncoding(Zend_Mime::ENCODING_BASE64)」あっても文字化けしません。
ちなみに原因について
長いSubjectが文字化けするのは Zend_Mime::encodeBase64Header の第3引数の Zend_Mime::LINELENGTH(72) と第4引数のZend_Mime::LINEEND(\n)に問題があります。ヘッダを Base64 にエンコードする際に 72文字ごとに「\n」が入ってしまうことが原因でした。なので LINELENGTH の数を増やしてやるか、LINEEND を空文字を指定してやれば解決します。
という事のようです。
ただ、いまの「function _encodeHeader」を見る限りは、「Zend_Mime::LINELENGTH(72)」という記述はなさそうです。
Zend_MailのSVNリポジトリ http://framework.zend.com/svn/framework/standard/trunk/library/Zend/Mail.php
なので、現在は「setHeaderEncoding(Zend_Mime::ENCODING_BASE64)」はいらないのではないかと推測しています。
これなしでもbase64でエンコーディングされていることが分かれば、ひとまずよさそうなんですがね。
わかりません。