はじめに
メールリーダーThunderbird(78.11.0/Windows10)でメールを受信したときに、ときどき件名(Subject)にゴミが混ざります。他のメールリーダーでは正常に表示されるので、どうやらThunderbirdの問題のようです。
具体的には、こんな感じで、ゴミ(�)が混ざります
「学科Webメンテナ�ンス(3/14)実施」
「ABCあい�うえおEFG」
同じSubjectでもゴミが混ざらない場合があります。それでメールのソースをみて差分を調べてみました。
補足: 本ブログの実験を試すにはLinuxにnkfとMewをインストールしてください。
ゴミが混ざる条件(1)
日本語メールのSubjectの文字コードは多くの場合、JIS(iso-2022-jp)もしくはUTF-8です。
そして、Bエンコーディングされています。(Qエンコーディングの場合もあります。)
ゴミが混ざるのはJIS+Bエンコーディングの時によく起きるようです。少なくとも私の確認した範囲では。
どうもJIS固有の何かのようです。
(余談)メールのSubjectのエンコーディング
すでにご存じの方は読み飛ばしてください。
例えばSubjectが「ABあいUE」のメールの場合、JISでBエンコーディングで記入されたメールのソースをみるとSubjectは次のようになってます。
Subject: =?iso-2022-jp?B?QUIbJEIkIiQkGyhCVUU=?=
ここで「 =?iso-2022-jp?B?」がBエンコーディングの始まり指定で、「?=」が終了指定です。
なのでSubjectの本文は
QUIbJEIkIiQkGyhCVUU=
です。上記はBASE64エンコーディングといいます。3バイトの8bitデータを4個のアスキーコードに置き換えるエンコーディングです。詳細はこちらをご覧ください。
このBASE64をdecodeしてみますと以下のようになります。ESCはASCIIの27番です。$は全角になってますが本当は半角です。空白は読みやすいように加筆したものです。
A B ESC $ B $ " $ $ ESC ( B U E
ここで「ESC $ B」という並びはJISコードの始まりという意味です。 「ESC ( B」という並びはJISコードの終わり(ASCIIコードの始まり)という意味です。読みやすくするとこうなります。
A B (JIS開始) $ " $ $ (JIS終了) U E
次に「$ "」はJISで「あ」です。「$ $」はJISで「い」です。なのでまとめると
A B あ い U E
になります。
ゴミが混ざる条件(2)
さて本題に戻りまして、Subjectの文字化け発生条件ですが、無駄にJIS開始および終了が挟まると文字化けするようです。
たとえば「あいうえお」のJIS開始および終了は
(JIS開始)あいうえお(JIS終了)
とするのがシンプルですが、次のように無駄にJIS開始および終了が挟まると文字化けするようです。
(JIS開始)あい(JIS終了)(JIS開始)うえお(JIS終了)
試しにやってみましょう。nkf -jでJISコードに変換します。echo の -n は最後に改行を付けないという意味です。3行目のperlはBASE64 encodeです。4行目がBASE64のencode結果です。
$ echo -n "あい"| nkf -j > tmp.txt
$ echo -n "うえお" | nkf -j >> tmp.txt
$ cat tmp.txt | perl -MMIME::Base64 -0777 -ne 'print encode_base64($_)'
GyRCJCIkJBsoQhskQiQmJCgkKhsoQg==
上記の4行目のBASE64の結果の前後をBエンコーディングの開始終了を挟むと次のようになります。
=?iso-2022-jp?B?GyRCJCIkJBsoQhskQiQmJCgkKhsoQg==?=
このSubjectでメールを送ればいいのですが、日本語対応のメールリーダーだと色々な加工が入り、そのまま送信はできません。
各種メールリーダーを確認すると、Mewだとそのまま送れます!。 MewでSubjectに上記文字列を張り付けて送信してみます。
予想通りThunderbirdで文字化けが再現しました。
蛇足1
上記のような無駄なJIS開始およびJIS終了を入れるソフトの特定はできているのですが、それは本筋でないので省略します。時間があればdebugしたい。。
蛇足2
Qエンコーディングでも試してみましょう。
$ cat tmp.txt | perl -MMIME::QuotedPrint -0777 -ne 'print encode_qp($_)'
=1B$B$"$$=1B(B=1B$B$&$($*=1B(B=
上記で最後に現れる「=」はソフト改行なので除去してください(詳細はWikipedia参照)。Qエンコーディングの開始終了を追加すると以下のようになります。
=?iso-2022-jp?Q?=1B$B$"$$=1B(B=1B$B$&$($*=1B(B?=
これをMewでSubjectに上記文字列を張り付けて送信してみます。
すると同じ場所にゴミが混ざりました。
蛇足3
このゴミ(�)ですが、Thunderbirdで具体的には何の文字コードが割り当てられているか調べてみました。SubjectのゴミはJISのみで発生しますが、このメールにメールに返事を書くと、Subjectの文字コードがUTF-8でもゴミが温存されます。このSubjectのコードを調べると「%ef %bf %bd」のようです。これはUNICODEのU+FFFD(replacement character)のUTF-8表現のようです。
Ref: https://ja.wikipedia.org/wiki/Specials_(Unicode_block)
以上です。