Live Hotmailの件名文字化けを回避する方法

hotmailの件名文字化けが一向に改善されないようなので、なんとか回避できないか考えてみる。


まずhotmailの挙動を調べる。


最初に件名に何文字まで入るのか調べてみた。
「1234567890123…」(半角のみ)
「1234567890123…」(全角のみ)
「12345678901234567890123…」(半角+全角)
という長い件名のテストメールを自分宛に出してみる。


自分宛に届いたメールを開く。
結果は…

文字種別 件名 文字数
半角のみ 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 100文字
全角のみ 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 100文字
半角+全角 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 100文字


どうやら、半角全角に関係なく、100文字が限度の様子。内部処理はUnicodeで行っていると思われる。


ちなみに、WeMail32で受信するとこうなる。

文字種別 件名
半角のみ 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
全角のみ 1234567890123456789#0#1#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0
半角+全角 123456789012345678901234567890123456789012345678901234567890渦慨偽係弘駑駭34567890渦慨偽係弘駑駭駮駱駲67890


次に生ヘッダのSubjectを確認する。


(1)半角のみ

Subject:
 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890

半角のみの場合は行分割は行われないようだ。


(2)全角のみ

Subject:
 =?iso-2022-jp?B?GyRCIzEjMiMzIzQjNSM2IzcjOCM5IzAjMSMyIzMjNCM1IzYjNyM4Izkj?=
 =?iso-2022-jp?B?MCMxIzIjMyM0IzUjNiM3IzgjOSMwIzEjMiMzIzQjNSM2IzcjOCM5IzAj?=
 =?iso-2022-jp?B?MSMyIzMjNCM1IzYjNyM4IzkjMCMxIzIjMyM0IzUjNiM3IzgjOSMwIzEj?=
 =?iso-2022-jp?B?MiMzIzQjNSM2IzcjOCM5IzAjMSMyIzMjNCM1IzYjNyM4IzkjMCMxIzIj?=
 =?iso-2022-jp?B?MyM0IzUjNiM3IzgjOSMwIzEjMiMzIzQjNSM2IzcjOCM5IzAbKEI=?=

行頭の空白1文字を含め1行75文字となるように行分割されている。エンコーディングはJIS(iso-2022-jp)で、Bエンコーディング(base64)となるようである。


(3)半角+全角

Subject:
 =?iso-2022-jp?B?MTIzNDU2Nzg5MBskQiMxIzIjMyM0IzUjNiM3IzgjOSMwGyhCMTIzNDU2?=
 =?iso-2022-jp?B?Nzg5MBskQiMxIzIjMyM0IzUjNiM3IzgjOSMwGyhCMTIzNDU2Nzg5MBsk?=
 =?iso-2022-jp?B?QiMxIzIjMyM0IzUjNiM3IzgjOSMwGyhCMTIzNDU2Nzg5MBskQiMxIzIj?=
 =?iso-2022-jp?B?MyM0IzUjNiM3IzgjOSMwGyhCMTIzNDU2Nzg5MBskQiMxIzIjMyM0IzUj?=
 =?iso-2022-jp?B?NiM3IzgjOSMwGyhC?=

全角のみと同じ。

★復号

次にBエンコーディングを復号してみよう。


(2)全角のみ

         1         2         3         4         5
12345678901234567890123456789012345678901234567890
                                                                                                  • -
Subject: *$B#1#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9# 0#1#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0# 1#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0#1# 2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0#1#2# 3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0*(B

*はESC(0x1B)。「ESC $ B」は、JISコードで2バイトコードの始まりを表し、「ESC ( B」は、2バイトコードの終わり(以降は1バイトコード)を表す。
これを見るとわかるとおり、hotmailはJISコードに変換してから行分割を行っているため、2バイトコードの状態に入ったまま改行が行われる。2行目の最後は「…#9#」で終わっているが、これは全角「0」のJISコード(0x2330 '#0')が3行目と泣き別れている。この状態のヘッダを受け取ったとき、まず行分割を解除し行結合を行ってから論理行単位でJISコードに戻す分には問題ない。
しかし、WeMail32のようなメーラーの場合、各行を物理行単位でJISコードに戻してから行結合を行う。そのため、2行目の最後の「#」(「0」の泣き別れた上位オクテット)は正しいJISコードとして識別できないため無視され、2行目は「…789」となる。
3行目は、そもそも「ESC $ B」がないため1バイトコードとして扱われるため、「0#1#2#…」と意味不明な文字が表示されることになる。3行目以下も同様である。JISコードとして解釈した結果は以下のようになる。

Subject:
 1234567890123456789
 0#1#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0#
 1#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0#1#
 2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0#1#2#
 3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0

これを行結合すると「1234567890123456789#0#1#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0」という文字化けになる。


(3)半角+全角

         1         2         3         4         5
12345678901234567890123456789012345678901234567890
                                                                                                  • -
Subject: 1234567890*$B#1#2#3#4#5#6#7#8#9#0*(B123456 7890*$B#1#2#3#4#5#6#7#8#9#0*(B1234567890*$ B#1#2#3#4#5#6#7#8#9#0*(B1234567890*$B#1#2# 3#4#5#6#7#8#9#0*(B1234567890*$B#1#2#3#4#5# 6#7#8#9#0*(B

全角のみの場合よりさらに状況はひどく、3行目と4行目の間でESCシーケンス「ESC $ B」が泣き別れている。これはひどい
JISコードとして(無理やり)解釈するとこんな感じ。

Subject:
 12345678901234567890123456
 789012345678901234567890
 B#1#2#3#4#5#6#7#8#9#0123456789012
 3#4#5#6#7#8#9#0123456789012345
 6#7#8#9#0

物理行の途中で半角/全角の境目があると、ESCシーケンスが埋め込まれるため、そこでコード認識が正常状態に復帰する。
行結合すると「12345678901234567890123456789012345678901234567890B#1#2#3#4#5#6#7#8#9#01234567890123#4#5#6#7#8#9#01234567890123456#7#8#9#0」となる。
あれ?WeMail32の表示「123456789012345678901234567890123456789012345678901234567890渦慨偽係弘駑駭34567890渦慨偽係弘駑駭駮駱駲67890」と合わない…
この辺はWeMail32側の異常系処理にも少し問題があるのかもしれない。たぶん、ESCシーケンスが泣き別れているのが影響を及ぼしているのだろう。

★で、回避できるの?

メーラーに正しくJISコードを認識させるには、物理行単位でESCシーケンスを適切に埋め込んでやる必要がある。


(2)全角のみ
まず物理行の各行のESCシーケンスを適切に埋め込むと同時に、2バイトコードの泣き別れを無くす。

         1         2         3         4         5
12345678901234567890123456789012345678901234567890
                                                                                                  • -
Subject: *$B#1#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9*(B *$B#0#1#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0*(B *$B#1#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0#1*(B *$B#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0#1#2*(B *$B#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0*(B

次に物理行1行あたり75文字に収まるように行分割しなおす。base64符号化した状態で75文字なので、符号化前のJISコードレベルだと1行あたり42文字にする必要がある。

         1         2         3         4         5
12345678901234567890123456789012345678901234567890
                                                                                                  • -
Subject: *$B#1#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7*(B__ *$B#8#9#0#1#2#3#4#5#6#7#8#9#0#1#2#3#4*(B__ *$B#5#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0#1*(B__ *$B#2#3#4#5#6#7#8#9#0#1#2#3#4#5#6#7#8*(B__ *$B#9#0#1#2#3#4#5#6#7#8#9#0#1#2#3#4#5*(B__ *$B#6#7#8#9#0#1#2#3#4#5#6#7#8#9#0*(B

(42文字にするために、各行末に半角空白(_)が2文字ずつ付いている)
JISコードとして解釈すると

Subject:
 12345678901234567__
 89012345678901234__
 56789012345678901__
 23456789012345678__
 90123456789012345__
 678901234567890

となる。つまり、件名が全部全角であるとすれば、17文字ごとに半角空白2文字を挟めばよいことになる。例えばこんな感じ。
「12345678901234567  89012345678901234  56789012345678901  23456789012345678  90123456789012345  678901234567890」
これはWeMail32でも正しく受信できることを確認できた。


(3)半角+全角

半角と全角が混在する場合、ESCシーケンスが頻繁に現れることになるため単純にはいかない。
上の例でいくと、

         1         2         3         4         5
12345678901234567890123456789012345678901234567890
                                                                                                  • -
Subject: 1234567890*$B#1#2#3#4#5#6#7#8#9#0*(B123456 7890*$B#1#2#3#4#5#6#7#8#9#0*(B1234567890 *$B#1#2#3#4#5#6#7#8#9#0*(B1234567890*$B#1#2*(B *$B#3#4#5#6#7#8#9#0*(B1234567890*$B#1#2#3#4#5*(B *$B#6#7#8#9#0*(B

行末を1バイトモードで終えるためには、「ESC ( B」の3バイトを行末に持ってこなければならず、そうすると4行目の行末で42文字をオーバーしてしまう。42文字で収めるために行末の2バイトコードを次の行に持っていくと、「ESC $ B ESC ( B」という全く意味のないコードができてしまう。この意味のないコードを削除すると、行末に半角空白を6文字入れなければならなくなる。

         1         2         3         4         5
12345678901234567890123456789012345678901234567890
                                                                                                  • -
Subject: 1234567890*$B#1#2#3#4#5#6#7#8#9#0*(B123456 7890*$B#1#2#3#4#5#6#7#8#9#0*(B1234567890__ *$B#1#2#3#4#5#6#7#8#9#0*(B1234567890______ *$B#1#2#3#4#5#6#7#8#9#0*(B1234567890______ *$B#1#2#3#4#5#6#7#8#9#0*(B

JISコードを適用して結合すると、「12345678901234567890123456789012345678901234567890  12345678901234567890      12345678901234567890      1234567890」となるが…
変に途中で空白が入って間延びしてるので何か変。しかもいちいちこの変換を行うのは手間に過ぎる。
でもまあ、いちおうWeMail32でも正しく認識はできた。

★結論

半角/全角混在の場合は手作業でやれば何とかなるが、単純に計算できないので、当面は

  • 件名を全部全角で書く(半角は混ぜない)
  • 全角17文字ごとに半角空白2文字を挿入する
というのがとりあえず最もわかりやすい文字化けの回避策になりそうだ。