在工作开发中用到了通过调用java核心库中的mail API,在发送邮件的时候遇到了这样的问题
Failed message 1:
javax.mail.MessagingException: IOException while sending message;
nested exception is:
javax.activation.UnsupportedDataTypeException: no object DCH for MIME type text/plain; charset=us-ascii
这个问题困扰了我很久,在网上搜索了很多解决办法,最终有一种解决办法可以解决
邮件发送代码类似如下:
public class JavaMailTest {
public static void sendEmail(String[] args) throws MessagingException {
Properties props = new Properties();
// 开启debug调试
props.setProperty("mail.debug", "true");
// 发送服务器需要身份验证
props.setProperty("mail.smtp.auth", "true");
// 设置邮件服务器主机名
props.setProperty("mail.host", "smtp.163.com");
// 发送邮件协议名称
props.setProperty("mail.transport.protocol", "smtp");
// 设置环境信息
Session session = Session.getInstance(props);
// 创建邮件对象
Message msg = new MimeMessage(session);
msg.setSubject("JavaMail测试");
// 设置邮件内容
msg.setText("这是一封由JavaMail发送的邮件!");
// 设置发件人
msg.setFrom(new InternetAddress("java_mail_001@163.com"));
Transport transport = session.getTransport();
// 连接邮件服务器
transport.connect("java_mail_001", "javamail");
// 发送邮件
transport.sendMessage(msg, new Address[] {new InternetAddress("java_mail_002@163.com")});
// 关闭连接
transport.close();
}
}
但是在transport.sendMessage的时候总是抛文初的那个异常
最终解决办法是,在sendMessge之前加上如下代码
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
但为什么此方法有效呢?
项目环境的是部署在osgi框架下,首先要了解OSGi框架中的类加载器是如何运作的
OSGI的类加载器
OSGI的每个bundle都包含了java包和类,模块的minifest文件中声明了这个bundle的 Import-Package,即模块的导入类,和 Export-Package,模块的到处类。OSGI通过特有的类加载机制来进行类的加载。OSGI中每个bundle有自己的类加载器,它负责加载模块自己包含的java类和jar包,如果它需要加载核心类库的时候,就会代理给父类加载器(通常是启动类加载器)进行加载,当它需要加载导入的类是,则会代理给这个导入类本身的那个bundle进行加载
好,回到我们开头的那个问题,为什么发送邮件时会抛出异常呢?
邮件发送模块我们调用了javaMail,然而JavaMail是由Sun定义的一套收发电子邮件的API,不同的厂商可以提供自己的实现类。但它并没有包含在JDK中,而是作为JavaEE的一部分。
因此在osgi中对javaMail(SPI 接口)的加载,是利用线程上下文类加载器来加载 SPI 实现的 Java 类,有可能会找不到 Java 类。该类加载器应该是该模块对应的类加载器。因此可以首先通过 class.getClassLoader()来得到模块对应的类加载器,再通过 Thread.currentThread().setContextClassLoader()来设置当前线程的上下文类加载器,从而解决了邮件发送的问题。