http://blog.csdn.net/fl_zxf/article/details/60126910
http://blog.csdn.net/wty19/article/details/50607411
0x00(测试条件)
附件名:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.txt
0x01(现象)
新浪邮箱解析出错:
QQ邮箱解析出错:
0x02(分析问题)
本地没问题,到 Linux 环境才出错。所以抓了本地的包和 Linux 下的包比较。
本地的包(之前用比较长的中文名测试抓的包):
------=_Part_18_1324418920.1488440125843
Content-Type: application/octet-stream;
name="=?UTF-8?Q?=E4=B8=AD=E6=96=87=E5=AD=97=E7=AC=A6201711=2Edocx?="
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename="=?UTF-8?Q?=E4=B8=AD=E6=96=87=E5=AD=97=E7=AC=A6201711=2Edocx?="
Linux 的包:
------=_Part_0_528597028.1488450122516
Content-Type: text/plain; charset=us-ascii;
name*0=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
name*1=a.txt
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename*0=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
filename*1=a.txt
可以看到问题是文件名太长被拆分了
0x03(查找根源)
看 Java 代码
String encodeName = MimeUtility.encodeWord(name); UrlResource inputStreamSource = new UrlResource(attach.getUrl()); helper.addAttachment(encodeName, inputStreamSource); // 自己的业务代码
addAttachment(attachmentFilename, inputStreamSource, contentType); // 跟进去
addAttachment(attachmentFilename, dataSource); // 跟进去
mimeBodyPart.setFileName(MimeUtility.encodeText(attachmentFilename)); // 跟进去
setFileName(this, filename); // 跟进去
part.setHeader("Content-Disposition", cd.toString()); // 跟进去
sb.append(list.toString(sb.length() + 21)); // 跟进去
if (value.length() > 60 && splitLongParameters && encodeParameters) { int seg = 0; name += "*"; // 省略...
已经看出是怎么回事了
0x04(解决)
在 Main方法下加
System.setProperty("mail.mime.splitlongparameters", "false"); // linux 会默认为 true,会截断附件名
0x05(PS)
这是 RFC2231 的规定,估计国内的还不支持(个人猜想)
0x06(走过的弯路)
之前没头绪。以为是 Linux 的限制;也怀疑过“MimeUtility.encodeWord(name)”的问题。
跟踪源码的时候看错了 jar 包,应该是 com.sun.mail:javax.mail:1.5.6,还不是 javax.mail:mail:1.4.5
------------ 记一个JavaMail 附件乱码的问题
String name = MimeUtility.encodeText(name, null) + ".xlsx";
messageBodyPart.setFileName(name);
貌似已经做过编码转换了。
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 协议导致的问题。
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 中 附件的命名规则,
名字太长会被截断~~!
System.setProperty("mail.mime.splitlongparameters","false");
就可以了。测试,解决。。。