javamail接收时邮件标题乱码解决方案

通过javamail接收邮件时,获取到Message后,通过Message#getSubject()获取邮件标题时出现中文乱码,如:[�求�� 5068761788:�I家已收到退款],这种情况只有在对方标题内容有繁体字,而且使用的编码是GB2312时就出现,把编码改为GBK后显示正常,这种情况是GB2312没有收录这部分繁体字符而无法显示导致的。

GB2312(1980年)共7445个字符,GBK(1995年)共21886个字符,GBK字符编码向上兼容GB2312,这部分无法显示的繁体字符在GBK收录的范围,因此GBK能正常显示。

查看Email的源码可以看到类似 Subject: =?GB2312?B?1tA=?= 的字符,其中第一个 ?GB2312?是指字符编码,第二个?B?,表示内容的编码方式,如果是B则表示Base64编码,如果是“Q”则代表 Quoted-Printable编码。

javamail在Message#getSubject()的方法中,通过MimeUtility#decodeText()对邮件消息的标题进行解码 ,通过MimeUtility#javaCharset(String charset)这个方法获取真正的字符集编码,代码如下:


public static String javaCharset(String charset) {
 if (mime2java == null || charset == null)
 // no mapping table, or charset parameter is null
 return charset;

String alias =
 (String)mime2java.get(charset.toLowerCase(Locale.ENGLISH));
 return alias == null ? charset : alias;
 }

可以看到最终会通过mime2java这个对象获取编码,mimi2java是一个Hashtable对象,在类加载的时候进行初始化,代码如下:


InputStream is =
 javax.mail.internet.MimeUtility.class.getResourceAsStream(
 "/META-INF/javamail.charset.map");

if (is != null) {
 try {
 is = new LineInputStream(is);

// Load the JDK-to-MIME charset mapping table
 loadMappings((LineInputStream)is, java2mime);

// Load the MIME-to-JDK charset mapping table
 loadMappings((LineInputStream)is, mime2java);

if (java2mime.isEmpty()) {

...

}

if (mime2java.isEmpty()) {

mime2java.put("iso-2022-cn", "ISO2022CN");

......

}

程序会先在”/META-INF/javamail.charset.map”这个文件中加载字符的映射关系,如果没有则添加默认值。到这里已经找到问题的解决办法了。

在项目下添加”/META-INF/javamail.charset.map”这个文件,文件内容为默认的映射关系+GB2312->GBK的映射关系,让程序通过GBK去解码全部GB2312的内容:


---------mimi2java(required)--------------
iso-2022-cn ISO2022CN
iso-2022-kr ISO2022KR
utf-8 UTF8
utf8 UTF8
ja_jp.iso2022-7 ISO2022JP
ja_jp.eucjp EUCJIS
euc-kr KSC5601
euckr KSC5601
us-ascii ISO-8859-1
x-us-ascii ISO-8859-1
gb2312 GBK

ps:这里第一行带有“——“的内容必须有,否则系统会把这些内容赋值给java2mime对象,而不对赋值给mime2java对象,程序是通过”–”标识或者空行来分割的.

每行内容必须用一个tab分开,因为javamail是通过”\t”来分割key和value的.源代码如下:


while (true) {

... ...

if (currLine == null) // end of file, stop
 break;
 if (currLine.startsWith("--") && currLine.endsWith("--"))
 // end of this table
 break;

... ...

StringTokenizer tk = new StringTokenizer(currLine, " \t");

... ...

}

javamail接收时邮件标题乱码解决方案》上有 2 条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注