[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でエンコーディングされていることが分かれば、ひとまずよさそうなんですがね。
わかりません。
