用 JavaMail API 发送纯文本邮件最简路径是引入 jakarta.mail 依赖,配置 Session 时必须用 Authenticator 匿名子类传账号密码(即使无需认证),正确选择端口(587 for STARTTLS/465 for SSL)并避免 TLS 参数互斥,Gmail 等需启用两步验证并使用应用专用密码。

用 JavaMail API 发送纯文本邮件最简路径
Java 自带的 javax.mail(现为 jakarta.mail)是实现邮件通知最轻量、无需第三方服务依赖的选择。前提是你的环境能直连 SMTP 服务器(比如公司内网邮箱或已配置好 Relay 的邮件网关)。
关键不是“能不能发”,而是“怎么绕过常见认证和 TLS 报错”。JDK 11+ 默认不带 javax.mail,必须显式引入依赖:
implementation 'com.sun.mail:jakarta.mail:2.0.1'
发送逻辑本身只需 10 行左右,但以下三点不处理,90% 的人卡在第一步:
-
Session必须用Authenticator匿名子类传入账号密码(哪怕 SMTP 不需要认证,也得传个空实现,否则抛AuthenticationFailedException) - SMTP 端口不是固定 25:启用 STARTTLS 用 587,启用 SSL/TLS 用 465,两者不能混;
mail.smtp.starttls.enable和mail.smtp.ssl.enable互斥,同时设 true 会静默失败 - Gmail 或 Outlook 等公有邮箱必须开“应用专用密码”,且禁用“安全性较低的应用访问权限”——这个开关藏在 Google 账号设置里,不是邮箱设置
避免 javax.mail.AuthenticationFailedException 的真实原因
这个异常名字极具误导性:它不一定代表密码错了。更常见的触发条件是 SMTP 服务器拒绝了连接协商阶段的任意一环。
立即学习“Java免费学习笔记(深入)”;
排查顺序应为:
- 先 telnet 测试端口通不通:
telnet smtp.gmail.com 587(Linux/macOS)或用 PowerShellTest-NetConnection smtp.gmail.com -Port 587 - 确认
mail.smtp.auth设为true—— 即使服务器不要求认证,很多 SMTP 实现(如 Postfix)也强制要求客户端声明“我支持 auth” - 检查
mail.smtp.host值是否含多余空格或 http:// 前缀(常见手误写成http://smtp.gmail.com) - 若用 Gmail,确保账号已开启两步验证,并生成了应用专用密码(不是你登录 Google 的密码)
Spring Boot 项目中注入 MailSender 的最小配置
如果你用 Spring Boot,别自己 new Session,直接配 JavaMailSender Bean。但注意:Spring Boot 2.6+ 默认不再自动装配 JavaMailSender,必须加 starter:
implementation 'org.springframework.boot:spring-boot-starter-mail'
application.yml 中只写必要项,其余交给 Spring 自动推导:
spring:
mail:
host: smtp.gmail.com
port: 587
username: your.email@gmail.com
password: xxxxxxxxxxyyyyyyyyy # 应用专用密码
properties:
mail:
smtp:
auth: true
starttls:
enable: true使用时直接 @Autowired 注入 JavaMailSender,调用 send() 即可。注意:Spring 的 SimpleMailMessage 只支持纯文本,附件或 HTML 需用 MimeMessage + MimeMessageHelper。
生产环境必须绕开的三个坑
本地能发 ≠ 上线能发。实际部署时,以下问题高频出现且日志极少提示:
- 云服务器(如阿里云、腾讯云)默认封禁 25/465/587 出方向端口,需工单申请解封,或改用云厂商提供的邮件推送服务(如阿里云 DirectMail)
- Docker 容器内 DNS 解析失败导致
UnknownHostException:在docker run加--dns 8.8.8.8,或在 Spring Boot 配置中把host换成 IP(如142.250.191.109代替smtp.gmail.com) - 频繁发送触发 SMTP 限流:Gmail 免费账号每 24 小时最多 500 封,超限后后续请求直接被静默丢弃(无异常),需加队列 + 重试 + 限速(如用
RateLimiter)
真正的难点不在代码,而在让邮件从你的 JVM 进程真正抵达收件箱——中间隔着网络策略、DNS、反垃圾规则、收件方过滤器,每层都可能无声吞掉你的 MimeMessage。










