環境
| バージョン
---|---
Java | 8
JavaMail | 1.5.5
ヘッダが長いメールをMimeUtility#encodeText(String)する際の注意点
JavaMailのMimeUtility#encodeText(String)を利用する際、Base64エンコード後の文字列が76文字以上になる場合、自動的に複数の文字列に分割されます。ここまではよいのですが、文字列の接続子が、標準では「半角空白」になります。
1.サンプルコード
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Properties;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Message.RecipientType;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
public class FoldTest {
public static void main(String[] args) throws MessagingException, IOException {
// smtp設定(設定値は適当)
Properties props = new Properties();
props.setProperty("mail.smtp.host", "smtp.example.com");
props.setProperty("mail.smtp.port", "587");
props.setProperty("mail.smtp.connectiontimeout", "5000");
props.setProperty("mail.smtp.timeout", "5000");
props.setProperty("mail.mime.address.strict", "false");
// メールオブジェクトを作る
final Session session = Session.getInstance(props);
MimeMessage message = new MimeMessage(session);
// Header-Fromに注目!!
final String from = MimeUtility.encodeText("とてもすごーいフレンズ <from@example.com>", "iso-2022-jp", "B");
message.setHeader("From", from);
// Header-To
final String to = MimeUtility.encodeText("<to@test.sample.co.jp>", "iso-2022-jp", "B");
message.setRecipients(RecipientType.TO, to);
// Subject
message.setSubject("件名欄");
// 本文
message.setText("Hello World.");
// メールオブジェクトから文字列へ
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
message.writeTo(baos);
System.out.println(baos.toString("utf-8"));
}
}
}
1.の出力
From: =?iso-2022-jp?B?GyRCJEgkRiRiJDkkNCE8JCQlVSVsJXMlOhsoQiA8ZnI=?= =?iso-2022-jp?B?b21AZXhhbXBsZS5jb20+?=
To: to@test.sample.co.jp
Message-ID: <2052001577.0.1490015862605@..........>
Subject: =?UTF-8?B?5Lu25ZCN5qyE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Hello World.
この接続子を、「改行(CRLF) + 半角空白」にしたい場合、MimeUtility#encodeText(String)を使用する前に、以下の設定が必要になるようです。
System.setProperty("mail.mime.foldencodedwords", "true");
2.サンプルコード(foldencodewords設定版)
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Properties;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Message.RecipientType;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
public class FoldTest {
public static void main(String[] args) throws MessagingException, IOException {
// trueの場合、長いヘッダー行は改行され、半角空白が付加される
System.setProperty("mail.mime.foldencodedwords", "true");
//---------- 以下は 1.と同様 ----------
// smtp設定(設定値は適当)
Properties props = new Properties();
props.setProperty("mail.smtp.host", "smtp.example.com");
props.setProperty("mail.smtp.port", "587");
props.setProperty("mail.smtp.connectiontimeout", "5000");
props.setProperty("mail.smtp.timeout", "5000");
props.setProperty("mail.mime.address.strict", "false");
// メールオブジェクトを作る
final Session session = Session.getInstance(props);
MimeMessage message = new MimeMessage(session);
// Header-Fromに注目!!
final String from = MimeUtility.encodeText("とてもすごーいフレンズ <from@example.com>", "iso-2022-jp", "B");
message.setHeader("From", from);
// Header-To
final String to = MimeUtility.encodeText("<to@test.sample.co.jp>", "iso-2022-jp", "B");
message.setRecipients(RecipientType.TO, to);
// Subject
message.setSubject("件名欄");
// 本文
message.setText("Hello World.");
// メールオブジェクトから文字列へ
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
message.writeTo(baos);
System.out.println(baos.toString("utf-8"));
}
}
}
2.の出力(foldencodewords設定版)
From: =?iso-2022-jp?B?GyRCJEgkRiRiJDkkNCE8JCQlVSVsJXMlOhsoQiA8ZnI=?=
=?iso-2022-jp?B?b21AZXhhbXBsZS5jb20+?=
To: to@test.sample.co.jp
Message-ID: <2052001577.0.1490015590351@..........>
Subject: =?UTF-8?B?5Lu25ZCN5qyE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Hello World.
出力結果のHeader-From欄を比較して見ていただければわかりますが、特に設定のないサンプルコードの出力は、Header-From欄が1行として表示されています。対して、foldencodewords設定が__true__の場合、Header-From欄が__改行__され、2行目の先頭に__半角空白__が付加されています。
この理由は、「なんらかの目印がないと、この行がどのヘッダに属しているのがわからない」為と思われます。仕様としては、RFC2822の以下の記述にあるように
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.
「ヘッダ行は、できれば(SHOULD)78文字以下に収めるのが望ましい(改行抜きで)」としかないので、目印に__半角空白__ではなく__タブ文字__を利用する環境もあることを意識しておきましょう。単にメール送信するだけなら気にする問題ではありませんが、外部のメール処理プログラムと連携したり、自分でメール解析するような場合は注意が必要です。
MimeUtilityには、foldやunfoldといったそれらしいメソッドがあるので、他にスマートなやり方があるかもしれませんが、備忘も兼ねて。
参考
2行に渡るメールヘッダの正しい処理 http://adiary.blog.abk.nu/0213
RFC2822和訳(2.2 Header Fields) http://www.t-net.ne.jp/~cyfis/rfc/mail/rfc2822_ja-1.html