PHPで文字化けしないHTMLメールを送信するために必要な知識とサンプルコードIT系おじさんのチラシの裏2018年10月~プロフィールAUTHOR:とっちら書きたくなったときに書きたいことを書く雑記ブログ。IT系のネタが多いかも知れません。11:57とっちら1年前の記事に助けられました。14:28とっちらこの記事のお陰で60分録画できるようになりました。16:01とっちらライセンスを明示して貰えると使いやすいのですが。14:37ご回答いただきどうもありがとうございます。21:56とっちら超初心者です。)メールを送信するプログラムは何度も書いて、実際に運用もしてきていますが、だいたいは受信する環境がわかっている(例えばGmailで受信するとあらかじめ知っている等)状況でした。不特定多数の様々な環境の人へメールを送る必要に迫られ、あらためて文字化けとの戦いが勃発し、あー、自分なんも理解してなかったッスわー、と今更ながら気が付いたので、HTMLメール送信で学んだことを備忘録としてまとめておきます。基本的にはRFC5322やRFC2045に従えば良いのですが、いちいち読んでられんって人も多いと思うので、特にハマりがちなところを抜粋します。Agent)との通信全般に適用されるルールです。PHP等で件名と本文だけ指定してメール送信していると忘れがちですが、実際には下記のような形式でメールは送信されています。.このメッセージの全ての行において、必ず998文字以下であることが求められ、出来れば78文字以内にすることが推奨されています。78文字を超える場合はCRLFを入れて続きを次の行に書くようにします。...が、それは生データの話であって、base64等でエンコードされた文字列の場合は1行あたり76文字以内に収める必要があります。文字コードにUTF-8を使い、日本語を扱う以上、エンコードは避けて通れません。PHPではmb_encode_mimeheaderという関数が自動的に一定の文字数ごとに改行(CRLF)を入れてくれるのですが、逆にこのせいで文字化けするケースもあるため、ここでも注意が必要。Content-Transfer-Encodingのこと。文字コードはUTF-8、ShiftJIS、ISO-2022-JP、EUC-JPであり、Content-Transfer-Encodingは7bit、8bit、base64、quoted-printableのいずれかから選びます。文字コードはUTF-8、Content-Transfer-Encodingはbase64にする、と覚えておけば良いです。文字コードがUTF-8でContent-Transfer-Encodingを8bitにしておけばメールの件名も本文もUTF-8そのまんまなのでデバッグはしやすいのですが、不特定多数に送る可能性があるのならやはり避けたほうが良いです。7bitしか通さないMTAが存在するからです。えー、いまどきぃ?と思われるかもですが、不特定多数向けのWebサイトを運営していると実感します。日本人でも匿名性のためかプロキシーを通して等、わざわざ海外のフリーメールを使っている人がおり、8bitを通さないMTAを経由してメール受信している人が実在します。なると、残りは7bit、base64、quoted-printableの3つになるわけですが、最初の7bitはASCIIコードしか使えず、日本語で7bitで送信するとなるとISO-2022-JP限定になるので除外します。UTF-8に比べると使えない漢字が多いですし、UTF-8で定義された絵文字なども全滅だからです。base64とquoted-printableのどちらを使うかは意見がわかれるところですが、個人的にはサイズの都合上、base64と思っています。「いつもお世話になっております。」というUTF-8の文字があったとしましょう。これは全角15文字ですが、データ量(バイト数)でいうと45バイトです。日本語をUTF-8にすると1文字あたり3バイト使うからです。(絵文字等、4バイトの文字も存在する)ちなみに英数字の場合は1文字=1バイトです。全世界の文字を1文字2バイトにしようぜって話でUnicodeが出来たのに欧米人が............いやその話は脱線するからやめましょう。先ほどの文字をPHPでbase64とquoted-printableにエンコードして結果を見てみましょう。base64_encode("いつもお世話になっております。quoted_printable_encode("いつもお世話になっております。=E3=81=A3=E3=81=A6=E3=81=8A=E3=82=8A=E3=81=BE=E3=81=99=E3=80=82quoted-printableはASCII文字はそのままですが、それ以外の文字は「=」を付けてコードで表現するため、1文字あたり9バイトくらい使います。英数字しか送らない場合や、文字コードがISO-2022-JPなら、(7bit文字なので)Content-Transfer-Encodingをquoted-printableにすることで最も少ないデータ量で済むため、昔はこれが主流でした。昨今はスマホでもUTF-8に対応していますし、絵文字も普通に使うため、メールの文字コードもUTF-8が主流。なるとデータ量が3倍くらいに肥大化するquoted-printableよりも、1.5倍程度で済むbase64のほうが良いでしょう。PHPでHTMLメールを送信するサンプル最近はメルマガではもちろんのこと、SNSの通知メールですらHTMLメールが当たり前となっているので、HTMLメールを送信するサンプルにしました。'メールソフトがHTMLメールに対応していない場合、このメッセージが表示されます。改行コードは変数にしておくべきまず一番ハマりそうなポイントが改行コード。RFCの仕様では行末にはCRLFを書くというルールになっているのですが、qmailというMTAはあろうことかメッセージ中のLFをすべてCRLFへ変換するという処理をしてくれやがります。いつもお世話になっております。[CRLF]と行末に[CRLF]を付けたつもりが、qmail側では勝手に、いつもお世話になっております。[CRCRLF]というメッセージに変換されてしまうのです。メールクライアントによってはCRLFは改行、CRも改行、と判断するため、すべてのメッセージが1行置きに表示される、という状況になります。そんなメール、受け取ったことありませんか?それだけならまだしも、ヘッダー部分が無駄に改行されてしまうと別の意味になってしまいます。具体的にはヘッダーを送信した後、「空行」を1行送信してから本文を送信する、というルールがあるため、ヘッダー内で無駄に改行されると本文がはじまったと判断され、メール本文にヘッダーが流れ込むことになります。...ぼくはあります。sendmailならCRLFで問題ないのですが、このqmailを使っているレンタルサーバーはいまだに多いため、お使いのサーバーによってはわざと行末をLFにする必要があります。