JavaMailでヘッダをエンコードする際の注意点

# 環境
 | バージョン
---|---
Java | 8
JavaMail | 1.5.5

# ヘッダが長いメールをMimeUtility#encodeText(String)する際の注意点

　JavaMailのMimeUtility#encodeText(String)を利用する際、Base64エンコード後の文字列が76文字以上になる場合、自動的に複数の文字列に分割されます。ここまではよいのですが、文字列の接続子が、標準では「半角空白」になります。

#### 1.サンプルコード
```java:FoldTest.java
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設定版)

```java:FoldTest.java
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といったそれらしいメソッドがあるので、他にスマートなやり方があるかもしれませんが、備忘も兼ねて。


# 参考
２行に渡るメールヘッダの正しい処理 http://adiary.blog.abk.nu/0213
RFC2822和訳(2.2 Header Fields) http://www.t-net.ne.jp/~cyfis/rfc/mail/rfc2822_ja-1.html