大部分人都不会注意到的JavaMail天坑

来源:互联网 发布:网络考试系统软件 编辑:程序博客网 时间:2024/06/06 04:27

问题背景

一般使用JavaMail发送邮件大致过程如下,创建同邮件服务的Session,配置Session参数等:

// Common variablesString host = "your_smtp_server";String from = "from_address";String to = "to_address";// Set propertiesProperties props = new Properties();props.put("mail.smtp.host", host);props.put("mail.debug", "true");// Get sessionSession session = Session.getInstance(props);try {    // Instantiate a message    Message msg = new MimeMessage(session);    // Set the FROM message    msg.setFrom(new InternetAddress(from));    // The recipients can be more than one so we use an array but you can    // use 'new InternetAddress(to)' for only one address.    InternetAddress[] address = {new InternetAddress(to)};    msg.setRecipients(Message.RecipientType.TO, address);    // Set the message subject and date we sent it.    msg.setSubject("Email from JavaMail test");    msg.setSentDate(new Date());    // Set message content    msg.setText("This is the text for this simple demo using JavaMail.");    // Send the message    Transport.send(msg);}catch (MessagingException mex) {    mex.printStackTrace();}

本以为这样就可以愉快地发邮件了。
运行一段时间发现系统总是卡在邮箱发送模块。后来查阅资料发现里面的大坑。

被忽略的参数

关键参数

参数 类型 解释 mail.smtp.connectiontimeout int Socket connection timeout value in milliseconds. This timeout is implemented by java.net.Socket. Default is infinite timeout. mail.smtp.timeout int Socket read timeout value in milliseconds. This timeout is implemented by java.net.Socket. Default is infinite timeout. mail.smtp.writetimeout int Socket write timeout value in milliseconds. This timeout is implemented by using a java.util.concurrent.ScheduledExecutorService per connection that schedules a thread to close the socket if the timeout expires. Thus, the overhead of using this timeout is one thread per connection. Default is infinite timeout.

解析
注意加粗部分,翻译过来就是“默认时间无穷大”,总之一句话:你要不配置这几个参数,邮箱发送的等待时间可能是无穷大,出现异常后(比如邮箱服务器繁忙)客户端有可能永远在等待往服务器读写消息。这里涉及到跟服务器间的socket交互。如下图,JavaMail在socket读写过程中有可能无限等待下去
这里写图片描述

解决方法

把JavaMail重构成异步,避免阻塞核心业务逻辑。
为JavaMail设置超时时间

        Properties props = new Properties();        props.put("mail.smtp.timeout", 10000);        props.put("mail.smtp.connectiontimeout", 10000);        props.put("mail.smtp.writetimeout", 10000);        props.put("mail.smtp.host", host);        props.put("mail.debug", "true");       // Get session        Session session = Session.getInstance(props);