Java 11+ 必须用 jakarta.mail,javax.mail 已废弃;务必用 Session.getInstance(),禁用 getDefaultInstance();QQ/163 邮箱需开 SMTP 并用授权码;HTML/附件邮件须显式设 UTF-8 编码且 setContent 后不可再调用 setSubject 等方法。

Java 发送邮件必须引入 javax.mail 还是 jakarta.mail?
Java 11+ 项目不能再用 javax.mail:mail(已废弃),必须迁移到 jakarta.mail:jakarta.mail-api + com.sun.mail:jakarta.mail。Maven 依赖要写对,否则运行时抛 NoClassDefFoundError: javax/mail/Session。
- Java 8–10:可用
com.sun.mail:javax.mail:1.6.2 - Java 11 及以上:必须用
jakarta.mail:jakarta.mail-api:2.1.3+com.sun.mail:jakarta.mail:2.1.3 - Spring Boot 3.x 默认集成的是 Jakarta 版,若手动配置
JavaMailSender,bean 的类型也得是jakarta.mail.Session
用 Session.getInstance() 还是 Session.getDefaultInstance()?
永远用 Session.getInstance(props, auth)。后者已被弃用,且在多线程下可能复用错误的认证信息,导致发信失败或混用账号。
Properties props = new Properties();
props.put("mail.smtp.host", "smtp.qq.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("your@qq.com", "your-app-password");
}
});
QQ 邮箱 / 163 邮箱发信失败常见原因
不是密码错了,而是没开对权限或填错端口/协议。重点检查以下几项:
- QQ 邮箱必须开启「SMTP服务」并生成「授权码」,不能用登录密码;163 同理,且授权码需在「POP3/SMTP/IMAP」设置页单独开启
- QQ 邮箱推荐用
smtp.qq.com+ 端口587+starttls;若用465端口,得改用mail.smtp.ssl.enable=true,且协议名要设为smtps - 发送方邮箱地址必须和
PasswordAuthentication中第一个参数严格一致(区分大小写) - 部分企业网络会屏蔽 25/465/587 端口,可先用 telnet 测试连通性:
telnet smtp.qq.com 587
发送带附件或 HTML 内容的邮件怎么写才不乱码?
关键在两处编码设置:一是 MimeMessage 构造时指定字符集,二是 MimeBodyPart 设置 setText(..., "UTF-8") 或 setDataHandler(...) 时明确 MIME 类型。
立即学习“Java免费学习笔记(深入)”;
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("from@qq.com"));
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse("to@example.com"));
message.setSubject("测试邮件", "UTF-8"); // ← 主题必须声明 UTF-8
MimeMultipart multipart = new MimeMultipart("related");
// HTML 正文
MimeBodyPart htmlPart = new MimeBodyPart();
htmlPart.setContent("你好
@@##@@", "text/html;charset=UTF-8");
multipart.addBodyPart(htmlPart);
// 内嵌图片
MimeBodyPart imgPart = new MimeBodyPart();
imgPart.attachFile("/path/logo.png");
imgPart.setHeader("Content-ID", "logo");
multipart.addBodyPart(imgPart);
message.setContent(multipart);
附件同理:用 setFileName(...) 并确保文件名用 MimeUtility.encodeText() 处理中文,否则 Outlook 里显示乱码。
真正容易被忽略的是:setContent() 后不能再调用 setSubject() 或 setFrom(),否则部分 SMTP 服务器会静默丢弃整封邮件——这个行为没有报错,但收件方根本收不到。










