freemlの承認待ちになったメールで文字化け
少し前に起こった文字化けメールについてまとめておく。
文字化けしたメールは受信者に届くまでに中継サーバーで加工されたもの。同じメールを直接受信したものと中継サーバーを通して受信したもののソースの一部。Thunderbirdでテキストエンコーディング「Unicode」で表示。 pic.twitter.com/SINVoXxMbo
— 正己 (@self7777) 2016年6月10日
文字化けが生じたのは、freemlで「承認待ち」になって承認されたメールをhtml形式で表示した場合である。「添付ファイルがある/またはHTMLメールである」場合は承認が必要になるように運営していると、添付ファイルがなくてもHTML形式のメールが届くたびにメーリングリスト(ML)の管理人が承認する必要がある。文字の一部が文字化けすることは何度もあったが、今回の文字化けは異質で、ユーザーによる対処が難しいので注意していただきたい。
以前(2011/2/6)に【Thunderbirdが勝手にUTF-8に変えて送信するのに警告を出さない】を書いたのだが、この仕様がfreemlを利用する時に悪影響をもたらしそうである。最近は、Thunderbirdに限らずメールをUTF-8でエンコードするソフトが増えてきたと思うが、freemlを利用する時には注意が必要である。
私が遭遇した文字化けを避ける方法を先に書いておく。以下のいずれかの方法で避けられると思われる。
- HTML形式のメールが承認待ちにならないように運営する。
- HTML形式のメールを承認する前に「HTML形式で表示する」をクリックして確認して、文字化けしていたら承認しない。
- 常にテキスト形式で送信してもらう。
- 返信時を含めて必ずISO-2022-JPでエンコードして送信してもらう。
- base64やquoted-printableでエンコードして送信してもらう。
さて、文字化けしたメールのソースは次の通りである。
上のソースはfreemlで承認待ちになって承認された後に届いたメールであるが、同時に自分宛にも送信していて、そちらは次のようなソースで文字化けしなかった。
送信にはThunderbird 45.1.1 を利用した。他のメールソフトでは未確認であるが、GmailのWebメールやモバイルを使った送信では「content-type: text/html; charset=UTF-8」の方が「content-transfer-encoding: base64」となって、文字化けしないと思われる。また、Yahoo!メールのWebメールからだと「content-type: text/html; charset=UTF-8」の方が「content-transfer-encoding: quoted-printable」となって、文字化けしないと思われる。Thunderbirdでは、「content-type: text/html; charset=UTF-8」の方が「content-transfer-encoding: 8bit」となっていて、これがfreemlの「承認」を経由した場合に文字化けが生じる条件だと思われる。
メールのソースを分析した時、私は文字コードの混在が文字化けの原因だと勘違いした。文字化けしたソースとしてないソースを比べると、freemlの承認サーバーを経由したメールは「content-type: text/plain」の方が「charset="iso-2022-jp"」となっていて、「content-type: text/html」の方は「charset=UTF-8」で異なってる。freemlの承認サーバーを経由しなければどちらも「charset=UTF-8」である。それで勘違いしたのだが、文字化けした方のメールの「content-type: text/html」で文字化けしている部分を文字化けしてないメールからコピーして、ファイルをUTF-8で保存してThunderbirdにドラッグ&ドロップして確認したら、文字化けしなかった。HTML形式での表示ではUTF-8で問題なく表示され、テキスト形式ではJISで問題なく表示される。また、文字化けしてないメールの<p> から </p> までを【エンコードマニアックス】を使ってエンコードしても、文字化けしたメールのようにできないし、文字化けしたメールの方の同じ部分をデコードしても元の文字には戻せなかった。そこで、別の原因を推測しなければいけなくなった。
文字化けした方のメールをよく見ると、</p> が前の文字化けに巻き込まれて /p> となっている。それで、以前(2010/11/18)に書いた【Yahoo!グループでSubjectが文字化けする原因】を思い出した。
そこでは、次のように結論付けた。
まとめると、『Yahoo!グループでは送信されたメールのSubjectで分割されているJISコードを一度合成してから処理して再度分割するのかもしれないが、再分割の際に「GyRC」や「GyhC」を無視するなどして、分割してはいけない所で分割してしまい文字化けを発生させている。(追記:あるいは再分割せずにメールサーバに送り、76文字を超えていることでメールサーバーが機械的に分割することで不適切な所で分割されてしまって文字化けを発生させている。【参照】)』ということだろう。
(Yahoo!グループでSubjectが文字化けする原因)
今回の文字化けはUTF-8で起こっているので、Yahoo!グループのケースとは少し異なる。ただ、「content-type: text/html; charset=UTF-8」の方をいったんbase64でエンコードしてからデコードして元に戻した時に文字化けが生じていそうである。content-transfer-encoding が 8bit ではなく、base64 や quoted-printable の場合はエンコードしてないかもしれないし、エンコード後にデコードしても文字化けしないだろう。
【Yahoo!グループでSubjectが文字化けする原因】で参考にした【第235章 base64の基礎 】を見ると次のように書いてある。
base64では、次のような方法をとります。
1.エンコードしたい文字列を前から順番に3バイトずつ区切ります。
2.これを今度は前から順に6ビットずつ区切りなおします。
3.この6ビットの値に応じてA-Z, a-z, 0-9, +,/の文字に置き換えます。
(第235章 base64の基礎 )
1.各漢字のJISコードを調べる
2.2進法で表す
3.前から6けたずつ区切る
4.16進(10進でもいいですが)になおす
5.それぞれの数値に対応する記号(A-Z, a-z, +, /)になおす
(第235章 base64の基礎 )
詳しいことは調べてないが、今回は次のような手順かもしれない。
1.各漢字のUTF-8コードを調べる
2.2進法で表す
3.前から6けたずつ区切る
4.16進(10進でもいいですが)になおす
5.それぞれの数値に対応する記号(A-Z, a-z, +, /)になおす
【第235章 base64の基礎 】には「JISでは2バイト文字の始まりの合図として(0x1b, 0x24, 0x42) の3バイトを付けなくてはなりません」「2バイト文字の後にはASCII文字が来るので(0x1b, 0x28, 0x42) を付け加えます」とあるが、UTF-8の場合は分からない。ただ、上記のメールの文字化けした<p> から </p> までをまとめてbase64にエンコードした場合と、2バイト文字とASCII文字を分けてからbase64でエンコードした場合は異なるので、デコードする前に何かをすると文字化けするかもしれない。
【Yahoo!グループでSubjectが文字化けする原因】の時のように手動でエンコードして全く同じ文字化けを再現してみたいが、今は時間と気力が無いので省略する。興味がある人は自分で確認してほしい。
freemlの承認メールでの文字化けがbase64によるエンコード→デコード処理によるものかどうかは分からない。しかし、文字コードの混在や機種依存文字によるものではないことは確かだろう。freemlの方は改善する余裕が無いかもしれない。だからユーザーの側で気をつけるしかない。対処法は上の方に記載したとおりである。
Thunderbirdの場合、返信時などに勝手にUTF-8で送信してしまうことがあるが、【Thunderbirdが勝手にUTF-8に変えて送信するのに警告を出さない】に書いたとおり、Thunderbirdのオプションの詳細から「設定エディタ」(about:config)を開いて mailnews.disable_fallback_to_utf8.ISO-2022-JP を「true」に変更すれば防げそうである。実際、今のところ、私が送信したメールで文字化けが生じたという報告は無い。
コメント 0