spring boot邮件发送失败主因是配置错误而非代码问题,需重点检查host、port、username、password及smtp授权码,并用thymeleaf渲染模板、设置utf-8编码、规范发信地址以避免进垃圾箱。

Spring Boot 项目里发不了邮件?先看 spring-boot-starter-mail 配置对不对
绝大多数“发不出验证码”的问题,根本不是代码写错了,而是配置漏了或填错了。Spring Boot 的邮件自动配置非常敏感,一个字段错,JavaMailSender 就不会初始化,调用 send() 时直接抛 NullPointerException 或 BeanCreationException。
关键检查点:
-
spring.mail.host必须是纯域名(如smtp.qq.com),不能带https://或端口号 -
spring.mail.port要和加密方式匹配:QQ 邮箱用587(STARTTLS)或465(SSL),别混用 -
spring.mail.username必须是完整邮箱地址(如xxx@qq.com),不是昵称或用户名 -
spring.mail.password不是登录密码,是邮箱「SMTP 授权码」——QQ/163 都要单独在邮箱设置里开通并生成 - 如果用 QQ 邮箱,必须加
spring.mail.properties.mail.smtp.auth=true和spring.mail.properties.mail.smtp.starttls.enable=true
验证码邮件内容怎么动态塞进去?别手拼 HTML 字符串
直接用 String.format() 或 + 拼 HTML,看着快,但容易 XSS、编码错乱、模板难维护。Spring Boot 原生支持 Thymeleaf,配合 TemplateEngine 解析最稳妥。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 把邮件 HTML 存在
src/main/resources/templates/email/verify.html,用th:text绑定变量,比如<span th:text="${code}"></span> - Java 里用
Context注入参数:context.setVariable("code", "829471") - 调用
templateEngine.process("email/verify", context)得到渲染后的字符串,再塞进MimeMessageHelper.setText(..., true) - 别忘了在
pom.xml加spring-boot-starter-thymeleaf,否则TemplateEnginebean 根本不存在
本地调试总超时?JavaMailSender.send() 卡住的常见原因
开发机连不上 SMTP 服务器,不是网络问题,大概率是防火墙、代理或 DNS 导致的。超时默认 5 秒,但实际卡住可能长达 30 秒以上,拖慢整个验证流程。
排查顺序:
- 先用命令行测试连通性:
telnet smtp.qq.com 587(Windows 可能要开 Telnet 功能;Mac/Linux 直接可用) - 如果 telnet 不通,说明是公司网络屏蔽了 SMTP 端口,换企业邮箱或改用邮件服务商 API(如 SendGrid)
- 如果 telnet 通但 Java 还是超时,检查
spring.mail.properties.mail.smtp.connectiontimeout和mail.smtp.timeout是否设得太小(建议设为10000) - 开发环境强烈建议加
@Profile("dev")条件化配置,用SimpleMailMessage打印日志代替真实发送,避免反复触发风控
验证码发出去了但收件箱没看到?注意垃圾邮件和字符编码
尤其是用中文模板或含 emoji 时,Gmail、Outlook 极易判为垃圾邮件。不是被拦截,是进了 Promotions 或 Spam 标签。
降低误判率的关键动作:
- 邮件主题加
[你的APP名]前缀,比如[小记]您的验证码,提升可信度 - HTML 中
加<meta charset="UTF-8">,且整个模板文件保存为 UTF-8 编码(IDE 里右下角确认) - 避免在 HTML 里写大段内联样式或 JavaScript,纯语义化标签 + 行内 style 最安全
- 发信地址用公司域名邮箱(如
no-reply@yourcompany.com),别用个人 QQ/163,否则 SPF/DKIM 验证失败,大概率进垃圾箱
真正麻烦的不是发不出去,是发出去了没人看见。模板渲染、编码、发信身份这三块,任何一个细节松动,验证码就等于没发。










