- blogs:
- cles::blog

RubyのNKFのバグでSubjectのエンコードができなくて困った



結論から書くと、CentOS 5.3のyumで入るRubyにはNKFにバグがあって(というか、オリジナルのnkfのバグの影響で)、UTF-8のMIMEエンコードがうまく出来ない。このバグはあくまで入力がUTF-8の場合のみに起きる現象なので、文字列を一旦別の文字列(EUC-JP,SJIS,JIS)に変換してからエンコードすることで回避できます。
例えば、こんな感じ。
このバグから抜け出すのに半日くらいかかってしまいました。
† 事の発端
NKFを使ってSubjectをMIMEエンコードしてメール送信するスクリプトを書いたら、なぜかSubjectの後半が文字化けする(というか、MIMEエンコードがきちんと終端されていない)という現象が発生。最初はメーラー依存の問題かと思っていたんですが、ログを確認すると送信時からどうもMIMEエンコードが壊れてるっぽい。
再現コードとしてはこんな感じ。Rubyのバージョンは1.8.5です。
ここで、長いSubjectが勝手に複数の行に分割されているのはRFC2822の2.1.1 行の長さの制限に準拠するためなので、これを勝手にやってくれること自体はNKFの動作としては特に問題ありません。メーラーはこの分割されたSubjectをデコードして自動的につなぎあわせてくれるようになっています。が、よく見るとなぜか最後の行の行末にMIME Bエンコーディングで当然ついているべきの"?="がなく、ちょっとおしりが切れているようにも見えます。
† どうやら元々のnkfのバグらしい。。。。
エンコードする文字列が短かかったりすると大丈夫なので、どう考えてもRubyもしくはnkfのバグのようなので、nkfの2.0.8以降のリリースノートをさらってみると、それらしきバグがnkf 2.0.8で修正されていることを発見。
nkf 2.0.8 released - はてなるせだいあり
* UTF-32, CP10001 (Microsoft's MacJapanese) のサポート。
* Unicode の BMP 外をサポート。
* CP932 系のユーザ定義文字をサポート。
* NTT DoCoMo と Softbank Mobile の Shift_JIS 絵文字の範囲をサポート。
* --guess にて改行コードを表示するようにした。
* --guess にて、文字コードを確定できなかった場合の推測が壊れていたのを修正。
* EUC モード時に SI/SO/ESC を捨てていたのを修正。
* UTF-8 の入力を MIME エンコードすると正しく出力されないのを修正。
* 複数ファイルを与えられた時、読めないファイルがあっても処理を続行するようにした。
* CP932 周りの各種修正
とりあえず、これだけのためにRubyやライブラリを入れ替えていられないのでなんとか抜け道を探します。このリリースノートを素直に読めば、入力がUTF-8でなければ良いように読めるので、今回の場合はどうせ最終的にはJIS(iso-2022-jp)にしてしまうので、JISに変換してからMIMEエンコードをかけるようにしてみたところ、うまく変換できるようになりました。
久々にこの手のバグでだいぶ時間をとられてしまいました。
このRubyはCentOSのデフォルトだから意外と困っている人多いんじゃないかなぁ。。。。
† 参考: [RFC2822] 2.1.1. Line Length Limits
http://www.puni.net/~mimori/rfc/rfc2822.txt
2.1.1. Line Length Limits
There are two limits that this standard places on the number of characters in a line. Each line of characters MUST be no more than 998 characters, and SHOULD be no more than 78 characters, excluding the CRLF.
行の長さの制限
この標準では1行中の文字数に2つの制限がある。それぞれの行の文字はCRLFを除いて、決して998文字以下でなければならず(MUST)、78文字以下であるべきである(SHOULD)。
このエントリへのTrackbackにはこのURLが必要です→https://blog.cles.jp/item/3275
古いエントリについてはコメント制御しているため、即時に反映されないことがあります。
コメントは承認後の表示となります。
OpenIDでログインすると、即時に公開されます。
OpenID を使ってログインすることができます。
2 . 福岡銀がデマの投稿者への刑事告訴を検討中(110777)
3 . 年次の人間ドックへ(110372)
4 . 2023 年分の確定申告完了!(1つめ)(109918)
5 . 三菱鉛筆がラミーを買収(109818)