上一篇
java 怎么实现邮件发送
- 后端开发
- 2025-08-07
- 4
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