上一篇
java 怎么实现邮件发送
- 后端开发
- 2025-08-07
- 38
Java可通过JavaMail API实现邮件发送,需配置SMTP服务器参数,创建会话及邮件对象后
技术原理与前置条件
1 核心机制
邮件发送基于 SMTP(Simple Mail Transfer Protocol) 协议,其工作流程为:
- 客户端(Java程序)→ 建立TCP连接至SMTP服务器(默认端口25/465/587);
- 身份验证(用户名+密码/OAuth2);
- 构造邮件内容(含头部字段+正文/附件);
- 服务器接收并转发至目标邮箱。
| 要素 | 说明 |
|---|---|
| 发件人 | 需真实存在的有效邮箱账号 |
| 收件人 | 支持单人/多人/抄送/密送 |
| 邮件服务器 | 根据服务商选择(如Exchange、Postfix、云服务厂商) |
| 安全层 | SSL/TLS加密(推荐端口465或587),明文传输已逐渐被淘汰 |
| 第三方库 | JavaMail API(现称 Jakarta Mail),底层依赖 javax.mail JAR包 |
2 环境准备
- JDK版本:≥8(兼容新版JavaMail)
- 依赖引入:Maven项目中添加以下依赖:
<dependency> <groupId>com.sun.mail</groupId> <artifactId>javax.mail</artifactId> <version>1.6.2</version> </dependency> - 服务器配置:获取目标邮箱的SMTP服务器地址及端口(例:QQ邮箱 smtp.qq.com:465,阿里云邮箱 smtp.aliyun.com:465)。
分步实现详解
1 基础配置项解析
通过 Properties 对象定义邮件会话参数,关键属性如下表所示:

| 属性名 | 示例值 | 作用 |
|---|---|---|
mail.smtp.host |
smtp.example.com | 指定SMTP服务器域名 |
mail.smtp.port |
465 | SMTP服务端口(465=SSL, 587=STARTTLS, 25=明文) |
mail.smtp.auth |
true | 启用身份验证 |
mail.smtp.ssl.enable |
true | 启用SSL加密(若端口为465必选) |
mail.smtp.timeout |
5000 | 连接超时时间(毫秒) |
mail.smtp.socketFactory.class |
javax.net.ssl.SSLSocketFactory | 强制使用SSL套接字工厂 |
2 核心代码实现(含附件)
以下为完整可运行的示例代码,包含纯文本、HTML内容及文件附件:
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.;
import javax.mail.internet.;
import java.util.Date;
import java.util.Properties;
public class EmailSender {
public static void main(String[] args) throws Exception {
// ========== 1. 配置会话属性 ==========
Properties props = new Properties();
props.put("mail.smtp.host", "smtp.example.com"); // 替换为你的SMTP服务器
props.put("mail.smtp.port", "465"); // SSL端口
props.put("mail.smtp.auth", "true"); // 启用认证
props.put("mail.smtp.ssl.enable", "true"); // 启用SSL
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); // 关键!
// ========== 2. 创建会话对象 ==========
Session session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("your_email@example.com", "your_password"); // 替换为你的邮箱和密码
}
});
session.setDebug(true); // 开启调试日志(生产环境建议关闭)
// ========== 3. 构建邮件消息 ==========
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress("your_email@example.com")); // 发件人
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse("recipient@example.com")); // 收件人
message.setSubject("Java邮件测试 " + new Date()); // 主题+时间戳
// 创建多部分容器(支持混合内容)
Multipart multipart = new MimeMultipart();
// 添加文本部分(可选HTML)
BodyPart textPart = new MimeBodyPart();
textPart.setContent("<h1>这是一封测试邮件</h1><p>当前时间:" + new Date() + "</p>", "text/html;charset=UTF-8");
multipart.addBodyPart(textPart);
// 添加附件(示例:上传本地文件)
BodyPart attachmentPart = new MimeBodyPart();
FileDataSource fds = new FileDataSource("C:\test.pdf"); // 替换为你的文件路径
attachmentPart.setDataHandler(new DataHandler(fds));
attachmentPart.setFileName(MimeUtility.encodeText("测试附件.pdf")); // 处理中文文件名乱码
multipart.addBodyPart(attachmentPart);
// 将多部分内容设置到邮件中
message.setContent(multipart);
message.setSentDate(new Date()); // 设置发送时间
// ========== 4. 发送邮件 ==========
Transport.send(message);
System.out.println("邮件发送成功!");
}
}
3 关键细节说明
- 中文乱码解决:对主题、文件名等非ASCII字符需使用
MimeUtility.encodeText()进行Base64编码。 - 大文件附件优化:若附件超过10MB,建议分块读取或使用流式处理避免内存溢出。
- 异步发送:可通过
Transport.send(message, new SendHandler())结合线程池实现异步发送,提升性能。 - 特殊字符转义:在HTML内容中,
<、>、&等符号需转义为<、>、&。
常见问题与解决方案
1 典型错误排查表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
Authentication failed |
账号/密码错误或未开启SMTP服务 | 检查邮箱设置,部分服务商需生成授权码 |
Connection refused |
防火墙拦截或端口错误 | 确认端口开放(如465/587),关闭代理软件 |
Timeout occurred |
网络延迟或服务器响应慢 | 增加 mail.smtp.timeout 值至10秒以上 |
| 附件显示为临时文件名 | 未正确设置 setFileName() |
使用 MimeUtility.encodeText() 包装文件名 |
| 收到空邮件 | 未正确设置邮件内容类型 | 检查 setContentType() 和编码格式 |
2 主流邮箱服务商特殊要求
| 服务商 | SMTP服务器 | 推荐端口 | 注意事项 |
|---|---|---|---|
| Gmail | smtp.gmail.com | 465/587 | 需开启“允许不够安全的应用”,或使用OAuth2 |
| Outlook | smtp.office365.com | 587 | 需开启双重验证并创建应用密码 |
| QQ邮箱 | smtp.qq.com | 465 | 需在邮箱设置中开启SMTP服务 |
| 阿里云邮箱 | smtp.aliyun.com | 465 | 需在控制台开通SMTP服务并获取授权码 |
扩展功能建议
- 模板引擎集成:结合Thymeleaf/FreeMarker实现动态邮件模板。
- 日志记录:记录发送状态(成功/失败)、耗时、错误信息至数据库。
- 重试机制:对临时性失败(如网络波动)进行指数退避重试。
- 批量发送优化:使用
Transport.send(message, addressList)批量发送,减少连接次数。 - DKIM签名:通过
message.saveChanges()+ 自定义DKIM头增强防垃圾邮件能力。
FAQs
Q1: 为什么我的程序能连接SMTP服务器但无法发送邮件?
A: 常见原因包括:① 发件人邮箱未在服务商处开通SMTP服务;② 账号密码错误(注意部分服务商要求使用应用专用密码而非登录密码);③ 邮件内容被判定为垃圾邮件(尝试简化内容或添加SPF/DKIM记录),建议开启调试日志(session.setDebug(true))查看详细错误信息。

Q2: 如何发送带有内嵌图片的HTML邮件?
A: 需将图片作为CIMG类型附件嵌入,步骤:① 将图片文件转为Base64编码;② 在HTML中使用 <img src="cid:imageId">;③ 创建 MimeBodyPart 并设置 ContentID 为 imageId,示例代码片段:
// 图片部分
BodyPart imagePart = new MimeBodyPart();
imagePart.setDataHandler(new DataHandler(new FileDataSource("logo.png")));
imagePart.setHeader("Content-ID", "<logo>"); // 与HTML中的cid对应
multipart.addBody

