MIMEとメールのダイエット

Hiroshi FUKUDA

(2022.8.8-2023.3.22)

メールはテキスト(印字可能文字の)ファイルです。メールのテキストをメールのソースといいます。メールのソースは,MIME(Multipurpose Internet Mail Extensions)という規格(規則)に従って書かれています。

メーラー

メーラー(メールソフト)は,MIMEに従ってメールのソースを解釈して表示します。MIMEを理解すれば,大きなメールのソースから,無駄な部分を圧縮したり削除したりしてファイルサイズをダイエットする事ができます。「メールのダイエット」というと,普通,書くメールの本数や本文の量を減らすことを指すようですが,ここでは,メールボックスを圧迫しないように,保存してあるメールの無駄な容量を削減するという意味で使います。

thunderbird

最も歴史があり信用できる,標準メーラーはthunderbirdです。例えば,他のメーラーでは文字化けしないのに,thunderbirdでは文字化けする,ということが起こります。これは,thunderbirdがMIMEに忠実で,他のメーラーでは文字化けを避けるために,MIMEを甘く解釈して処理を行っているからです。メールのダイエット処理もMIMEに厳格なthunderbirdを使って行うのが安全です

emlファイル

thunderbirdでは,Ctrl+Sでメールのソースを拡張子がemlのテキストファイルとして保存できます。逆に,emlファイルは,thunderbirdのメールのフォルダにドラッグ&ドロップすれば,メールとして取り込めます。

それゆえ,メールのダイエットは,メールをemlファイルで保存し,ソースを編集して,再びメールフォルダに戻して行います。

emlファイルの編集は,Visual Studio Code(VSCode)にEmail extensionを入れて行うと,MIME文法が色分けされて表示されるので便利です。

文字コード

メールソースで使われる文字コードは,英語圏ではASCII(Unicodeの127番目まで)文字です。

1バイトでASCII文字を表現すると,最上位の1ビットは使われないことから,メールの通信経路では,この最上位1ビットが送られないことがあります。

日本語では,MIMEに従って,JIS(iso-2022-jp)か UTF-8が使われます。

JISコード

JISコード(iso-2022-jp)では,ASCII文字で次のように日本語の文字を表します:ESC(1B)に続く2バイトで文字集合を指示し,文字はASCIIのGL文字n個で表します。指示が(BならASCII(n=1),(JならJIS C 6220(n=1,カタカナなど),$@ならJIS C 6226(n=2),$BならJIS X 0208(n=2)です。

JISコードも1バイト中7ビットしか使わないので,最上位1ビットが送られない可能性のあるメールで使われるようになりました。しかし、最近はそのような経路は無くなったので、メールのコードもUTF-8に統一されつつあります。

文字コードの変換

文字コードは,VSCodeや秀丸などのエディタ,または(linuxの)nkfコマンドで行えます:

nkf -オプション 入力ファイル > 出力ファイル

オプション

nkfはWSLにapt install nkfでインストールできます。なお,VSCodeではJISコードはUTF-8で表示されるESCは絵文字で表示される)のでコードの変換は行えませんが,秀丸エディタではJISコードも変換できます。

改行コード

テキストデータの1行の区切りを表すコードはシステムによって異なり,CR(0x0D)またはLF(0x0A)が使われます。

nkfにオプションを指定して,これらを変換できます

nkf -オプション 入力ファイル > 出力ファイル

オプション

しかし,メールダイエットの作業では改行コードの変換は必要ありません。

文字エンコード

テキストデータに限らない,一般のデータをテキストデータに変換することを文字エンコード,逆に,元のデータに戻すことを文字デコードといいます。メールはテキストデータであるため,画像などの一般のデータを添付する際は文字エンコードが使われます。電子メールで使われる文字エンコードは,quoted-printable, base64, uuencode, binhexなどです。

base64

データを6ビットに区切り,64通りある6ビットの値を1バイトのASCII文字に置き換えます(以下ではこれを8/6変換と呼びます)。base64エンコード/デコードはbase64コマンドで行えます。

base64 [-d] 入力ファイル > 出力ファイル 

オプション-dがなければエンコード,-dがあればデコード。base64WSLにapt install base64でインストールできます。

テキストデータのデコードはなぜかbase64ではエラーでできない事が多いので,以下のようにnkfで行います:

nkf -mB 入力ファイル > 出力ファイル

quoted-printable 

=に続く2桁の16進数で文字コードを表します(=3Dなど)。ただし,=を除く文字コードが0x21~7EのASCII文字はそのままでもかまいません。行末の=は行の継続を表します。テキストデータのquoted-printableのエンコード/デコードはnkfで行うことができます

エンコード

nkf -MQ 入力ファイル > 出力ファイル

デコード

nkf -mQ 入力ファイル > 出力ファイル

(QをBにすると,base64のエンコード/デコードができます)

uuencode

 8/6変換後,データの先頭にヘッダー行,末尾にフッター行(end)が付加されます。

binhex

8/6変換後,圧縮と誤り検出が加えられ,ヘッダー行 (This file must be converted with BinHex 4.0) が付加されます。

pythonでbinhexエンコード/デコードを行えます Google ColaboratoryでGoogle Driveをマウント(画面左側の📁を選択し、[ドライブをマウント][GOOGLEドライブに接続])し,/content/drive/My Drive/ に処理したいファイルをアップロードします。

デコード:

import binhex

binhex.hexbin('/content/drive/My Drive/入力ファイル', '/content/drive/My Drive/出力ファイル')

エンコード:

import binhex

binhex.binhex('/content/drive/My Drive/入力ファイル', '/content/drive/My Drive/出力ファイル')

サンプル入力ファイル(hello.docx)サンプル出力ファイル(hello.txt)

MIMEヘッダ

MIMEでは,次のようなMIMEヘッダという形式で,文字コードやデータの種類を指定します。

Content-Type: Multipart

Content-Type: multipart/mixed; boundary="文字列"

"文字列"で区切られるパートからなる,マルチパートメールであることを示します。Content-Typeに続くMIME Typeはここに一覧があります。

Content-Type: multipart/alternative; boundary="文字列"

個々のパートが,プレーンテキストとHTMLのように,同じ内容であることを示します。

Content-Type: multipart/signed; protocol="application/pkcs7-signature"; micalg=sha1; boundary="文字列"

署名されていることを示します。

Content-Type: text

Content-Type: text/html; charset="文字コード"

HTML文書。文字コードはUTF-8,Shift_JIS,EUC-JP,ISO-2022-JP。ISO-2022-JPがJISコード。

Content-Type: text/plain; charset="文字コード"

テキスト文書。

Content-Transfer-Encoding:

Content-Transfer-Encoding: 文字エンコード

文字エンコードを指定します。base64,quoted-printable,あるいは7bit,8bit。Nbitとは,バイト並びの下位Nビット文字コードとして解釈し,上位8-Nビットは無視するという意味です。

ファイル

Content-Type: 種類; name="ファイル名"

ファイル。種類は application/msword,application/pdf,application/vnd.ms-excel;image/bmp,image/gif,image/jpeg,image/png,image/svg+xml,image/tiff など。

Content-Disposition: attachment; filename="ファイル名"

添付ファイル。

Content-Disposition: inline; filename="ファイル名"

Content-Id: <コンテンツID>

内部ファイル。コンテンツIDで参照します。

Content-Type: application/pkcs7-signature; name="smime.p7s"

Content-Transfer-Encoding: base64

Content-Disposition: attachment; filename="smime.p7s"

Content-Description: S/MIME Cryptographic Signature

署名ファイル。

件名や送信者名などの文字コード

件名や送信者名などメールヘッダに日本語を含めるには,次の形式で文字コード,文字エンコードを指定します:

=?文字コード?文字エンコード方式?文字列?=

文字コードは,UTF-8かISO-2022-JP,文字エンコード方式は,Base64の場合B,Quoted-Printableの場合Q,いずれかの値が入ります(本文の文字エンコード方式で利用できる7bit,8bitに相当するものはありません)。

メールのダイエット例

thunderbirdでは,添付ファイル分離暗号化メールの復号はできますが,その他のダイエットはできないので,以下のように手動で行う必要があります。頻繁にあり得るものはスクリプトeml-minifierを作りましたので,ご利用ください。

インライン添付ファイルの分離

署名付きメールの添付ファイル分離

thunderbirdでは,署名付きメールの添付ファイルは分離できないので,以下のように手動で分離します。

返信の引用を削除

返信メールから,長々と引用された返信元のメールを削除するには,以下のようにします。

winmail.datで添付されたファイルの分離

Content-Type: 種類; name="ファイル名"

Content-Disposition: attachment; filename="ファイル名"

画像ファイルのダイエット

base64 処理済み画像ファイル名 > テキストファイル名

ファイルの分離先

添付ファイルやインラインファイルの分離先として,ローカルマシンのフォルダを指定しておけば,ファイルが分離された事を意識することなく利用できます。

添付ファイルの分離先URL

file:///C:/.../ファイル名 のようにフォルダを/で区切って指定するか,http://localhost/.../ファイル名 とします。

Content-Type: 種類; name="ファイル名"

Content-Disposition: attachment; filename="ファイル名"

X-Mozilla-External-Attachment-URL: 分離先URL

X-Mozilla-Altered: AttachmentDetached; date="Tue Mar 31 11:13:55 2020"

インラインファイルの分離先URL

text/htmlのimgタグのsrcような参照先を,分離先URLに置き換えます。この場合,file://でローカルファイルをしても上手くいかないようです。http://なら上手くいきます。

そこで,Windowsの場合,Webサーバ,インターネットインフォメーションサービス(IIS)を起動しておけば,ローカルファイルをhttp://localhostで参照できます。

IISの起動法

⚙→[アプリ]→[プログラムと機能]→[Windows機能の有効化または無効化]→[インターネットインフォメーションサービス]をチェック。

IISの設定

[スタート]を右クリックして[コンピュータの管理]→[サービスとアプリケーション]→[インターネットインフォメーションサービス]で[ディレクトリの参照]でディレクトリを開いて,[Default Web Site]を右クリックして[仮想ディレクトリを作る]でファイルを置きたいディレクトリを指定する。http://仮想ディレクトリ名/でファイルを参照できます。