在编写demo代码时,用 spring 的JavaMailSender连续发送2封邮件,在发送第2封时,会出现 “Could not connect to SMTP host” 的问题,以下是分步排查和解决方案:
1. 核心问题分析
该错误通常由以下原因导致:
- SMTP 服务器连接限制:部分邮件服务商限制短时间内的连接频率(如QQ邮箱、Gmail)
- 连接未正确关闭:首次发送后连接未释放,导致后续连接被拒绝
- 资源泄漏:未使用连接池时,频繁创建新连接导致资源耗尽
2. 解决方案
方案一:启用 SMTP 连接池
在 application.properties
中添加连接池配置:
# 连接池配置
spring.mail.properties.mail.smtp.connectionpool=true
spring.mail.properties.mail.smtp.connectiontimeout=5000
spring.mail.properties.mail.smtp.timeout=5000
spring.mail.properties.mail.smtp.writetimeout=5000
spring.mail.properties.mail.smtp.maxconnects=5 # 最大连接数
方案二:强制关闭连接
在每次发送后手动关闭传输通道:
public void sendEmailWithClose() throws MessagingException {MimeMessage message = mailSender.createMimeMessage();MimeMessageHelper helper = new MimeMessageHelper(message, true);// 设置邮件内容...Transport transport = mailSender.getSession().getTransport();try {transport.connect();transport.sendMessage(message, message.getAllRecipients());} finally {transport.close(); // 关键:强制关闭连接}
}
方案三:增加发送间隔
在连续发送间添加延迟(不推荐,但可临时验证问题):
public void sendMultipleEmails() {sendEmail();Thread.sleep(3000); // 间隔3秒sendEmail();
}
3. 邮件服务器特殊配置
邮件服务商 | 特殊要求 | 建议配置 |
---|---|---|
QQ邮箱 | 单IP每分钟最多5次连接 | 使用连接池 + 间隔至少12秒 |
Gmail | 每日发送限制(免费版500封/天) | 启用OAuth2认证 + 连接池 |
阿里云 | 新账户需手动解除发信频率限制 | 提交工单申请调整配额 |
4. 调试步骤
- 开启详细日志
# application.properties
logging.level.org.springframework.mail=DEBUG
logging.level.com.sun.mail=DEBUG
- 观察日志特征
正常日志应显示连接复用:
DEBUG SMTP: trying to connect to host "smtp.qq.com", port 587, isSSL false
DEBUG SMTP: connected to host "smtp.qq.com", port: 587
DEBUG SMTP: connection reused
异常日志会显示连接中断:
DEBUG SMTP: could not connect to host "smtp.qq.com", port: 587
java.net.SocketException: Connection reset
5. 高级优化
自定义连接工厂
@Configuration
public class MailConfig {@Beanpublic JavaMailSenderImpl mailSender() {JavaMailSenderImpl sender = new JavaMailSenderImpl();sender.setHost("smtp.qq.com");sender.setPort(587);Properties props = sender.getJavaMailProperties();props.put("mail.smtp.ssl.trust", "*");props.put("mail.smtp.connectiontimeout", 10000);props.put("mail.smtp.ssl.socketFactory.class", "javax.net.ssl.SSLSocketFactory");return sender;}
}
异步发送 + 重试机制
@Async
@Retryable(maxAttempts = 3, backoff = @Backoff(delay = 2000))
public void sendEmailWithRetry(String to, String subject, String text) {// 发送逻辑
}
6. 企业级解决方案
场景 | 方案 | 工具推荐 |
---|---|---|
高并发批量发送 | 消息队列 + 消费者限流 | RabbitMQ + Spring Batch |
跨国邮件服务 | 多SMTP服务商自动切换 | Apache Camel |
合规审计要求 | 邮件网关代理 | Postfix + OpenSMTPD |
7. 验证工具
使用 Telnet 测试 SMTP 连接稳定性:
# 第一次连接
telnet smtp.qq.com 587
EHLO test
QUIT# 立即第二次连接(观察是否被拒绝)
telnet smtp.qq.com 587
如果第二次连接失败,说明服务器端有限制,需调整发送策略。
通过上述方案,可有效解决连续发送邮件时的连接中断问题。建议优先采用 连接池 + 强制关闭连接 的组合方案,兼顾性能和可靠性。