问题:
用JavaMail 发邮件,带上附件,附件名有时乱码,有时非乱码。查看Java端代码:
最终生成的邮件附件名称为:
=UTF-8Q=E6=97=A0=E5=BF=A7Hour=E6=8A=A5=E8=A1=A8=E7=BB=9F=E8=AE=A1.xlsx=
根据网上部分百度结果修改:
在设置邮件附件的时候调用javax.mail.internet.MimeUtility 来编码,代码修改如下:
DataSource source = new FileDataSource(filePath);
bodyPart = new MimeBodyPart();
bodyPart.setDataHandler(new DataHandler(source));
bodyPart.setFileName(MimeUtility.encodeText(fileName));
multiPart.addBodyPart(bodyPart);
生成的邮件附件名称为:
=UTF-8Q=E6=97=A0=E5=BF=A7Hour=E6=8A=A5= =UTF-8Q=E8=A1=A8=E7=BB=9F=E8=AE=A1=2Exlsx=
仍旧没有解决乱码问题。
来看邮件源码:
Content-Type: application/octet-stream;
name*0="=?utf-8?B?5rWL6K+V5qCH6aKYLS0tMDAx5oiR6KaB5LiK?==?utf-8?B?5";
name*1="a2mQUJDREXvvIzlkKzor7TopoHotrPlpJ/plb8=?=.xlsx"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename*0="?utf-8?B?5rWL6K+V5qCH6aKYLS0tMDAx5oiR6KaB5LiK?==?utf-8?B?5";
filename*1="a2mQUJDREXvvIzlkKzor7TopoHotrPlpJ/plb8=?=.xlsx"
这串就是 有些系统乱码有些系统 正常显示的 邮件源码。。
对比在邮件客户端上的非乱码邮件:
Content-Type: application/octet-stream; name="=?utf-8?B?5rWL6K+V?=.xlsx"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="=?utf-8?B?5rWL6K+V?=.xlsx"
filename*0,filename*1 和 filename 的区别,猜测也许就是邮件客户端不支持这种filename*0,filename*1 协议导致的问题。
分析
有了以上的想法,就开始来看源码。
MimeBodyPart 这个类中的 setFileName 方法 用到一个 ParameterList 在ParameterList 的 toString 类中找到下面一段:
if (v instanceof MultiValue) {
// ....
ns = name + i + "*";
//...
}
} else if (v instanceof Value) {
/// ...
} else {
if (value.length() > 60 &&
splitLongParameters && encodeParameters) {
int seg = 0;
name += "*";
/// ....
}
这个类在邮件附件属于 MultiValue 会把 名字用name + i 隔开 ,在名字大于 60个字符的时候也会主动截断,这也就是 javamail 中 附件的命名规则,名字太长会被截断~~!
中文在base64 加密后,超过60个字符那是妥妥的有可能。这种截断文件名的模式在某些客户端,并不能很好的支持。
解决
解决就很容易了, 代码里有 splitLongParameters 这个参数, 观察了下 对应于一个环境变量,如果想不截断文件名,只要在程序运行之初加上:
System.setProperty("mail.mime.splitlongparameters","false");
正常生产的附件名称为:
无忧Hour报表统计.xlsx
至此乱码问题解决