最近把项目迁移到阿里云,这几天观察后台日志,发现这么一段异常:
2020-04-09 20:51:39 ERROR MailUtils:228 : 发送邮件失败!com.sun.mail.util.MailConnectException: Couldn't connect to host, port: smtp.163.com, 25; timeout -1;
nested exception is:
java.net.ConnectException: Connection timed out (Connection timed out)
然后去调发送邮件的接口,还真的发不了。刚开始也是觉得很奇怪,之前项目在另一台服务器上运行好好的,在本地也可以正常的,为什么一迁移到阿里云服务器上就不行了呢?在阿里云官网上提交工单,他们的售后工程师说了一堆,为了防止垃圾邮件的泛滥,阿里加入了中国什么反垃圾邮件协会,禁用25端口。并给出两种解决方案:
其一:使用SSL安全端口465发送,
其二,使用他们阿里邮箱,他们将25重定向到80端口了。
果断排除第二种,这一来嘛,公司买了第三方邮箱的服务,未到期,重新买阿里邮箱,会造成资源浪费,这二来嘛,还需要修改各个项目涉及到邮件发送的代码。除了核心业务方面的代码,基础配置的代码我一向懒得去改。
所以就毅然决然踏上使用465端口这条路。首先找到项目中邮件发送的代码,可找来找去,没发现涉及到端口方面的配置,于是联系邮件服务提供方,他们说已经开放465端口了的,不信,你用下面的命令测试一下就知道了:
telnet smtp.163.com 465
打开终端,输入以上命令,确实出来welcome的欢迎语。那说明问题不在他们那,于是又找到阿里,阿里小姐姐可真敬业啊,大中午我在吃着午饭,她打来电话,此时已过北京时间12:30。电话里态度也是很好,说了一大堆,挂了电话一想,她话中“是,邮件提供方开放了465端口,但不代表他就使用默认的465端口来发邮件啊,万一他使用25呢”是解决问题的中心思想呀。又联系邮件服务提供方,他们明确告诉我,他们并不能指定使用哪个端口来发送邮件,使用哪个端口发送邮件在于客户端的设定。转了几圈,才猛地发现,原来需要自己编码手动指定邮件发送所使用的端口,如果不指定端口,那么系统将会使用25端口来发送。于是进行编码和测试,终于通了。下面是实现的源码:
/**
* 使用SSL 465安全方式发送
* @param toEmail 收件人邮箱
* @param content 邮件内容
* @param subject 邮件主题
*/
public static void sendSSLEmail(String toEmail, String content, String subject) {
boolean isSSL = true;
String host = "smtp.163.com";
int port = 465;
final String from = "[email protected]"; // 发件人的email
boolean isAuth = true;
final String password = "123456";
Properties props = new Properties();
props.put("mail.smtp.ssl.enable", isSSL); //指定使用SSL方式发送
props.put("mail.smtp.host", host); //邮件主机
props.put("mail.smtp.port", port); //指定使用465安全端口
props.put("mail.smtp.auth", isAuth); //需要验证
Session session = Session.getDefaultInstance(props, new Authenticator() {
/**
* 身份验证
*/
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(from , password);
}
});
/**
* 实现邮件发送功能
*/
try {
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.addRecipient(Message.RecipientType.TO, new InternetAddress(toEmail));
message.setSubject(subject);
message.setText(content);
LOGGER.info("准备发送");
Transport.send(message);
LOGGER.info("发送完毕");
} catch (AddressException e) {
LOGGER.error(e.getMessage(),e);
} catch (MessagingException e) {
LOGGER.error(e.getMessage(),e);
}
}
注:文中涉及到账号密码请替换为自己的信息。
更新到服务器终于能正常发送邮件了。