Windows上のCGI(Perl)でメールを送信するが、Thunderbirdで文字化けする。

Thunderbirdで文字化けする。

長年、社内システムをWindowsServer上のPerlで組んで運用していた。

かれこれ20年以上前から・・・・。

しかし、ウィンドウズのバージョンアップ等で、OSの載せ替えを余儀なくされ、その都度、細かい設定変更を行ってきた。

当初はsendmailを使用していたが、OSの変更でPerl自体を変更した結果使えなくなり、変わりにNet::SMTPを使う事になった。

その他、表示端末がウィンドウズPCだけではなく、スマホと言う新しいデバイス、OS、メールクライアントが出現し、今までは正常に表示されていたメールも、文字化けが発生するようになってしまった。

利用者にはなんとか我慢してもらっていたのだが、ついに御達しがかかり、修正する事となった。

症状

ウィンドウズ上Outlookや、Beckyでは正常に表示されるが、Thunderbirdや、アンドロイドスマホ上のOutlook、メールクライアントで文字化けしてしまう。

この時点で、社内なので「メールソフト変えてくれよ。」等の安易な方法も出来なくはないが、やはりこれは何とかしてやらんといかんなという事で作業に取り掛かる。

なかなか原因がわからない。

色々な先人の知恵をググってみるのだが、大体はタイトルに、

=?iso-2022-jp?B? タイトル ?=

を入れなさい。と言うアドバイスであるが、これを行う事で一部メーラーで改善されるのだが、Thunderbirdだけはどうしても文字化けする。

・・・余談ですが、「~しなさい。」と言う文言を聞くと、

じろう


これをお食べなさい・・・

と「シベリア」を差し出すあのアニメ映画のワンシーンが私の中でこの言葉がループしてしまう。
あれは、ある意味凄くインパクトあるシーンだ。

閑話休題。

色々ググって調べ、何をやっても駄目なので、ウィンドウズ+Perlシステムでは、現在のマルチな環境では対応できないのではないかと半分諦めかけていた。

特にThunderbirdはウィンドウズ上だとしても「形式」に厳格であり、他のソフトでは自動的に解釈してくれるところが、容赦なくダメ出しをしてくれる。逆にThunderbirdで正常に表示されれば、どのソフトや環境でも正常に表示されるという、車の世界でいうならばニュルブルクリンクのような、非常に厳しいソフトなのだ。

文字化けの3つの要因

文字化けする要因としては、

  1. ヘッダの項目
  2. エンコード
  3. 文字コード

この3つ。

まず、ヘッダの項目

Mime-Version:
From:
To:
Date:
Content-Type:
Content-Transfer-Encoding:
Subject:

この5つが必要。

From:
To:
Date:

は、文字化けには関係がない。

Mime-Version:
Content-Type:
Content-Transfer-Encoding:
Subject:

を、送信する側が適切な値を入れてやる必要がある。文字化けに関して受信側メーラーは、よっぽど無名なメーラか、不具合のあるソフト以外はほぼ無関係といって良い。

Mime-Version:

この項目は、ヘッダがどの規則に従って書いてますという宣言。

お決まりなので、 今の所1.0で良い。

なので、

Mime-Version: 1.0

となる。

Subject:

ここですね。大体はここで詰まるのですが、前述したように、

=?iso-2022-jp?B? + 「タイトル文字列」 + ?=

にする事が挙げられているが、これは私の環境では半分合ってて半分間違いになる。

まず、「=?」  から 次に出てくる「?」までの間に表示される文言が、エンコードされる前の元の文字コードを宣言してやらないといけない。

この記述だと「iso-2022-jp」で書いてますよと言う事になるのだが、大体、日本語だから「iso-2022-jp」と言う解釈にしていた。そして、Thunderbird以外では正常に表示されることから、「iso-2022-jp」で合ってるよなと疑わなかった。

今回のシステムは昔からのウィンドウズ用ソースなので、ソース文字コードはシフトJIS。なので、「Shift_JIS」が正解。

では、その後の「B?」は何?という事だが、「B」はエンコードをBase64で行ってますよと言う宣言。なので、後述するエンコードBase64で行っている場合は、「B?」でOK。

なので、あとは「?=」で括ってやればいい。即ち、

=?Shift_JIS?B? + 「タイトル文字列」 + ?=

が正解。

因みに、quoted-printableエンコードで行っている場合は、「Q?」となる。詳細は割愛。

そして、タイトル文字列をこのヘッダ最後とし、本文と分ける場合は、改行コードが2つ「\n\n」必要。

Content-Type:

この項目は「Content-Type: text/plain;」固定で大丈夫。

その後の charset=に指定する文言。これは本文の文字コード指定と言う意味で、「Subject:」で説明した通り、Windows+Perl構築CGIでは、文字コードはシフトJISコードになるので、この後に指定するcharsetは、 「charset=Shift_JIS」が正解。

なので最終的にはこうなる。

Content-Type: text/plain; charset=Shift_JIS

Content-Transfer-Encoding:

この項目は、そもそもウェブ上で日本語データをやり取りし、また、データ転送の効率を上げる為に必要なエンコード(暗号化)作業を何でやりましたという宣言。

Perlでは、MIME::Base64モジュールがあるので、このBase64エンコーディングを行う。

即ち

Content-Transfer-Encoding: base64

という記述になる。

なので、最終的には、

Mime-Version: 1.0
From: 送信元アドレス
To: 送信先アドレス
Content-Type: text/plain; charset=Shift_JIS
Content-Transfer-Encoding: base64
Date: 送信日時
Subject:?Shift_JIS?B? + 「タイトル文字列」 + ?=
「改行」
~以下本文~

となる。

※このセクションでは、特に順番、大文字小文字は関係なく(全角は勿論ダメ)、見やすさ等で工夫していい。本文との間に改行コード「\n\n」を二つ入れる事だけ気を付ければいい。

タイトルと本文のエンコード

勘違いしやすいのがエンコードと文字コード。

くり返しになるが、このエンコードはネット通信を簡便に行うための物。文字コードは文字そのもののコード。

エンコードを行わず、Content-Transfer-Encodingを指定してしまうと、また文字化けが発生する。だが、エンコードを行わずにそのまま発信しても、日本語の場合は必ず文字化けするので、エンコードは必須。

Perlでは、前述したようにBase64でエンコードできるので、以下のようなコーディングとなる。

use MIME::Base64;
$Title = encode_base64($Title); #タイトルのエンコード
$Body = encode_base64($Body); #本文のエンコード

このエンコード処理したタイトルである$Titleを、先ほどのヘッダのSubjectに挿入。
改行コード2つ付加「\n\n」(結果的には1行開ける)し、その直後に$Bodyを本文として挿入し送信すると、Thunderbirdでも、正常に理解して文字化けなく表示してくるようになった。

まぁ、そもそもソースコードをUTF-8や、送信する前にコンバートメソッドでJIS等に変換してやればいいのだろうけど、そうするとブラウザ表記もすべて変更を迫られ、ソース膨大かつ多岐に渡るので横着してしまった。そもそも、Windows+Perlってどうなのという事になるので、次期システムはやるならシステム自体を刷新する必要がある。

それでも文字化けする

大体は、このヘッダ文字列がきっちり送られていない(改行コードが入ってない等)が多い。
Thunderbirdでヘッダを表示するか、メール全体をテキストエディタで表示して確かめる。

Thunderbirdで、ヘッダを表示するには、先ずThunderbirdのメニューバーを表示(上部分を右クリックでメニューバーをチェック)させ、そのメニュー内の表示(V)→ヘッダー(H)→すべて(A)を選択すると、メールのヘッダーが表示される。

回私が嵌った例としては、ヘッダの「Content-Type」と「Content-Transfer-Encoding」の改行が正常に挿入されておらず、全てContent-Type列に認識されてしまい、「charset」が指定通りの文字コードに認識されていなかったという事例。
この症状でも、Thunderbird以外では正常に表示されているというから、良くも悪くも、他のメーラーがいかに懐の深い解釈をしてもらっている事が良く判る。

最終的には、この修正を行った事によってようやっと全てのメーラー、デバイスで正常に表示されるようになった。やれやれ。

また、刷新され、対応を余儀なくされるとは思うが、暫くはこれで凌げそうだ。