スキップしてメイン コンテンツに移動

そもそも添付ファイル名の規約ってRFCでどうなってるの?

Outlookから送ったメールの添付ファイル名が、iPhoneで「=?utf-8?Q?...?=」と無残に文字化けしてしまう現象。その元凶を紐解くと、1990年代から続く「RFC規格のねじれ」と、Microsoftによる「独自の割り切り」という深い闇に突き当たります。

前回の検証記事(Outlookのエンコード選択 / iPhoneでの5nの法則)を補完する形で、そもそもRFC(インターネット標準)では添付ファイル名がどう定義されているのかを解説します。

1. 添付ファイル名を定義する「RFC 2183」

メールにファイルを添付する際、ヘッダーには Content-Disposition というフィールドが使われます。これを定義しているのがRFC 2183です。

Content-Disposition: attachment; filename="example.txt"

ここで重要なのは、このRFC 2183が制定された1997年当時、filenameパラメータには「7bitのASCII文字(英数字)」しか想定されていなかったという点です。日本語などのマルチバイト文字をどう扱うかは、この規格内には書かれていません。

2. 日本語対応の救世主「RFC 2231」

そこで、ファイル名に日本語を使ったり、長すぎる名前を分割したりするために作られたのがRFC 2231です。これが現在、世界標準の「正しい作法」です。

  • 特徴: filename*=utf-8''%... という形式を使い、文字コードを明示する。
  • 利点: ヘッダーの文法を壊さずに、安全に非ASCII文字を伝送できる。

3. なぜ問題が起きるのか? ― Outlookの「不採用」

ここが最大のポイントですが、デスクトップ版のOutlook(2019等を含む)は、この「正しい作法(RFC 2231)」を頑なに採用していません。

代わりにOutlookが何をしているかというと、本来はメールの件名(Subject)などに使うための規格であるRFC 2047(Encoded-Word)を、添付ファイル名のパラメータの中に無理やり流用しているのです。

【Outlookの非標準な挙動】
Content-Disposition: attachment; filename="=?utf-8?B?...?=" (Base64形式)
Content-Disposition: attachment; filename="=?utf-8?Q?...?=" (Quoted-Printable形式)

※RFC 2047の仕様書には「このエンコードをパラメータ(quoted-string)内で使ってはいけない」と明記されているため、これは明確なRFC違反です。

4. iPhone(iOS Mail)の孤独な抵抗

受信側のiPhoneは、本来この「違反」を無視しても構わない立場です。しかし、あまりにOutlookユーザーが多いため、iPhone側で「救済措置」を入れています。

  • Base64(?B?)の場合: Appleが「まあ、Outlookの仕業だな」と判断してデコードしてくれるため、正しく表示される。
  • Quoted-Printable(?Q?)の場合: Appleのパーサーがこれをエンコードと見なさず、ただの文字列として扱う。結果、iPhoneの画面にはデコード前の無残な生コードが表示される。

まとめ:ユーザーが踏む地雷の正体

検証記事で明らかになった「5n文字」などの特定の条件下でOutlookがQエンコードを選んでしまう挙動は、まさにこの「標準を無視する送信側(Outlook)」「中途半端に救済を拒む受信側(iPhone)」のデッドロックによって引き起こされています。

根本解決は「OutlookがRFC 2231に対応すること」なのですが、四半世紀放置されている現状を鑑みると、私たちはこの「RFCのねじれ」と付き合い続けるしかなさそうです。

コメント

このブログの人気の投稿

Chatの「メッセージは投稿者によって削除されました」を非表示にする方法

Chrome拡張機能を自作してやってみよう! ♪できるかな できるかな ・・・ 無理ぽ (´・ω・`) iframeの中に、実際のメッセージのやり取りが表示されるので、 $(function(){ $('iframe[name^="spareFrame"]').contents().find('[data-is-tombstoned="true"]').hide(); }); って書いたけど An iframe which has both allow-scripts and allow-same-origin for its sandbox attribute can escape its sandboxing. って言われてダメだったよ・・・

cron で実行されたコマンドから出力されたメッセージをメールで送信する方法

本題に入る前に、まずは、sh/bash系のシェルで標準出力と標準エラー出力をリダイレクトする方法から。 現在使用中のシェルを確認するには、 # echo $SHELL とすれば確認できる。 その他、利用できるシェルを確認するには # cat /etc/shells とする。 ■リダイレクトについて commandコマンドが出力を伴うコマンドの場合、commandコマンドの出力をresult.txtへ出力するには # command > result.txt コマンドの実効結果を別のコマンドの入力値とする場合は、|(パイプ)でつなげる。 # command1 | command2 ■標準出力と標準エラー出力について ・標準出力 正常結果やコマンド実行途中に出力されるメッセージの出力先。 ・標準エラー出力 異常終了時のメッセージやエラーメッセージなど、ユーザーに気づいてほしいメッセージの出力先。 ■標準出力と標準エラー出力の両方をリダイレクトする 先のcommandコマンドのリダイレクト例のうち、result.txtへのリダイレクトは、標準出力をリダイレクトしている。そのため、標準エラー出力はリダイレクトされず、仮にcommandコマンドが標準エラー出力へメッセージを出力した場合は、result.txtではなくコンソールへ出力(表示)される。 標準出力と標準エラー出力の両方をリダイレクトして、result.txtへ出力するには、 # command > result.txt 2>&1 とする。 なお、上の例を省略なしで記述すると # command 1> result.txt 2>&1 となる。 この「1」「2」の番号について。 ・1:標準出力。通常はコンソール画面。 ・2:標準エラー出力。通常はコンソール画面。 となっている。 ちなみに、「0」は「標準入力」。通常はキーボードからの入力。 例:標準エラー出力を error.log へ出力する。標準出力はコンソールへ表示する。 # command 2> error.log 例:標準出力は result.log 、標準エラー出力は error.log へ...

cron で bash を使うまでのお話

おー、ほぼ一年ぶりの更新だ・・・ 普段、何気に設定していた cron なんですが、 「PATHは通っていないから、フルパス書いて」 「#!/bin/bash はお呪い」 っていう程度の認識しかなかった。 ので、一からお勉強。 まず、cron の シェル等を確認するには、cron実行ユーザーで [root@localhost ~]# crontab -e * * * * * printenv >/var/tmp/env.txt ってやって1分待つ。 で、1分後に出来上がったファイルの中身を見てみる [root@localhost ~]# cat /var/tmp/env.txt ... SHELL=/bin/sh USER=root PATH=/usr/bin:/bin PWD=/root LANG=ja_JP.UTF-8 SHLVL=1 HOME=/root LOGNAME=root XDG_RUNTIME_DIR=/run/user/0 ... あー、shだ。 どおりで、/bin/bash って書かないと、動かない記述があるわけだ。