polidog lab

Top About Rss
2014年09月12日

Swift MailerでISO-2022-JPなメールが送れなくなっていた件について

どうもこんばんはポリドッグ(♂)です。
僕は元気で毎日働いているよ!

さて、そんな事はどうでもいいんですが、今日はSwift Mailerのお話でもしたいと思います。 Symfony2でWebアプリケーションを実装していると結構使う事になるSwift Mailerだと思います。

最近だとUTF-8の文字コードでメールを送ってもそれほど問題ないとは思いますが、未だにメールはISO-2022-JPで送信しろよという空気だったり、サービス規模が大きくなる場合はあるていど気にしてあげるべき問題だと思います。

ISO-2022-JPのメールが送れない

Practical Symfony #15: Swift Mailerによる日本語メールの作成を参考に実装してみましたが、動かなかった・・・って事案が発生したわけですよ。
なぜか知らないけどエンコードをISO-2022-JPにして送信してもUTF-8で送信されるとうことが・・・。

調べて行くとどうやらMimePart.phpの202行目にこんな実装が

        if (!in_array($charset, array('utf-8', 'iso-8859-1', ''))) {
            // mb_convert_encoding must be the first one to check, since iconv cannot convert some words.
            if (function_exists('mb_convert_encoding')) {
                $string = mb_convert_encoding($string, 'utf-8', $charset);
            } elseif (function_exists('iconv')) {
                $string = iconv($charset, 'utf-8//TRANSLIT//IGNORE', $string);
            } else {
                throw new Swift_SwiftException('No suitable convert encoding function (use UTF-8 as your charset or install the mbstring or iconv extension).');
            }

            return $string;
        }

な、なるほど・・・UTF-8 or ISO-8859-1じゃない場合はUTF-8に変換される素敵な仕様・・・

ISO-2022-JPの対応が行われたコミットを確認してみる

一応どうやって最初にISO-2022-JPが実装されたのか調べました。
どうやら#199のPRでマージされていたようですね。

このときのPRのMimePart.phpの実装だとmb_convert_encodingが

{% codeblock lang:php MimePart.php %} $string = mb_convert_encoding($string, $charset, ‘utf-8’); {% endcodeblock %}

こんな感じになっていて、指定したエンコードに変換してくれたようです。 Blameでおったところ#475でISO-2022-JPの 対応をやめてしまったようですね(´・ω・`)

それでもISO-2022-JPを諦めたくない人

それでも諦められない人とか、プロジェクト的に対応しなきゃ上司に殺されるーって人もいるかと思います。
対応方法として僕がとった手段はSwift_Messageクラスを継承して拡張するというアプローチでした。

class Message extends \Swift_Message
{

    /**
     * Create a new Message.
     *
     * @param string $subject
     * @param string $body
     * @param string $contentType
     * @param string $charset
     *
     * @return Message
     */
    public static function newInstance($subject = null, $body = null, $contentType = null, $charset = null)
    {
        return new self($subject, $body, $contentType, $charset);
    }

    /**
     * 日本語メール用のsubject設定
     * @param string $subject
     * @return \Swift_Mime_SimpleMessage|void
     */
    public function setSubject($subject)
    {
        $subject = $this->_convertString($subject);
        parent::setSubject($subject);
        return $this;
    }


    /**
     * @param $string
     * @return string
     */
    protected function _convertString($string)
    {
        $charset = strtolower($this->getCharset());
        if (! in_array($charset, ['utf-8','iso-8859-1', ""])) {
            $string = mb_convert_encoding($string, $charset, 'utf-8');
        }
        return $string;
    }
}

ということで、これでなんとかISO-2022-JPな日本語メールが送信出来るようになります。
もし他にもっといい方法があるよとか、普通におくれたよーっはコメントかtwitterで教えてください。

おしまい。

comments powered by Disqus