Zend\Mailで日本語(ISO-2022-JP)メールを送る

ZendFramework2.0でメール送信を行いました。
公式ドキュメントに加えて、下記ブログは参考になります。私はこの通りにはしませんが、ひとつの方法として参考にしました。
http://www.michaelgallego.fr/blog/?p=208

日本語メールは?

テストした環境はmb_stringが使えて、
mbstring.internal_encoding = UTF-8
mbstring.language = Japanese
な環境です。
UTF-8でメールを送る場合、ほとんど問題は起きず、そのまま何もしなくても日本語のsubjectやアドレスの注釈が使えます。ほとんど、と書いたのは、その日本語の中に、たとえば、半角カッコを含んだ場合に、メールサーバーによってはヘッダを解釈してアドレス区切りと理解し、ドメイン名を追加されたりで壊れてしまうケースがあるためです。(どちらに問題があるかについてはよく調べていません!)

JISで送る

さて、スクリプトUTF-8で書いている場合、データのやり取りのほとんどをUTF-8で統一しているという前提とします。
内輪で使う場合は、ほとんどのメールソフトはUTF-8に対応しているので問題ないですが、不特定の顧客に対して送りつけるにはJISで送りたいケースもあると思います。
この場合、Zend Framework2.0では、
$message->setEncoding('ISO-2022-JP');
としてあげれば、ドキュメント上ではできそうですが、勝手に文字コード変換は行わない(行うべきではない)ので個別にデータをJISに文字コード変換してから与える必要があり、それで十分にも見えます。
ところが、よくある文字列でも、JIS変換するとUTF-8上で処理するとかなりの数のカッコ相当の文字が入り、Zend\Mimeでは文字コードを意識しないのでエンコードしてもカッコが残ってしまいます。(内部エンコーディングを変えれば問題が解消するかということについては、どのみち筋が悪いので試していません。)カッコが残ったままsmtpトランスポートに乗せると、UTF-8では稀だったトラブルがかなりの確率で発生することになります。
そこで、対処としては、アドレスを設定する際に、mb_encode_mimeheaderでエンコードしておくこと。(本文については、mb_convert_encodingでよいでしょう。)
$message->setFrom('from@example.com', mb_encode_mimeheader("日本語も(大丈夫)あいうえお", 'JIS', 'Q'));
次に、setEncodingを省略するとUTF-8エンコードしてしまいますので、
$message->setEncoding('ASCII');
として、Zend\Mimeによるエンコードをキャンセルします。
mb_encode_mimeheaderにはmb_encode_mimeheader固有の問題がありますし、UTF-8からJISへの変換では脱落する文字もあり、変換用のライブラリを持っているケースでは、それらを通すような中間クラスを用意することになると思いますが。

たとえばHTMLメールとか

$html = $this->render('mail/receipt', $data);
のように、viewスクリプトからHTMLを育成したとします。

$txtPart = new \Zend\Mime\Part('');
$txtPart->type = "text/plain";
$htPart = new \Zend\Mime\Part(mb_convert_encoding($html, 'JIS'));
$htPart->type = "text/html";
$htPart->charset = "ISO-2022-JP";
$htPart->encoding = "7bit";
$body = new \Zend\Mime\Message();
$body->setParts(array($txtPart, $htPart));

これで、
$message->setEncoding('ASCII');
としている場合でも、JISコードで、charset指定のあるメッセージbodyを作れます。
必要に応じて、language指定なども。