【问题标题】:Parsing Multipart/Mixed with Multipart/Alternative body in java在java中解析Multipart/Mixed with Multipart/Alternative body
【发布时间】:2026-01-24 05:55:01
【问题描述】:

我收到来自客户的电子邮件,他们将多部分/替代消息嵌套在多部分/混合消息中。当我得到消息的正文时,它只返回 multipart/alternative 级别,而我真正想要的是包含在 multipart/alternative 中的 text/html 部分。

我查看了 javax.mail 的 javadocs,但我找不到一种简单的方法来获取本身就是 multipart 的 bodypart 的主体,或者跳过第一个 multipart/mixed 部分并进入 multipart/alternative body 来阅读 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>
            }
        }
    }
}

它似乎一直停在第二个边界并且没有进一步解析任何内容。在上述消息的情况下,它会在边界 =“----=_Part_19486_1391901275.1418138792683”处停止,并且永远不会到达消息的文本。

【问题讨论】:

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

标签: java email multipart jakarta-mail


【解决方案1】:

在这个区块中:

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;
}

【讨论】:

  • @Psycho_Penguin:对你有帮助吗?
  • 抱歉,这几天我一直在度假。到目前为止,它在测试环境中有效,但在生产环境中无效。
  • 很奇怪。在两种环境都失败之前?
  • 未确定,之前的测试邮件略有不同,并且总是通过。终于用相同的电子邮件进行了测试,但它仍然无法在产品中工作。试图找出原因。
  • 如果它在测试中工作但不在生产中,一些差异(代码、测试数据、conf)必须保留
【解决方案2】:

我已经测试了你的代码,但我也失败了。

在我的例子中,b.getContentType() 返回所有大写字符(例如“TEXT/HTML; charset=UTF-8”)。所以我将它转换为小写并且它有效。

String contentType=b.getContentType().toLowerCase(Locale.ENGLISH);

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

【讨论】:

  • 为什么我将内容类型打印到日志时总是小写?
  • 如果是小写,没问题。我认为这与您使用的电子邮件客户端库有关。一些电子邮件客户端返回大写(我已经用 gmail 测试了 sun 的 IMAP 实现)。