Java中解析带有多部分/混合和多部分/替代正文的消息。

8
我收到了客户发送的电子邮件,他们在multipart/mixed消息中嵌套了一个multipart/alternative消息。当我获取消息正文时,它只返回multipart/alternative级别的内容,但实际上我想要的是包含在multipart/alternative中的text/html部分。
我查阅了javax.mail的javadocs,但找不到一种简单的方法来获取一个bodypart的内容,特别是它本身就是一个multipart或跳过第一个multipart/mixed部分并进入multipart/alternative体以读取text/html和text/plain部分。
该电子邮件的结构如下:
...
Content-Type: multipart/mixed; 
    boundary="----=_Part_19487_1145362154.1418138792683"

------=_Part_19487_1145362154.1418138792683
Content-Type: multipart/alternative; 
    boundary="----=_Part_19486_1391901275.1418138792683"

------=_Part_19486_1391901275.1418138792683
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset=ISO-8859-1

...

------=_Part_19486_1391901275.1418138792683
Content-Transfer-Encoding: 7bit
Content-Type: text/html; charset=ISO-8859-1

...

------=_Part_19486_1391901275.1418138792683--

------=_Part_19487_1145362154.1418138792683--

这是解析电子邮件所用代码的大纲:
Message [] found = fldr.search(searchCondition);           
for (int i = 0; i < found.length; i++) {
    Message m = found[i];
    Object o = m.getContent();
    if (o instanceof Multipart) {
        log.info("**This is a Multipart Message.  ");
        Multipart mp = (Multipart)o;
        log.info("The Multipart message has " + mp.getCount() + " parts.");
        for (int j = 0; j < mp.getCount(); j++) {
            BodyPart b = mp.getBodyPart(j);

            // Loop if the content type is multipart then get the content that is in that part,
            // make it the new container and restart the loop in that part of the message.
            if (b.getContentType().contains("multipart")) {
                mp = (Multipart)b.getContent();
                j = 0;
                continue;
            }

            log.info("This content type is " + b.getContentType());

            if(!b.getContentType().contains("text/html")) {
                continue;
            }

            Object o2 = b.getContent();
            if (o2 instanceof String) {
                <do things with content here>
            }
        }
    }
}

看起来它停留在第二个边界,无法解析更多内容。对于上述消息,它会在boundary="----=_Part_19486_1391901275.1418138792683"处停止,从未到达消息正文。


1
log.info("This content type is " + b.getContentType()); 这段代码会输出什么? - ToYonos
1
这个内容类型是multipart/alternative;当它工作时,它会显示“这个内容类型是text/html; charset=ISO-8859-1”。 - NGittlen
1
每次,对于每个循环转? - ToYonos
1
这是一个多部分消息。 该多部分消息有1个部分。 此内容类型为multipart/alternative; boundary="----=_Part_19486_1391901275.1418138792683" 退出循环并尝试解析找到的数组中的下一条消息。 - NGittlen
2个回答

3
在这个区块中:
if (b.getContentType().contains("multipart"))
{
    mp = (Multipart)b.getContent();
    j = 0;
    continue;
}

您将j设置为0并要求循环继续,希望它将从零开始重新启动。但是增量操作j++将在之前执行,导致您的循环从1开始而不是从0开始。
请将j设置为-1以解决您的问题。
if (b.getContentType().contains("multipart"))
{
    mp = (Multipart)b.getContent();
    j = -1;
    continue;
}

1
@Psycho_Penguin:这有帮助到你吗? - ToYonos
抱歉,我过去几天一直在度假。目前它在测试环境中运行正常,但在生产环境中却不行。 - NGittlen
奇怪。之前在两个环境中都失败了? - ToYonos
无法确定,测试邮件之前略有不同,但始终能够通过。最终使用相同的邮件进行测试,但在生产环境中仍然无法正常工作。正在努力找出原因。 - NGittlen
是的,正在努力弄清楚差异是什么。 - NGittlen
显示剩余2条评论

1
我已经测试了你的代码,但是对我来说也失败了。
在我的情况下,b.getContentType() 返回所有大写字母(例如 "TEXT/HTML; charset=UTF-8")。因此,我将其转换为小写后就可以正常工作了。
String contentType=b.getContentType().toLowerCase(Locale.ENGLISH);

if(!contentType.contains("text/html")) {
   continue;
}

1
为什么我将内容类型打印到日志中时,它总是小写? - NGittlen
1
如果是小写字母,那没问题。我认为这与你使用的电子邮件客户端库有关。一些电子邮件客户端会返回大写字母(我已经在Sun的IMAP实现中测试了Gmail)。 - Serdar Basegmez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接