让javamail 可以处理 unicode-1-1-utf-7 编码的Email

    客户总是报告某些email 在outlook中可以正常显示,而在我用javamail编写的客户端却显示正文一片空白。看看日志报告的是 UnsupportedEncodingException 。我让客户把 email 原件从outlook 中下载下来发给我,打开一看,发现标题和正文使用的编码是 unicode-1-1-utf-7。
    自从使用utf-8,很久没有遇到乱码的问题了。unicode-1-1-utf-7这个编码真是头一次看到。到google 上一搜,还真有不少人使用 javamail 遇到这个问题。不想这竟是 java 的 bug,参见 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4304013 。难以理解为什么 java 一直到1.4.2还不支持UTF-7编码(j2sdk1.5 不知道搞定没有)。
    看看RFC 和一些网上资料,基本了解了UTF-7,摘录一段如下:

UTF-7:A Mail-Safe Transformation Format of Unicode(RFC1642)。这是一种使用 7 位 ASCII 码对 Unicode 码进行转换的编码。它的设计目的仍然是为了在只能传递 7 为编码的邮件网关中传递信息。 UTF-7 对英语字母、数字和常见符号直接显示,而对其他符号用修正的 Base64 编码。符号 + 和 - 号控制编码过程的开始和暂停。所以乱码中如果夹有英文单词,并且相伴有 + 号和 - 号,这就有可能是 UTF-7 编码。

    客户自然不能接受程序平台bug这样的借口,所以重要的是如何搞定这个编码。google 又是一阵狂搜,老实说没有google,我不知道我是否仍然可以继续程序员这份很有前途的工作。但话有说回来,google也让我产生了惰性,遇到不明白的例外的时候基本就不再自己思考了。网上提问题的人多,解决问题的人少,好不容易发现有人提供了解决的办法,不曾想竟是个日本人。
    我是仇日的,除了三年前一个 Olympus 的数码相机,我一直严于律己,不染日货。但我还是对这个叫做 木下信 的日本人心生敬意。他写了整整一本书来共享其使用 javamail 的经验,《JavaMail完全解说》。其中一篇专门介绍了如何处理 UTF-7编码并提供源码下载。参见:http://www.sk-jp.com/cgi-bin/treebbs.cgi?kako=1&all=1220&s=1220,涉及的source可以从 http://www.sk-jp.com/software 下载。
    
    结合日本人的解法,我的部分处理代码如下:

    private static String decodeStream(InputStream in, String charset) throws IOException {
        //System.out.println(IOUtils.toString(in));
        if (isUTF7(charset)) {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int c;

            while ((c = in.read()) != -1) {
                out.write(c);
            }
            byte[] bytes = out.toByteArray();

            try {
                ByteToCharUTF7 btc = new ByteToCharUTF7();
                char[] chars = new char[bytes.length / 2 + 1];
                btc.convert(bytes, 0, bytes.length, chars, 0, chars.length);
                return new String(chars);
            } catch (Exception e) {
                log.warn("Error occurred while parse stream with charset " + charset
                        + ". Cause by: " + e.getMessage());
                //可能会抛出sun.io.ConversionBufferFullException, 那么直接用默认编码解码
                return new String(bytes, "ISO8859-1");
            }

        } else {
            return IOUtils.toString(in, charset);
        }
    }

    private static boolean isUTF7(String charset) {
        return "UTF-7".equalsIgnoreCase(charset) || "unicode-1-1-utf-7".equalsIgnoreCase(charset);
    }

    完全按照日本人的解法,时常会抛出sun.io.ConversionBufferFullException。问题可能出在它默认假定字符串一定包含有UTF7编码的内容,如果字符串只包含ASCII,那么就抛出了例外(UTF-7 对英语字母、数字和常见符号直接显示,而对其他符号用修正的 Base64 编码,见上UTF7的说明)。所以如果 catch 了例外,就直接用ISO8859-1编码处理。

    希望java赶紧支持utf-7。我对unicode一直是一知半解,觉得编码这玩意挺复杂。主要是看到代码中遍布 >>、<< 这样的位操作符就心生怯意。到底不是科班出身啊。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值