Java でメールを送信する場合、JavaMail を使用するのがほとんどだと思います。
最近、JavaMail で送信したメール、Gmail で添付ファイルのファイル名を復元できないという問題が発生するようになりました。
添付ファイルのファイル名は、基本的には Content-Disposition ヘッダの filename パラメータで指定されます。メーラによっては、Content-Type ヘッダの name パラメータを見る場合もあるようで、javamail はどちらにもファイル名を埋め込むようです。
ただこの埋め込み方の部分について、JavaMail 1.5.3 で修正が入ったようです。
パラメータの値が長い場合、RFC 2231 に従って、分割するようになりました。
簡単なプログラムで確認してみます。1つ目は「数字のみ 70 文字」、2つ目は「ひらがなのみ 30 文字」です。
import javax.mail.internet.ContentDisposition;
import javax.mail.internet.MimeUtility;
public class ContentDispositionTest {
public static void main(String args[]) throws Exception {
ContentDisposition cd = new ContentDisposition("attachment");
cd.setParameter("filename",
"1234567890123456789012345678901234567890123456789012345678901234567890");
System.out.println(cd.toString());
cd.setParameter("filename",
MimeUtility
.encodeText("あいうえおかきくけこさしすせそ", "UTF-8", "B"));
System.out.println(cd.toString());
}
}
JavaMail 1.5.2 と 1.5.3 の結果は以下の通りです。
attachment;
filename=1234567890123456789012345678901234567890123456789012345678901234567890
attachment;
filename="=?UTF-8?B?44GC44GE44GG44GI44GK44GL44GN44GP44GR44GT44GV44GX44GZ44Gb44Gd?="
attachment;
filename*0=123456789012345678901234567890123456789012345678901234567890;
filename*1=1234567890
attachment;
filename*0="=?UTF-8?B?44GC44GE44GG44GI44GK44GL44GN44GP44GR44GT44GV44GX44";
filename*1="GZ44Gb44Gd?="
Gmail では、1つ目は正しいファイル名に復元できますが、2つ目は復元できないことが解っています。(2017-11-21 時点)
Gmail の「メッセージのソースを表示」する機能で Content-Disposition ヘッダを見ると、2つ目はパラメータの値が元の形に連結されていないと解ります。
Content-Disposition: attachment; filename="=?UTF-8?B?44GC44GE44GG44GI44GK44GL44GN44GP44GR44GT44GV44GX44\"; filename*1=\"GZ44Gb44Gd?="
JavaMail のこの動きが、MIME の仕様として正しいのかどうか、解っていません。(解る方、教えていただけると幸いです)
1.5.3 だけでなく、現在の最新版 1.6.0 でも同様の動きになることが解っています。
なお、mail.mime.splitlongparameters システムプロパティの値を false にすることで、1.5.2 までの動きと同じになります。
attachment;
filename=1234567890123456789012345678901234567890123456789012345678901234567890
attachment;
filename="=?UTF-8?B?44GC44GE44GG44GI44GK44GL44GN44GP44GR44GT44GV44GX44GZ44Gb44Gd?="
追加 (2017-11-30)
ContentDisposition#setParameter() に、MIME エンコードした文字列を渡すやり方が悪いと解りました。どうするべきか、後日まとめます。