正在开发的平台的邮件服务在本地测试是没问题的,不过在部署到ECS之后,发现每次发送邮件的时候,会抛这个异常:
javax.mail.MessagingException: Could not connect to SMTP host: smtp.mxhichina.com, port: 25;
nested exception is:
java.net.ConnectException: Connection timed out (Connection timed out)
at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:1282)
at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:370)
at javax.mail.Service.connect(Service.java:275)
at javax.mail.Service.connect(Service.java:156)
at com.weymay.util.email.MailUtils.realSend(MailUtils.java:76)
at com.weymay.util.email.MailUtils.send(MailUtils.java:108)
at com.weymay.service.email.PlatformEmailServiceImpl.realSend(PlatformEmailServiceImpl.java:70)
at com.weymay.queue.msg.EmailQueueListener.onMessage(EmailQueueListener.java:45)
at com.weymay.common.queue.msg.RedisQueue$ListenerThread.run(RedisQueue.java:208)
Caused by: java.net.ConnectException: Connection timed out (Connection timed out)
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at java.net.Socket.connect(Socket.java:538)
at com.sun.mail.util.SocketFetcher.createSocket(SocketFetcher.java:232)
at com.sun.mail.util.SocketFetcher.getSocket(SocketFetcher.java:189)
at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:1250)
... 8 more
很明显提示的是不能通过25端口连接到smtp服务。
尝试测试25端口出口方向连接163的smtp服务是否畅通:
$ telnet smtp.163.com 25
Trying 220.181.12.16...
Trying 220.181.12.15...
Trying 220.181.12.12...
Trying 220.181.12.11...
Trying 220.181.12.13...
Trying 220.181.12.18...
Trying 220.181.12.17...
^C
果然出口方向25端口有点问题。
在网络上查了下资料,发现阿里官方有相应的解释:
为何 SMTP 服务 25 端口不可用?
ECS 基于安全考虑,目前已禁用 25 端口。
如果您的发送程序部署在阿里云 ECS 上,建议您不勾选 SSL 时,使用 80 端口;勾选 SSL 时,使用 465 端口。
再查了一下,阿里官方有提到各种申请开启25端口的方式。不过考虑每台服务器都需要申请的话,貌似有点太麻烦了。所以决定放弃25端口。
如果启用了ssl,那么可以通过465端口发送邮件。所以在原代码的基础上在邮件配置的地方添加:
//因为阿里服务器封闭了出口25端口的缘故,所以改用ssl,改用465端口发送邮件
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
props.setProperty("mail.smtp.socketFactory.class", SSL_FACTORY);
props.setProperty("mail.smtp.socketFactory.fallback", "false");
props.setProperty("mail.smtp.port", "465");
props.setProperty("mail.smtp.socketFactory.port", "465");
重新部署,问题即解决。