Java初学者应使用jakarta.mail替代已废弃的javax.mail,因JDK 9+模块化移除了java.activation,旧版会抛NoClassDefFoundError;需显式引入jakarta.mail-api和com.sun.mail:jakarta.mail依赖,并正确配置TLS/SSL、应用专用密码及Authenticator。

Java初学者直接写完整邮件客户端容易卡在认证、SSL、协议细节上,不建议从零手撸 SMTP/IMAP 协议栈。用 javax.mail(现为 jakarta.mail)是合理起点,但要注意 JDK 11+ 默认不包含它,且旧版 javax.mail:mail 已废弃。
为什么 javax.mail 会抛 NoClassDefFoundError 或 ClassNotFoundException
因为 JDK 9 开始模块化,java.activation 和邮件 API 全被移出默认 classpath;JDK 11 彻底删除 java.activation 模块。即使加了旧 jar,也会因缺少 javax.activation.DataSource 等类失败。
- ✅ 正确做法:改用
jakarta.mail:jakarta.mail-api+com.sun.mail:jakarta.mail(推荐 2.0.1+) - ❌ 不要再用
javax.mail:mail:1.6.2或更老版本 - 若用 Maven,必须显式声明依赖,不能指望 JDK 自带
jakarta.mail jakarta.mail-api 2.1.3 com.sun.mail jakarta.mail 2.0.1
Session.getInstance(...) 和 Session.getDefaultInstance(...) 的区别与风险
后者已被标记为 @Deprecated,且线程不安全:多个线程调用会共享同一 Session 实例,导致配置(如密码、host)被覆盖。前者才是标准用法,但需传入 Properties 和可选的 Authenticator。
- SMTP 发信必须设
mail.smtp.auth="true",否则 Gmail/Outlook 等拒绝连接 - 务必启用 TLS:
mail.smtp.starttls.enable="true"(Gmail 端口 587)或 SSL:mail.smtp.ssl.enable="true"(端口 465) - 避免硬编码密码——用
Authenticator子类延迟提供凭据,防止日志泄露
Properties props = new Properties();
props.put("mail.smtp.host", "smtp.gmail.com");
props.put("mail.smtp.port", "587");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
Session session = Session.getInstance(props, new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("user@gmail.com", "app-password-here");
}
});
收邮件时 Store.connect(...) 报 AuthenticationFailedException 的常见原因
Gmail/Outlook 等已停用“用户名+密码”直连,必须用应用专用密码(App Password)或 OAuth2。普通网页登录密码无效,且开启两步验证后才可生成应用密码。
立即学习“Java免费学习笔记(深入)”;
- Gmail:进入 Google 账户 → 安全 → 两步验证 → 应用专用密码(选“邮件”,生成 16 位密码)
- Outlook:账户安全设置 → 高级安全选项 → 应用密码
- IMAP 设置必须匹配:Gmail 是
imap.gmail.com:993,mail.imaps.enable="true",且用Store.connect(host, user, password) - 别漏掉
folder.open(Folder.READ_ONLY),否则getMessages()返回空数组
初学者最容易忽略的权限与安全细节
本地测试时,IDE 运行的 Java 进程可能被系统防火墙拦截出站连接;企业网络常屏蔽 465/587/993 端口;而 Gmail 对异常登录行为(如新设备、非浏览器 UA)会静默拒收或进垃圾箱。
- 发信后检查收件箱和垃圾邮件文件夹——Gmail 可能标记为“未加密发送”并降权
- 收信前先 telnet 测试端口连通性:
telnet smtp.gmail.com 587(需安装 telnet 客户端) - 不要在代码里写死邮箱密码,哪怕只是 demo;至少用
System.console().readPassword()交互输入 - 收到
javax.mail.AuthenticationFailedException: 535-5.7.8 Username and Password not accepted时,90% 是密码错或未开应用专用密码
真正跑通收发,关键不在写多少行代码,而在确认每层协议(DNS 解析、TCP 连接、TLS 握手、SMTP/IMAP 认证)是否逐级通过。卡住时优先查网络和账号设置,而不是重写 Java 逻辑。









