使用JavaMail发送邮件-no object DCH for MIME type multipart/mixed报错解决

最近需要实现一个使用Spring schedule按一定时间间隔自动触发条件发送邮件的功能,在开发的过程中,是按照先测试能发出text/html文本邮件,然后测试添加附件发送邮件,我碰到的问题是,文本邮件能正常发送出来,但是添加附件的邮件却发不出来,这个问题困扰了我很久,所以有必要记录下。

报错内容:"javax.activation.UnsupportedDataTypeException: no object DCH for MIME type multipart/mixed"
初步解释:是不支持数据类型,没有复合邮件对象的专用信息渠道(MIME type multipart/mixed)”,字面意思是没有发送MIME类型邮件的对象专用信息通道。
报错内容
以下是百度对MIME邮件的解释:
MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型。是设定某种扩展名文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义文件名,以及一些媒体文件打开方式。
它是一个互联网标准,扩展了电子邮件标准,使其能够支持:非ASCII字符文本;非文本格式附件(二进制、声音、图像等);由多部分(multiple parts)组成的消息体;包含非ASCII字符的头信息(Header information)
 
问题解决过程:
(1)CSDN,overstackflow等上有很多帖子,说在使用实例化Transport对象send()方法发送邮件前,需要添加下面这一段代码:
MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed; x-java-fallback-entry=true");
mc.addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822");
CommandMap.setDefaultCommandMap(mc);                        
Thread.currentThread().setContextClassLoader( getClass().getClassLoader() );        

overstackflow上面对这段代码的解释是:

javaMail depends on some configuration files to map MIME types to Java classes (e.g., multipart/mixed to javax.mail.internet.MimeMultipart). These configuration files are loaded using the ClassLoader for the application. If the ClassLoader doesn't function properly, these configuration files won't be found

中文意思大概是:javaMail发送MIME类型的邮件需要依赖某些配置文件,比如如果使用MimeMultipart需要找到multipart/mixed的对应配置。这些配置文件将会被类装载器加载,如果不能被正常加载,这些配置文件将无法生效。

javamail包下有MANFEST文件,里面有一个mailcap或者mailcap.default文件,读取的就是这个文件,发现里面有对邮件格式的要求,如普通html邮件text/html,纯文本邮件text/plain,包含附件的邮件multipart/*等,如下图所示:

参考博客:https://stackoverflow.com/questions/21856211/javax-activation-unsupporteddatatypeexception-no-object-dch-for-mime-type-multi?r=SearchResults

结果:添加完成后,依然报错,无效。

 (2)怀疑mail.jar包和activation.jar包版本问题

由于项目中使用的mail.jar包版本1.4.1,网上建议升级到1.4.7版本或更高的版本尝试解决,由于项目服务器是使用OSGI来建立的,对OSGI几乎不了解,使用常规的方式导入包后发现没有任何效果,项目下只是新多了一个dependency libraries,里面包含自己添加的包,但是这个包里面的资源对于项目好像没有效果,测试依然报错。后面根据帖子又重新build path,将新jar包import然后又export后,还是没有效果。

结果:包更换未成功,对OSGI不了解

参考博客:http://osgi.com.cn/article/7289374

 (3)怀疑自己代码本身存在问题

在尝试了以上方法还是没有解决后,参考博客 https://www.cnblogs.com/xdp-gacl/p/4216311.html,使用博客里能发出邮件附件的代码来进行测试。测试时在OSGI服务端项目里新增了一个package,里面写了一个包含main方法的类,直接发送邮件测试,以下是代码

package TestMailSend;
import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.Properties; import javax.activation.DataHandler; import javax.activation.FileDataSource; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; public class SendMail { public static void main(String[] args) throws Exception{ //创建Properties文件 Properties prop=new Properties(); prop.setProperty("mail.host", "mail.boe.com.cn");//主机 prop.setProperty("mail.transport.protocol", "smtp"); prop.setProperty("mail.smtp.auth", "true"); //使用JavaMail发送邮件的5个step //step1 创建session //Session session=Session.getInstance(prop); Session session1=Session.getDefaultInstance(prop); //开启session的debug模式,可以看到程序发送email的运行状态 session1.setDebug(true); //step2 通过session得到transport对象 //Transport trans=session.getTransport(); Transport trans=session1.getTransport(); //step3 使用邮件的用户名和密码连上邮箱服务器,发送邮件时,需要验证发件人的邮箱名和密码正确后才可以发送 trans.connect("mail.boe.com.cn", "发件人邮箱", "发件人邮箱密码"); //step4 创建邮件 //Message message=createSimpleMail(session);//发送纯文本 Message messageAttach=createAttachMail(session1); //step5 发送邮件 //trans.sendMessage(message, message.getAllRecipients()); trans.sendMessage(messageAttach, messageAttach.getAllRecipients()); trans.close(); } /** * 创建一个封只包含文本的邮件 * @param session * @return * @throws MessagingException * @throws AddressException */ public static MimeMessage createSimpleMail(Session session) throws AddressException, MessagingException{ //创建邮箱对象 MimeMessage message=new MimeMessage(session); //指明邮件的发件人 message.setFrom(new InternetAddress("发件人邮箱")); //指明邮件的收件人 message.setRecipient(Message.RecipientType.TO, new InternetAddress("收件人邮箱")); //邮件的标题 message.setSubject("只包含文本的简单邮件"); //邮件的文本内容 message.setContent("这是一封测试邮件!","text/html;charset=utf-8"); //返回创建好的邮件对象 return message; } /** * 创建一封包含附件的邮件 * @param session * @return * @throws MessagingException * @throws AddressException * @throws IOException * @throws FileNotFoundException */ public static MimeMessage createAttachMail(Session session) throws AddressException, MessagingException, FileNotFoundException, IOException{ //创建邮件 MimeMessage message=new MimeMessage(session); //指明邮件发件人 message.setFrom(new InternetAddress("发件人邮箱")); //指明邮件收件人 message.setRecipient(Message.RecipientType.TO, new InternetAddress("收件人邮箱")); //邮件标题 message.setSubject("这是一封包含附件的邮件"); //创建邮件正文,为了避免邮件正文中文乱码,使用utf-8 MimeBodyPart text=new MimeBodyPart(); text.setContent("使用JavaMail创建的包含附件的邮件","application/x-xls;charset=utf-8"); //创建附件邮件 MimeBodyPart attachment=new MimeBodyPart(); DataHandler dh=new DataHandler(new FileDataSource("C:\\测试Excel.xls")); attachment.setDataHandler(dh); attachment.setFileName(dh.getName()); //创建容器描述数据关系 MimeMultipart mmp=new MimeMultipart(); mmp.addBodyPart(text); mmp.addBodyPart(attachment); mmp.setSubType("mixed"); message.setContent(mmp); message.saveChanges(); //存盘 message.writeTo(new FileOutputStream("C:\\attachmentEmail.eml")); //返回生成的邮件 return message; } }

结果:将这部分代码执行,发现能正常发出包含附件的邮件,然后将同样的代码放到OSGI服务器下运行,发现还是发不出来。通过以上发现,邮件发不出附件排除了jar包版本的问题,也可排除了代码本身的问题(前面测试过了没有问题),然后怀疑到了OSGI服务器设置的问题,查询overstackflow上也有一个人跟我情况类似,参考博客:https://stackoverflow.com/questions/8923324/java-throws-an-unsupporteddatatypeexception-when-running-osgi-with-javax-mail?r=SearchResults,但是依然没有找到解决办法。

(4)尝试将mail包通过MANIFEST添加到class path里

最后通过MANIFEST,在runtime下添加了class path,将mail.jar包添加到类路径,重新测试竟然OK了!

runtime下添加mail.jar类路径。

Classpath下面有一段介绍:
Specify the libraries and folders that constitute the plug-in classpath.  If unspecified, the classes and resources are assumed to be at the root of the plug-in.
英语蹩脚,大概意思就是,指定组成plug-in 类路径下的文件夹,如本项目文件夹为lib。如果不指定,资源类可能还在plug-in的根目录, 这样配置后,MANIFEST.MF里在Bundle-Class下面新增lib/mail.jar 。
然后在build.properties下发现自动新增lib/mail.jar。
网上有一篇帖子有大概的说明MANIFEST.MF配置,里面有一段话: .”指程序运行目录,即导出的JAR 包所在目录。程序运行时依据Class-Path 项的设置路径来查找支持库。每一个支持库之间用空格隔开。
结论:将mail.jar包在MANIFEST文件下,通过runtime导入包的类路径后,重新发送添加附件的邮件能成功。

 

总结:Javamail发送有附件的邮件功能不是很熟悉,走了很多弯路,小小的记录一下,有些不需要的步骤没有写。另外如果想对发送邮件过程有详细的了解,可以学习segmentfault上面的一篇博文:https://segmentfault.com/a/1190000008030346

猜你喜欢

转载自www.cnblogs.com/youngchaolin/p/10430032.html