IPv6环境下JavaMail连接SMTP服务器超时问题求助
刚看到你的问题——这段在Eclipse里正常运行的邮件发送代码,放到IPv6环境里就抛出连接超时错误了:
Failed to sent mail javax.mail.MessagingException: Could not connect to SMTP host: smtp.gmail.com, port: 465; nested exception is: java.net.SocketTimeoutException: connect timed out
先把你的测试代码贴在这里方便参考:
package test; import java.util.Properties; import javax.mail.*; import javax.mail.internet.*; public class EmailSender { public static void send(String from, String password, String to, String sub, String msg) { // Get properties object Properties props = new Properties(); props.put("mail.smtp.host", "smtp.gmail.com"); props.put("mail.smtp.socketFactory.port", "465"); props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); props.put("mail.smtp.auth", "true"); props.put("mail.smtp.port", "465"); // get Session Session session = Session.getDefaultInstance(props, new javax.mail.Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(from, password); } }); // compose message try { MimeMessage message = new MimeMessage(session); message.addRecipient(Message.RecipientType.TO, new InternetAddress(to)); message.setFrom(new InternetAddress("sannavdev@gmail.com")); message.setSubject(sub); message.setText(msg); // send message Transport.send(message); System.out.println("message sent successfully"); } catch (MessagingException e) { throw new RuntimeException(e); } } public static void main(String[] args) { final String fromEmail = "sannavdev@gmail.com"; // requires valid gmail id final String password = "sannavdev@1234"; // correct password for gmail id final String toEmail = "vethsa.teja@broadcom.com"; // can be any email id EmailSender.send(fromEmail, password, toEmail, "hello javatpoint", "How r u?"); } }
问题根源分析
这种情况大多是因为IPv6环境下,Java默认优先尝试用IPv6地址连接smtp.gmail.com,但要么你的网络环境没开放IPv6的SMTP端口访问,要么Gmail的SMTP服务在IPv6链路下有访问限制,再加上旧版SSLSocketFactory对IPv6的支持不够完善,最终导致连接超时。
可行的解决方案
你可以按顺序尝试下面这些方法:
强制Java优先使用IPv4连接
最简单的办法是在启动程序时添加JVM参数,强制Java用IPv4:java -Djava.net.preferIPv4Stack=true test.EmailSender也可以在代码里初始化Properties之前直接设置系统属性:
System.setProperty("java.net.preferIPv4Stack", "true");优化JavaMail的SSL配置
你原来用的mail.smtp.socketFactory.class配置有点过时,改用JavaMail内置的SSL启用配置,对IPv6的兼容性更好:// 替换原来的props配置 Properties props = new Properties(); props.put("mail.smtp.host", "smtp.gmail.com"); props.put("mail.smtp.auth", "true"); props.put("mail.smtp.port", "465"); props.put("mail.smtp.ssl.enable", "true"); // 关键配置,启用SSL这个配置会自动使用支持IPv6的SSL socket工厂,不用手动指定类名。
检查Gmail账户的安全设置
现在Gmail默认禁用了低安全性应用的访问,所以如果你的账户开启了两步验证,必须用App密码替换代码里的原密码;如果没开两步验证,得去Google账户设置里临时开启“允许不安全的应用访问”(虽然不推荐,但可以用来排查问题)。排查网络连通性
先在IPv6环境的命令行里测试能不能连上Gmail的SMTP端口:# 用telnet测试IPv6连接 telnet -6 smtp.gmail.com 465 # 或者用nc命令 nc -6 smtp.gmail.com 465如果命令行都连不上,那就是网络环境的问题,得找管理员开放IPv6下465端口的出站权限。
额外小建议
- 把代码里的
Session.getDefaultInstance()换成Session.getInstance(),前者会复用全局Session,容易出现配置冲突,后者每次创建新Session更可靠。 - 确保你的JavaMail版本是1.4.7及以上,旧版本对IPv6的支持确实有bug。
内容的提问来源于stack exchange,提问作者Tej4493

