JavaMail是JavaEE中13种核心技术之一,其中有不少涉及国际化的知识点,例如subject, body, attachment时间日期等。本文我们来关注邮件附件乱码问题,首先看一个真实的bug,测试步骤如下。
1. 创建一个mail notification,附件名为中文
2. 触发notification条件,发送mail并检查
结果如图所示。
一探究竟,最终我们在notification代码中找到了addAttachment方法。
public void addAttachment(NotificationAttachment attachment) {
Assert.notNull(attachment, "Attachment was null");
try {
String fileName = attachment.getFileName();
if (StringUtil.isNullOrEmpty(fileName)) {
fileName = DEFAULT_FILE_NAME + multipart.getCount();
}
}
...
}
读到这里,其实我们已经破解了该问题,只要调用MimeUtility.encodeText方法对fileName进行编码即可,修改如下。
public void addAttachment(NotificationAttachment attachment) {
Assert.notNull(attachment, "Attachment was null");
try {
String fileName = attachment.getFileName();
if (StringUtil.isNullOrEmpty(fileName)) {
fileName = DEFAULT_FILE_NAME + multipart.getCount();
}
fileName = MimeUtility.encodeText(fileName);
}
...
}
问题解决!不过关于MimeUtility工具类,这里仍需多说几句。该类包含一组根据RFC2047规范来对MIME头进行编码和解码的方法。但一般情况下,使用setSubject和setRecipients方法时候,编解码方法是无需使用的,JavaMail会自动进行编码和解码。这些方法只有在使用setHeader及getHeader方法操作MIME头时才需要被调用。
RFC 822规定邮件头只能包含ASCII字符,含有non ASCII字符的邮件头必须进行编码。所以使用Java Mail发送非英文邮件时必须经过编码,否则别人看到的邮件只能是一堆乱码。通常对邮件头的编码方式有两种,一种是base64方式编码,一种是qp(quoted-printable)方式编码,JavaMail会根据具体情况来选择相应的编码方式。