0%

邮件带附件发送

带附件邮件发送全指南:基于 Spring 与 Apache Commons Email 的实现

在日常开发中,带附件的邮件发送是常见需求(如报表推送、文件共享等)。本文将详细讲解两种实现方式:Spring 的 MimeMessageHelper(适合 Spring 生态项目)和 Apache Commons Email(通用 Java 项目),包括依赖配置、核心代码、参数说明及常见问题解决,帮助你快速集成邮件附件功能。

技术选型对比

实现方式 优势 适用场景
Spring MimeMessageHelper 与 Spring 无缝集成,API 简洁,支持 HTML 内容 Spring Boot/SSM 项目
Apache Commons Email 轻量级,无 Spring 依赖,配置灵活 非 Spring 项目或简单 Java 应用

Spring 方式:使用 MimeMessageHelper

依赖配置

需引入 Spring 邮件相关依赖(适用于 Spring 项目):

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- Spring 邮件支持 -->  
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.29.RELEASE</version> <!-- 版本需与项目 Spring 版本匹配 -->
</dependency>

<!-- JavaMail 核心依赖 -->
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>

核心代码实现

MimeMessageHelper 是 Spring 提供的邮件辅助类,支持附件、HTML 内容等功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import org.springframework.mail.javamail.JavaMailSenderImpl;  
import org.springframework.mail.javamail.MimeMessageHelper;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
import java.util.Properties;

public class SpringMailWithAttachment {

/**
* 发送带附件的邮件
* @param host SMTP 服务器地址(如 QQ 邮箱:smtp.qq.com)
* @param port SMTP 端口(如 QQ 邮箱:587)
* @param username 发件人邮箱账号
* @param password 发件人密码(或授权码,如 QQ 邮箱需用授权码)
* @param to 收件人邮箱(多个用逗号分隔)
* @param cc 抄送人邮箱(可选)
* @param subject 邮件标题
* @param content 邮件内容(支持 HTML)
* @param attachment 附件文件(可选)
* @return 发送成功返回 true
*/
public static boolean sendWithAttachment(String host, int port, String username, String password,
String to, String cc, String subject, String content,
File attachment) {
// 1. 配置邮件发送器
JavaMailSenderImpl sender = new JavaMailSenderImpl();
sender.setHost(host); // SMTP 服务器
sender.setPort(port); // 端口
sender.setUsername(username); // 发件人账号
sender.setPassword(password); // 密码/授权码
sender.setDefaultEncoding("UTF-8"); // 编码

// 2. 配置 SMTP properties(根据邮箱服务商要求调整)
Properties props = sender.getJavaMailProperties();
props.put("mail.smtp.auth", "true"); // 开启认证
props.put("mail.smtp.starttls.enable", "true"); // 启用 TLS(如 QQ、Gmail 需开启)
props.put("mail.debug", "false"); // 调试模式(可选,true 会打印发送日志)

try {
// 3. 创建 MIME 消息(支持附件和 HTML)
MimeMessage mimeMessage = sender.createMimeMessage();
// 第二个参数设为 true,表示支持多部分内容(附件、HTML 等)
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "UTF-8");

// 4. 设置邮件基本信息
helper.setFrom(username); // 发件人
helper.setTo(to.split(",")); // 收件人(支持多个)
if (cc != null && !cc.isEmpty()) {
helper.setCc(cc.split(",")); // 抄送人
}
helper.setSubject(subject); // 标题
// 第二个参数设为 true,表示内容为 HTML 格式
helper.setText(content, true);

// 5. 添加附件(如果存在)
if (attachment != null && attachment.exists()) {
// 第一个参数:附件显示名称(可自定义);第二个参数:附件文件
helper.addAttachment(attachment.getName(), attachment);
}

// 6. 发送邮件
sender.send(mimeMessage);
System.out.println("邮件发送成功!");
return true;

} catch (MessagingException e) {
System.err.println("邮件发送失败:" + e.getMessage());
e.printStackTrace();
return false;
}
}

// 测试方法
public static void main(String[] args) {
// 示例:发送带附件的邮件(以 QQ 企业邮箱为例)
String host = "smtp.exmail.qq.com"; // QQ 企业邮箱 SMTP
int port = 587;
String username = "sender@example.com"; // 发件人邮箱
String password = "yourAuthCode"; // 授权码(非登录密码)
String to = "receiver@example.com"; // 收件人
String cc = "cc@example.com"; // 抄送人
String subject = "测试带附件的邮件";
String content = "<h1>这是一封带附件的测试邮件</h1><p>请查收附件内容</p>";
File attachment = new File("/Users/example/测试附件.pdf"); // 附件路径

sendWithAttachment(host, port, username, password, to, cc, subject, content, attachment);
}
}

关键参数说明

  • SMTP 服务器与端口:不同邮箱服务商的配置不同(见下表);
  • 授权码:多数邮箱(如 QQ、163)需开启 SMTP 服务并生成授权码,而非使用登录密码;
  • 附件处理addAttachment 方法可多次调用添加多个附件,第一个参数为附件在邮件中显示的名称(可自定义)。
邮箱服务商 SMTP 服务器 端口 备注
QQ 邮箱 smtp.qq.com 587 需开启 SMTP 并获取授权码
163 邮箱 smtp.163.com 25 需开启 SMTP 服务
企业微信 smtp.exmail.qq.com 587 用企业邮箱账号和密码
Gmail smtp.gmail.com 587 需开启 TLS 和两步验证

通用方式:使用 Apache Commons Email

依赖配置

适用于非 Spring 项目,引入 Apache Commons Email:

1
2
3
4
5
<dependency>  
<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
<version>1.5</version> <!-- 稳定版本 -->
</dependency>

核心代码实现

Commons Email 封装了 JavaMail,API 更简洁:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import org.apache.commons.mail.*;  
import java.io.File;

public class CommonsEmailWithAttachment {

/**
* 发送带附件的邮件(Commons Email 实现)
*/
public static boolean sendWithAttachment(String host, int port, String username, String password,
String to, String cc, String subject, String content,
File attachment) {
try {
// 1. 创建 MIME 邮件实例(支持附件和 HTML)
MultiPartEmail email = new HtmlEmail(); // 若需 HTML 内容,用 HtmlEmail
email.setHostName(host);
email.setSmtpPort(port);
email.setAuthentication(username, password); // 认证
email.setStartTLSEnabled(true); // 启用 TLS
email.setCharset("UTF-8");

// 2. 设置收件人、抄送人
email.addTo(to); // 收件人(可多次调用添加多个)
if (cc != null && !cc.isEmpty()) {
email.addCc(cc); // 抄送人
}
email.setFrom(username); // 发件人
email.setSubject(subject); // 标题

// 3. 设置内容(若为 HTML,需用 HtmlEmail 的 setHtmlMsg 方法)
if (email instanceof HtmlEmail) {
((HtmlEmail) email).setHtmlMsg(content);
// 可选:设置纯文本备选内容(当收件人不支持 HTML 时显示)
((HtmlEmail) email).setTextMsg("您的邮箱不支持 HTML 内容");
} else {
email.setMsg(content); // 纯文本内容
}

// 4. 添加附件
if (attachment != null && attachment.exists()) {
EmailAttachment emailAttachment = new EmailAttachment();
emailAttachment.setPath(attachment.getAbsolutePath()); // 附件路径
emailAttachment.setDisposition(EmailAttachment.ATTACHMENT);
emailAttachment.setName(attachment.getName()); // 附件显示名称
email.attach(emailAttachment);
}

// 5. 发送邮件
email.send();
System.out.println("邮件发送成功!");
return true;

} catch (EmailException e) {
System.err.println("邮件发送失败:" + e.getMessage());
e.printStackTrace();
return false;
}
}

// 测试方法
public static void main(String[] args) {
// 示例:与 Spring 方式参数相同
String host = "smtp.qq.com";
int port = 587;
String username = "your@qq.com";
String password = "yourAuthCode";
String to = "receiver@example.com";
String content = "<h1>Commons Email 测试</h1><p>附件已添加</p>";
File attachment = new File("/Users/example/附件.txt");

sendWithAttachment(host, port, username, password, to, null, "Commons Email 测试", content, attachment);
}
}

与 Spring 方式的区别

  • API 风格:Commons Email 采用链式调用,更接近原生 Java 风格;
  • HTML 支持:需使用 HtmlEmail 子类,而 Spring 的 MimeMessageHelper 通过参数控制;
  • 附件处理:Commons Email 需通过 EmailAttachment 类包装附件信息。

多附件发送与高级配置

发送多个附件

两种方式均可通过多次调用附件添加方法实现多附件发送:

1
2
3
4
5
6
7
// Spring 方式:多次调用 addAttachment  
helper.addAttachment("附件1.pdf", new File("file1.pdf"));
helper.addAttachment("附件2.txt", new File("file2.txt"));

// Commons Email 方式:多次调用 attach
email.attach(attachment1);
email.attach(attachment2);

超大附件处理

若附件体积过大(如 >10MB),直接发送可能超时或被邮箱服务商拒绝,建议:

  • 先将文件上传至云存储(如 OSS、S3),邮件中只包含下载链接;
  • 拆分大文件为多个小文件,分开发送(需在邮件内容中说明)。

异步发送邮件

邮件发送可能耗时(尤其带大附件),建议通过异步方式执行,避免阻塞主线程:

1
2
3
4
5
6
7
8
9
// Spring 异步示例(需开启 @EnableAsync)  
@Async
public void asyncSendEmail(...) {
sendWithAttachment(...);
}

// 通用异步示例(使用线程池)
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.submit(() -> sendWithAttachment(...));

常见问题与解决方案

1. 认证失败(535 错误)

  • 原因:密码或授权码错误,或未开启 SMTP 服务;
  • 解决
    • 检查密码是否正确,多数邮箱需用 授权码(如 QQ 邮箱在 “设置 - 账户” 中开启 SMTP 并生成);
    • 确认邮箱账号是否开启 SMTP 服务(登录邮箱网页版设置)。

2. 附件中文名称乱码

  • 原因:编码设置不当;

  • 解决:确保创建MimeMessageHelper或HtmlEmail时指定UTF-8编码:

1
2
3
4
5
// Spring 方式  
new MimeMessageHelper(mimeMessage, true, "UTF-8");

// Commons Email 方式
email.setCharset("UTF-8");

3. 邮件被标记为垃圾邮件

  • 原因:内容含敏感词、发件人信誉低、HTML 格式不规范;
  • 解决
    • 避免使用 “广告”“优惠” 等敏感词;
    • 内容中增加文本说明,减少纯 HTML 代码;
    • 发件人邮箱提前与收件人邮箱建立联系(如让收件人将发件人加入白名单)。

4. 发送超时

  • 原因:网络不稳定、SMTP 服务器响应慢、附件过大;

  • 解决

    • 增加超时配置:

      1
      2
      3
      // Spring 方式添加超时参数  
      props.put("mail.smtp.connectiontimeout", "5000"); // 连接超时(毫秒)
      props.put("mail.smtp.timeout", "10000"); // 发送超时(毫秒)
    • 优化附件大小(压缩或改用链接)。

欢迎关注我的其它发布渠道