我面对着一份邮件原文发出以上的感慨,客户抱怨该邮件收到的时候在系统中正文显示是乱码而标题正常。 这是一份典型的不合规范的邮件: Content-Type : text/plain ,没有说明 charset,而接下来的正文直接就是未进行任何编码的中文文字。不过 Subject 却是符合规范的(=?gb2312?B?xxxxxxx?=)。
行行色色的不合规范的邮件见过不少,最常见的就是某些header未编码,还有的可能就是,Body编码了而Subject 未编码,最讨厌的就是整份Email都没有编码信息。
恨归恨,问题还是得解决,我修改了代码,处理逻辑如下:
1. 在最开始解析邮件的时候,先解析某些可能带有编码信息的header,并记录为 headerCharset;部分代码如下:
|
private static Pattern encodeStringPattern =
Pattern.compile("=\\?(.+)\\?(B|Q)\\?(.+)\\?=", Pattern.CASE_INSENSITIVE
| Pattern.DOTALL); private final String[] CHARTSET_HEADER = new String[] { "Subject", "From", "To", "Cc", "Delivered-To" }; .......... Enumeration enum = message.getMatchingHeaderLines(CHARTSET_HEADER); while (enum.hasMoreElements()) { String header = (String) enum.nextElement(); Matcher m = encodeStringPattern.matcher(header); if (m.find()) { this.headCharset = m.group(1); log.debug("guess mail charset is " + this.headCharset); break; } } .......... |
2.
接着解析邮件体,找到 Body 的时候,看看是否指明 charset 信息;如果指定了,记录为 bodyCharset;如果没有,使用
headerCharset,如果 headerCharset 也是 null,使用默认charset。通常是
ISO-8859-1,但通常我们收到的很多不符合规范的邮件都是简体或者繁体中文的,所以设置默认charset 为 GBK比较保险。
3. 最后再处理邮件 header,如果没有charset 信息,使用 bodyCharset,否则使用默认charset。
以
上的解决方案,只要邮件的Body或者Header中的一个提供了编码信息,那么都可能可以避免乱码的产生,如果哪份遭千杀的邮件,Body 用
gb2312
编码,Subject 却是未编码的日文,那我只能长叹被击败了。如果整份邮件都没有编码信息的话,除非你确定邮件都是指定的编码并进行转码,否则只有听
天由命。
在寻求解决方案的过程中,参考了JCharDet 项目,一个猜测字符串编码集的程序包,具体参见竹笋炒肉的blog。不过在实际操作中,猜测结果并不准确,繁体字总被猜作UTF-16。
最后呼吁一声,请遵循规范!

