MimeMessage.getAllHeaders() 在两个不同的项目中返回两个不同的类

Posted

技术标签:

【中文标题】MimeMessage.getAllHeaders() 在两个不同的项目中返回两个不同的类【英文标题】:MimeMessage.getAllHeaders() returns two different classes in two different projects 【发布时间】:2015-05-04 07:55:51 【问题描述】:

我有一个关于邮件的项目并且可以正常工作,但我创建了另一个项目,该项目也是关于邮件的,生成的 MimeMessage 无法在第一个项目中解析。

我研究了这些类,发现 MimeMessage 的头类之间的区别 两个项目都在使用

javax.mail.internet.MimeMessage

但我将标题记录为:

Enumeration enumer = originalUserMessage.getAllHeaders();
while(true)
    try
        Object obj = enumer.nextElement();
        if(obj == null) 
            break;
        
        LOGGER.info("Header class: "+obj.getClass().getName());
        LOGGER.info("Header super class:" + obj.getClass().getSuperclass().getName());
     catch (NoSuchElementException nsee) 
        break;
    


打印的第一个项目:

2015-03-03 16:57:16 INFO  SmimeWriter:204 - Header class: 
javax.mail.Header
2015-03-03 16:57:16 INFO  SmimeWriter:205 - Header super class: 
java.lang.Object

打印第二个项目

2015-03-03 16:57:39 INFO  SmimeWriter:204 - Header class: 
javax.mail.internet.InternetHeaders$InternetHeader
2015-03-03 16:57:39 INFO  SmimeWriter:205 - Header super class: 
javax.mail.Header

所有相关的类似乎都在 mail.jar 中。我正在使用 maven 来获取 jars,两个项目都将 jar 获取为:

<dependency>
  <groupId>javax.mail</groupId>
  <artifactId>mail</artifactId>
  <version>1.4.2</version>
</dependency>

可能是什么问题。还有其他依赖的jar吗?

两个项目都使用相同的方法。在设置了 MIME 消息其他部分下方的代码块后,但此处出现问题。 代码:

        MimeMessage originalUserMessage = new MimeMessage(session);

        originalUserMessage.setFrom(from);
        originalUserMessage.setRecipients(Message.RecipientType.TO, to);
        if(cc != null && cc.length>0)
            originalUserMessage.setRecipients(Message.RecipientType.CC, cc);
        

        Enumeration enumer = originalUserMessage.getAllHeaders();
        while(true)
            try
                Object obj = enumer.nextElement();
                if(obj == null) 
                    break;
                
                LOGGER.info("Header class: "+obj.getClass().getName());
                LOGGER.info("Header super class: "+obj.getClass().getSuperclass().getName());
             catch (NoSuchElementException nsee) 
                break;
            

        

【问题讨论】:

如果从 cmets 正确理解您的真正问题:在某些 JavaMail 实现中,调用 setRecipients(Message.RecipientType.TO, addr),其中 addr 是包含两个或多个逗号分隔地址的字符串,结果在多个“To:”标头中,而不是 MimeMessage 中的单个统一“To:”标头。对吗? 这正是我的问题 :) 很抱歉没有解决这个问题。 您说 servlet 容器提供 JavaMail,即使我在我的应用程序 ClassLoader 中放置所需版本的 JavaMail 也可能会忽略它并使用服务器环境提供的版本。在第一个项目中,我们使用定制版本的 tomcat,但在第二个项目中,我们在常规 tomcat 上运行。这可能是实际问题。如何强制 ClassLoader 从包而不是 tomcat 提供的包中加载 JavaMail。 顺便说一句,我错过了说 addr is javax.mail.Address[] 听起来定制的Tomcat在它的库目录中有一个更新的JavaMail,你的JavaMail可能有bug。考虑将您的依赖项更改为a more recent JavaMail version。 【参考方案1】:

这根本不是问题。 contract of the MimeMessage.getAllHeaders() method 很清楚:

将此消息中的所有标头作为 Header 对象的枚举返回。

该文档指的是javax.mail.Header 类。

因此,当您调用 MimeMessage.getAllHeaders() 时,只能假设 Enumeration 将返回 javax.mail.Header 的实例是安全的。它可能会或可能不会返回作为 Header 子类的对象,根据多态性的基本规则,这是完全有效的事情,只要调用代码可以安全地将它们视为 Header实例。

根据您运行程序的方式,您的 pom.xml 中的 JavaMail 版本可能无关紧要。在 Java EE 容器(如 GlassFish 和 JBoss)和 servlet 容器(如 Tomcat)中,JavaMail 由容器提供,因此即使您将自己的 JavaMail 版本打包到应用程序中,ClassLoader 也可能会忽略它并无条件使用提供的 JavaMail由服务器环境决定。

旁注:循环遍历枚举的正确方法是使用其hasMoreElements() 方法:

while (enumer.hasMoreElements()) 
    Header header = (Header) enumer.nextElement();
    System.out.printf("%s: %s%n", header.getName(), header.getValue());

尽管使用 try/catch 在技术上有效,但使用 try/catch 检测枚举的结束是不正确的。它更慢、更难阅读,并且可能会无意中捕捉到编程错误,这使得调试变得相当困难。

【讨论】:

首先,感谢您的回答和附注:) 关于标题类型的问题是:当邮件有 2 个地址并且我使用 MimeMessage 的 writeTo 方法并将其写入 eml 文件时第一个项目将标头导出为:到:a@domain.com、b@domain.com 但第二个项目的 InternetHeader 导出标头有两行:到:a@domain.com 到:b@domain.com。与邮件服务器联系的实际项目是第一个项目,当它解析从第二个项目生成的 eml 文件时,它只需要第一个 To: 标头并忽略第二个收件人,我认为标头对此负责 考虑编辑您的问题以包含您在 MimeMessage 中设置收件人的代码。您可能还应该在问题中包含您的评论文本,因为这是您遇到的真正问题。 我寻找您关于 addr 的评论是字符串并包含一些用逗号分隔的地址,并尝试使用 String 调用 setRecipients 方法并且它有效。这是一种解决方法,但无论如何,它奏效了。

以上是关于MimeMessage.getAllHeaders() 在两个不同的项目中返回两个不同的类的主要内容,如果未能解决你的问题,请参考以下文章