GNU-JavaMailでメールを送ると件名が文字化けする

メール送信機能をJavaで実装したところ、なぜか件名が文字化けするという問題にぶち当たりました。
しかも、不思議なことにWindowsからだと大丈夫なのに、Linuxからだと化ける・・・。


最初は文字コード指定を間違えたと思っていろいろ確認したんですが、特に問題なし。

message.setSubject("メール送信テスト","ISO-2022-JP"); 

いろいろ調べてわかったこと。

原因は、RedHat LinuxにインストールされているJavaMailでした。
てっきり JavaMail って Sun がリリースしている奴が使われていると思っていたんですが、RedHat に標準で入っているのは GNU ライセンスによる互換実装のもの(classpathx-javamail)でした。


Sun の JavaMail -> Oracle Technology Network for Java Developers | Oracle Technology Network | Oracle
GNU の JavaMail -> GNU JavaMail - GNU Project - Free Software Foundation (FSF)


そして、このGNU版のソースを確認したところ、こんな処理が入ってました。

private static String encodeWord(String text, String charset,
                                 String encoding, boolean word)
    throws UnsupportedEncodingException{
    if (asciiStatus(text.getBytes()) == ALL_ASCII){
        return text;
    }

(この処理は、javax/mail/internet/MimeUtility.javaの391〜398行目)


すべての文字が ASCII ならば、エンコードせずにそのままの値を返しています。
しかし、Linux 上のデフォルトエンコードは「ISO-8859-1(ラテンアルファベット)」なので、このように引数なしで getBytes をすると、日本語が解釈不明で「?」に化けてしまい、常にエンコードされません。

つまり、完全に GNU-JavaMail のバグが原因でした
しかも、このメソッドは private なので回避不能・・・。


どうしよう・・・

/var/lib/Tomcat5/common/lib/[javamail].jar を入れ替えれば問題は解決しますが・・・。
運用の方から、「いじってもいいけど rpm パッケージ単位で」と言われてしまいました。


作戦1:Sun 公式の JavaMail に置き換える

 というわけで、さっそく rpm を入れ替えようとしましたが、すでに入っている GNU-JavaMail は Tomcat などに依存関係があるため消せない。
 しかも、JavaMail の rpm はあるけど*1、一緒に必要な JavaBeans Activation Framework(JAF) が見つからない*2

作戦2:WARファイルの /WEB-INF/lib に Sun 公式の mail.jar を入れる

 消すのをあきらめて、優先順位の高いクラスパスに直接 jar を入れてみる*3
 ところが、これだと NoClassDefFoundError。
 どうやら、JavaMail の jar が tomcat5/common/lib と /WEB-INF/lib の両方にあると、両方とも認識しないらしい。

作戦3:デフォルトエンコーディングを変える

 「-Dfile.encoding=UTF-8」を設定する。
 これで直るんですが、アプリケーション全体に影響を与えてしまうので却下。
 (問題がないように作って入るハズですが、今回のようにライブラリまで動作が変わらないかどうか保証できないため)


他にも試したものの、ことごとく失敗。
商用でなければ無茶もできるんですが・・・。
(たとえば、/var/lib/Tomcat5/common/lib/[javamail].jar を直接消せば、作戦2で動く)


結局・・・

1週間粘って解決のめど立たず(−−;)
なにかいい方法をご存知の方、ぜひ教えてください・・・

*1:fedoraリポジトリにあった

*2:Java6には標準で入っているから? でも、Red HatにはGNUJAFが入ってしまっているので、Sun-JavaMailを使うならSun-JAFがないと、組み合わせがまずそう…

*3:Servlet の仕様で、Webアプリケーションごとのライブラリ(/WEB-INF/lib 配下)が優先されるようになっている。ただし、今回の JavaMail のように javax.* のパッケージの場合は common が優先されるから、意味ない・・・。 参考:http://www.jajakarta.org/tomcat/tomcat5.0/ja/docs/tomcat-docs/class-loader-howto.html