技術

Laravel4: 普通のテキストメールを送りたい

Laravelのバージョンは4.1.24です。

ここで言う”普通のテキストメール”というのは

  • 件名と本文がISO-2022-JPな日本語
  • Content-Transfer-Encoding が 7bit
  • Content-Type が text/plain
  • マルチパートじゃない

という事を表します。

こんなご時世なので正直小細工なしでUTF8で送りたいんですけどね。
(今回の話はある組織内部で使うとある申請フォームに関連するものなのですが、まだガラケー使いも多い組織ですのでちゃんと対応しとこうと思った次第です)

で、Laravel4でISO-2022-JPな日本語メールを送信する方法を調べると、start/global.php等に

\Swift::init(function()
{
    \Swift_DependencyContainer::getInstance()
        ->register('mime.qpheaderencoder')
        ->asAliasOf('mime.base64headerencoder');

    \Swift_Preferences::getInstance()->setCharset('iso-2022-jp');
});

と記述しておいて、controller等で

Mail::plain('emails.welcome', $data, function($message)
{
    $message->from('us@example.com', 'Laravel');
        ->to('foo@example.com')->cc('bar@example.com')
        ->subject('あいうえお')
        ->setCharset('iso-2022-jp')
        ->setEncoder(new \Swift_Mime_ContentEncoder_PlainContentEncoder('7bit'));
});

のようにして送信すると良いよという情報が見つかりました。

でまぁこうやると確かにISO-2022-JPでメールが送信出来てるようでしたが、届いたメールのソースを見てみると Content-Type が multipart/alternative になっていてその中の唯一のパートとして Content-Type: text/plain な本文がはいっていました。
text/plain なパートひとつしか含まれてないのになぜ multipart/alternative なってしまうのか理解に苦しみました。
しかも Content-Transfer-Encoding が 7bit ではなく quoted-printable になってしまっていました。

正直この状態でも実害は無いのかもしれないんですが、気持ち悪いのでライブラリ側のソースを見てみたら原因がすぐに分かりました。

vendor/laravel/framework/src/Illuminate/Mail/Mailer.php の Mailer クラスの addContent メンバ関数が以下のような実装になってました。

	/**
	 * Add the content to a given message.
	 *
	 * @param  \Illuminate\Mail\Message  $message
	 * @param  string  $view
	 * @param  string  $plain
	 * @param  array   $data
	 * @return void
	 */
 	protected function addContent($message, $view, $plain, $data)
 	{
		if (isset($view))
 		{
			$message->setBody($this->getView($view, $data), 'text/html');
 		}
 
		if (isset($plain))
 		{
			$message->addPart($this->getView($plain, $data), 'text/plain');
 		}
 	}

$view には HTMLメールの本文用のビュー(テンプレート)名が入っていて、 $plain にはテキストメールの本文用のビュー名が入ってきます。
あきらかに、HTMLメールが基本になっていて、プレインテキストはそれに付随する情報という扱いになっています。
なので $view が空で $plain だけが指定されてる場合、本文は無いけどもプレインテキストのパートが含まれたマルチパートなメールが出来上がってしまいます。

これを修正するためにライブラリ側に手をつけない方法をあれこれ考えたんですが、あまりいい案が思い浮かばなかったので addContent を変更することにしました。

	/**
	 * Add the content to a given message.
	 *
	 * @param  \Illuminate\Mail\Message  $message
	 * @param  string  $view
	 * @param  string  $plain
	 * @param  array   $data
	 * @return void
	 */
	protected function addContent($message, $view, $plain, $data)
	{
		if (isset($plain))
		{
			$message->setBody($this->getView($plain, $data), 'text/plain');
		}

		if (isset($view))
		{
			$message->addPart($this->getView($view, $data), 'text/html');
		}
	}

安易ですが、こんな風に書き換えることで当初の目的は達成できました。
($view が空でない場合のテストをしてないので何か問題あるかもです)

ただ、これで送ってみると本文が変なところで改行されるようになってしまったので、自動で改行を含めいないようにするため、送信時のコードを以下のようにしました。

Mail::plain('emails.welcome', $data, function($message)
{
    $message->from('us@example.com', 'Laravel');
        ->to('foo@example.com')->cc('bar@example.com')
        ->subject('あいうえお')
        ->setCharset('iso-2022-jp')
        ->setEncoder(new \Swift_Mime_ContentEncoder_PlainContentEncoder('7bit'))
        ->setMaxLineLength(0);
});

setMaxLineLength(0)で自動で改行を含めないように出来るらしいです。
RFCとかで行の最大長とかが決まってるらしいので、ほんとうに全く改行せずに送信するのはアレですが、埋め込む項目の最大長なども考慮しつつテンプレート側できちんと成形してあれば問題ないかと思います。

参考
Laravel – The PHP Framework For Web Artisans.
Laravel4、メールの送信
Swift Mailer のテキストメールで改行させない | Javable.Jp

コメント

気になってたもモヤモヤが晴れました。
ありがとうございます。

しかし、変な仕様ですねw

コメントを残す

メールアドレスが公開されることはありません。



※画像をクリックして別の画像を表示

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください