職業プログラマの休日出勤

職業プログラマによる日曜自宅プログラミングや思考実験の成果たち。リアル休日出勤が発生すると更新が滞りがちになる。記事の内容は個人の意見であり、所属している(いた)組織の意見ではない。

quoted-printable

基本的にASCII文字(英数+ちょっとした記号)しか取り扱うことのできない電子メールにおいては、それ以外の文字をASCII文字へ置き換える(=エンコードする)必要がある。
世の中にはいくつかのエンコード方式が存在するが、 quoted-printable は、英語以外の西欧の言語をメール上で表現するために設計された(と聞いている)。「西欧の言語」がどのような特徴を持つかと言うと、多くはアルファベットで構成されるが、時々、ASCII文字ではない文字が出てくるのである。ドイツ語のウムラウトは代表的な例であろう(ドイツは西欧なのか否かという議論はここではしない)。こういった言語で書かれた文章をエンコードする際は「特殊文字のみエンコードする」という方式だと効率が良い。これが quoted-printable の狙いである。

…と長い前置きになってしまったが、何だか、quoted-printable に関する検索によりこのブログに辿り着く方が多く居られるようなので、quoted-printableについて少し深く掘り下げてみる。
需要があるのはこういった仕様の解説ではなくて実装例であるというのは理解しつつも、敢て、仕様の面から触れていきたい。実装例は、また次回以降に。
なお、誤訳や誤解等があったとしても筆者は責任を負わないので、この記事を参考にして実装など行う場合は原文を必ず読み、十分に吟味して頂きたい。

■quoted-printable その仕様

仕様は、RFC 2045 "Internet Message Bodies" の第6章 "Content-Transfer-Encoding Header Field" の第7節 "Quoted-Printable Content-Transfer-Encoding" にて定義されている。(19ページから23ページまで)

参考:http://www.ietf.org/rfc/rfc2045.txt

全文の日本語訳なんて情報処理系の大学生向けの宿題やら何やらで、そこら中に転がってると思われるので、以下、プログラムの実装に必要な要素を抽出し、紹介していく。

■データの表記方法(原文:octets are to be represented as determined by the following rules:)


  • 改行やデータの区切りを示すCRやLFといった文字以外は、「=」とそれに続く2桁の16進数にて表現する。16進数の英字部分は大文字でなければならない。

  • (文字表現)ASCII文字の中でも、33(0x21)番以上60(0x3C)番以下と、62(0x3E)番以上126(0x7E)番以下の文字は、エンコードしなくても良い。

  • (空白)水平タブと半角空白文字はエンコードしなくても良い。※9(0x9)番と32(0x20)番
    但し、行末ではエンコードしなければならない。後述の「無意味な改行」の前ではエンコードしなくても良い。

  • (改行)改行にはCRLFを用いること。なお、文字データ以外ではCRやLFをエンコードすることもある。

  • (無意味な改行)エンコードされた文字列は、1行は76文字以下である必要がある(改行文字を除く)。それよりも長い行を表現する時は「無意味な」改行を入れなければならない。行末の「=」文字は、その改行が「無意味」であることを示す。(原文では(3)に書いてある内容:)この行末の「=」文字の後には(エンコードされていない)タブや空白文字が続いても良い。

■注意書き(原文の21ページ)


  • ハイフン「-」はエンコードする必要が無いので、multi-part MIME を作る時の boundary と衝突しないように気をつけること。boundary文字列を選定する際には、「=_」のように quoted-printable では絶対に出て来ない文字列を使うと良いだろう。multipart MIME の詳細は RFC2046 へ。
  • エンコードしたデータが、EBCDICなシステムを経由して受け渡される際は、以下の文字もエンコードしておくと良い ⇒ !"#$@[\]^`{|}~

  • 改行文字がCRLFに強制されるなど、quoted-printable エンコードの際にはデータに手を入れることがある。もしデータに厳密さが必要なら base64 を検討すること。

  • (原文の23ページ)バイナリデータをエンコードする際は、途中で出てくるCR(0x0D)やLF(0x0A)に気をつけること。CRとLFが連続して出てくる場合は、エンコードすべきである。さもなくば、CRLFを「意味のある」改行として出力すると、受け手のシステムによっては違う改行コードに置き換えられてしまうのである。

■より強固な実装にするために 〜 もしもデコードの際に、不正な表現に出くわしたら??(原文の22ページ)


  • 「=」の後の16進数として英小文字を使っているのは不正である。これらを英大文字として解釈しても良い。

  • 「=」の後に16進数やCRLF改行 以外の文字を使っているのは不正である。これらはデコードせずにそのまま出力するのが筋だろう。もし可能であれば、ユーザに警告を示すと良い。

  • 「=」文字が、最後の文字、または最後から2番目の文字であるのは不正である。(2)と同様に取り扱うのが良い。

  • 水平タブやCRLF 以外の制御文字は不正である。126番(0x7E)より大きいコードの文字も同様である。これらは無視して出力した上で、ユーザに警告を示すと良い。

  • 1行が76文字を超えるのは不正であるが、それにも関わらず長い行があれば、デコードした上で、ユーザに警告を示すと良い。

■形式主義者へ

原文の23ページには、quoted-printable をBNFで表したものが載っているので参考にすること。