HTMLメールで一部だけ表示がくずれるときはここが怪しい

最近のメールマガジンとか、すっかりHTMLメールが当たり前になりましたよね。

以前の記事「WindowsのPHPでsendmailを使えるようにする」で書いたとおり、内部エンコーディングも出力もUTF-8で統一されているのが当たり前になってきたので、PHPによるメール送信も気楽なものになりました。

PHPでHTMLメールを送信する例

<?php
//HTML本文を書く
$html = '<table>';
for ($i = 0; $i < 50; $i++) {
	$html .= "<tr><td>$i:テストテストテストテストテストテストテストテスト</td></td></tr>";
}
$html .= '</table>';

//送信処理
$to = "hoge@example.com";
$header = "Content-Type:text/html;charset=UTF-8\r\n";
$header .= "From:hoge@example.com\r\n";

$ret = mail($to, "テストっす", $html, $header);
?>

きちんとしたメールマガジンだと、Content-Type:multipart/alternativeにしてテキストメールとHTMLメールの両方を同梱して送ってきていて感心しますが、もうそろそろHTMLメールだけでも良いんじゃないかなぁなんてちょっと思ってしまいます。

まぁ今回の本題はそこじゃないので割愛させていただくとして、上記のPHPスクリプトでHTMLメールを送信すると、こんなふうに文字化けするケースがあります。

1行1000バイトでの文字化け

全体的に文字化けしているならエンコードのミスかな、とも思いますが、ほんの一部だけ、しかも一定間隔で文字化けするのが特徴です。

よーく見るとわかりますが、PHPでは出力していない”!”(エクスクラメーションマーク)が挿入されているのです。

これはテストなので、いい感じの場所で文字化けするように調整しましたが、タグの中に”!”が入ると文字化けとはならず、表示がちょっと崩れてるなぁおかしいなぁ、とハマる原因になります。

このケース、原因は単純なのに知らないといつまでも解決できないという厄介さんなんですよね。

RFC2821でメールは1行1000バイトまでと規定されている

■RFC2821原文
ftp://ftp.rfc-editor.org/in-notes/rfc2821.txt

The maximum total length of a text line including the <CRLF> is 1000 characters
(意訳:1行の最大長はCRLFを含んで1000文字までやぞ!)

補足説明によるとSMTPサービスの拡張によって増やしても構わない、ともあるのですが、これはそのとおりで、1行1000バイト以上でも問題なく送れるメールサーバーもあります。

でもダメなところもありますし、以前紹介したfake sendmailなんかだと1行1000バイトを超えたところで自動的に”!”マークと改行が挿入されます。
(正確に言うと、半角英数で検証したら992文字目に自動挿入されました)

普通のテキストメールなら1000文字以上改行しないなんて迷惑なことはしないでしょうし、この仕様で問題なかったんだと思いますが、HTMLだとそうとは限りませんよね。

むしろCSSのダイエットのために空白と改行を出来るだけ削るとか、よくやるじゃないですか。

また、出力はずら~っと1行になっていてもPHPだとこんなふうに構造化されているからあまり気にしなかったりするんですよね。

$html = '<table>';
for ($i = 0; $i < 50; $i++) {
	$html .= "<tr><td>$i:テストテストテストテストテストテストテストテスト</td></td></tr>";
}
$html .= '</table>';

解決策としては適度に改行を入れるしかない

ここでメールヘッダーをこう書き換えるだけで治るっ!とかだと格好良かったんですが、あれこれ手をつくしてもどうにもこうにもメールサーバーが1行1000バイトでぶった切っちゃう現象は回避できませんでした。

なので、結局、いい感じのところで “\r\n” を入れてあげることに。

$html = '<table>';
for ($i = 0; $i < 50; $i++) {
	$html .= "<tr><td>$i:テストテストテストテストテストテストテストテスト</td></td></tr>\r\n";
}
$html .= '</table>';

■そして綺麗になった
HTMLでも改行が必要

まとめ

  • PHPでHTMLメールを送信して一部だけ表示がくずれたら1行の文字数を疑おう!

実際のトラブルは例に出したような簡単なHTMLではなくて、こう、デザイナーさんが納品してきたjQueryゴリゴリ使ったゴツいHTMLだったり、それを読み込んで加工して、あーだこーだしてHTMLメールで送信する~とかよくやると思いますけど、そうなるとなかなか適度な改行って悩ましかったりします。

場合によっては

$html = str_replace("</tr>", "</tr>\r\n", $html);

みたいな力技もアリかも知れませんね…。

『HTMLメールで一部だけ表示がくずれるときはここが怪しい』へのコメント

  1. 名前:apptaro 投稿日:2020/08/21(金) 16:00:35 ID:b0a85a3a7 返信

    あるメール配信サービスでは下記で回避していました。参考までに。
    Content-Type: text/html; charset=”UTF-8″
    Content-Disposition: inline
    Content-Transfer-Encoding: quoted-printable

    • 名前:とっちら 投稿日:2020/08/21(金) 16:19:40 ID:21bad467d 返信

      情報提供ありがとうございます!
      さっそく試してみましたが、fake sendmailではやはり1000行ごとに文字化けしてしまいました。まぁコレが例外なだけで、ほとんどの今どきのSMTPサーバーなら問題ないのだろうと思います。