Java: Jdk17 异步或同步或并行发邮件
项目结构:

所需要的包:
<dependencies>
<!-- JavaMail API -->
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!-- Jackson JSON库 -->
<!-- 已有的jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version> <!-- 版本号需统一 -->
</dependency>
<!-- 添加jackson-annotations依赖 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.13.0</version> <!-- 与databind版本一致 -->
</dependency>
<!-- 添加jackson-core依赖(databind也依赖它,保险起见显式声明) -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.13.0</version> <!-- 与databind版本一致 -->
</dependency>
<!-- SLF4J日志框架 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.32</version>
<scope>runtime</scope>
</dependency>
</dependencies>
邮件服务配置: mail-config.json
{
"smtp": {
"host": "smtp.qq.com",
"port": "465",
"auth": true,
"sslEnable": true,
"debug": false
},
"sender": {
"email": "463588883@qq.com",
"password": "your_auth_code",
"name": "邮件发送者"
},
"threadPool": {
"corePoolSize": 5,
"maximumPoolSize": 10,
"keepAliveTime": 60,
"unit": "SECONDS",
"queueCapacity": 100
},
"retry": {
"maxRetries": 3,
"retryDelay": 1000
}
}
/**
* encoding: utf-8
* 版权所有 2025 ©涂聚文有限公司 ®
* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
* 描述:
* Author : geovindu,Geovin Du 涂聚文.
* IDE : IntelliJ IDEA 2024.3.6 Java 17
* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
* # OS : window10
* Datetime : 2025 - 2025/10/27 - 21:07
* User : geovindu
* Product : IntelliJ IDEA
* Project : swingdemo
* File : MailConfig.java
* explain : 学习 类
**/
package com.example.mail.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;
/**
* 邮件配置类
*/
public class MailConfig {
private SmtpConfig smtp;
private SenderConfig sender;
private ThreadPoolConfig threadPool;
private RetryConfig retry;
// 单例实例
private static volatile MailConfig instance;
private MailConfig() {
// 私有构造方法
}
/**
* 获取单例实例
* @return MailConfig实例
*/
public static MailConfig getInstance() {
if (instance == null) {
synchronized (MailConfig.class) {
if (instance == null) {
instance = loadConfig();
}
}
}
return instance;
}
/**
* 从配置文件加载配置
* @return 加载的MailConfig对象
*/
private static MailConfig loadConfig() {
try {
ObjectMapper objectMapper = new ObjectMapper();
InputStream inputStream = MailConfig.class.getClassLoader().getResourceAsStream("mail-config.json");
if (inputStream == null) {
throw new RuntimeException("找不到邮件配置文件 mail-config.json");
}
return objectMapper.readValue(inputStream, MailConfig.class);
} catch (Exception e) {
throw new RuntimeException("加载邮件配置文件失败", e);
}
}
// Getters
public SmtpConfig getSmtp() {
return smtp;
}
public SenderConfig getSender() {
return sender;
}
public ThreadPoolConfig getThreadPool() {
return threadPool;
}
public RetryConfig getRetry() {
return retry;
}
/**
* SMTP配置
*/
public static class SmtpConfig {
private String host;
private String port;
private boolean auth;
private boolean sslEnable;
private boolean debug;
// Getters
public String getHost() {
return host;
}
public String getPort() {
return port;
}
public boolean isAuth() {
return auth;
}
public boolean isSslEnable() {
return sslEnable;
}
public boolean isDebug() {
return debug;
}
}
/**
* 发送者配置
*/
public static class SenderConfig {
private String email;
private String password;
private String name;
// Getters
public String getEmail() {
return email;
}
public String getPassword() {
return password;
}
public String getName() {
return name;
}
}
/**
* 线程池配置
*/
public static class ThreadPoolConfig {
private int corePoolSize;
private int maximumPoolSize;
private long keepAliveTime;
private String unit;
private int queueCapacity;
// Getters
public int getCorePoolSize() {
return corePoolSize;
}
public int getMaximumPoolSize() {
return maximumPoolSize;
}
public long getKeepAliveTime() {
return keepAliveTime;
}
public TimeUnit getUnit() {
return TimeUnit.valueOf(unit);
}
public int getQueueCapacity() {
return queueCapacity;
}
}
/**
* 重试配置
*/
public static class RetryConfig {
private int maxRetries;
private long retryDelay;
// Getters
public int getMaxRetries() {
return maxRetries;
}
public long getRetryDelay() {
return retryDelay;
}
}
}
/**
* encoding: utf-8
* 版权所有 2025 ©涂聚文有限公司 ®
* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
* 描述:
* Author : geovindu,Geovin Du 涂聚文.
* IDE : IntelliJ IDEA 2024.3.6 Java 17
* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
* # OS : window10
* Datetime : 2025 - 2025/10/27 - 21:16
* User : geovindu
* Product : IntelliJ IDEA
* Project : swingdemo
* File : MailCallback.java
* explain : 学习 类
**/
package com.example.mail.core;
/**
* 邮件发送回调接口
*/
public interface MailCallback {
/**
* 邮件发送成功回调
* @param message 发送的邮件消息
* @param duration 发送耗时(毫秒)
*/
void onSuccess(MailMessage message, long duration);
/**
* 邮件发送失败回调
* @param message 发送的邮件消息
* @param throwable 失败原因
*/
void onFailure(MailMessage message, Throwable throwable);
}
/**
* encoding: utf-8
* 版权所有 2025 ©涂聚文有限公司 ®
* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
* 描述:
* Author : geovindu,Geovin Du 涂聚文.
* IDE : IntelliJ IDEA 2024.3.6 Java 17
* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
* # OS : window10
* Datetime : 2025 - 2025/10/27 - 21:17
* User : geovindu
* Product : IntelliJ IDEA
* Project : swingdemo
* File : MailMessage.java
* explain : 学习 类
**/
package com.example.mail.core;
import java.io.File;
/**
* 邮件消息类,封装邮件内容
*/
public class MailMessage {
private String[] to;
private String[] cc;
private String[] bcc;
private String subject;
private String content;
private boolean html;
private File[] attachments;
// 私有构造方法,通过Builder创建
private MailMessage(Builder builder) {
this.to = builder.to;
this.cc = builder.cc;
this.bcc = builder.bcc;
this.subject = builder.subject;
this.content = builder.content;
this.html = builder.html;
this.attachments = builder.attachments;
}
// Getters
public String[] getTo() {
return to;
}
public String[] getCc() {
return cc;
}
public String[] getBcc() {
return bcc;
}
public String getSubject() {
return subject;
}
public String getContent() {
return content;
}
public boolean isHtml() {
return html;
}
public File[] getAttachments() {
return attachments;
}
/**
* 邮件消息构建器
*/
public static class Builder {
private String[] to;
private String[] cc;
private String[] bcc;
private String subject;
private String content;
private boolean html = false;
private File[] attachments;
/**
* 设置收件人
* @param to 收件人邮箱数组
* @return Builder
*/
public Builder to(String... to) {
this.to = to;
return this;
}
/**
* 设置抄送
* @param cc 抄送邮箱数组
* @return Builder
*/
public Builder cc(String... cc) {
this.cc = cc;
return this;
}
/**
* 设置密送
* @param bcc 密送邮箱数组
* @return Builder
*/
public Builder bcc(String... bcc) {
this.bcc = bcc;
return this;
}
/**
* 设置邮件主题
* @param subject 邮件主题
* @return Builder
*/
public Builder subject(String subject) {
this.subject = subject;
return this;
}
/**
* 设置邮件内容
* @param content 邮件内容
* @return Builder
*/
public Builder content(String content) {
this.content = content;
return this;
}
/**
* 设置是否为HTML邮件
* @param html 是否为HTML邮件
* @return Builder
*/
public Builder html(boolean html) {
this.html = html;
return this;
}
/**
* 设置附件
* @param attachments 附件文件数组
* @return Builder
*/
public Builder attachments(File... attachments) {
this.attachments = attachments;
return this;
}
/**
* 构建MailMessage对象
* @return MailMessage
*/
public MailMessage build() {
if (to == null || to.length == 0) {
throw new IllegalArgumentException("收件人不能为空");
}
if (subject == null || subject.trim().isEmpty()) {
throw new IllegalArgumentException("邮件主题不能为空");
}
if (content == null || content.trim().isEmpty()) {
throw new IllegalArgumentException("邮件内容不能为空");
}
return new MailMessage(this);
}
}
}
/**
* encoding: utf-8
* 版权所有 2025 ©涂聚文有限公司 ®
* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
* 描述:
* Author : geovindu,Geovin Du 涂聚文.
* IDE : IntelliJ IDEA 2024.3.6 Java 17
* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
* # OS : window10
* Datetime : 2025 - 2025/10/27 - 21:17
* User : geovindu
* Product : IntelliJ IDEA
* Project : swingdemo
* File : MailSender.java
* explain : 学习 类
**/
package com.example.mail.core;
import com.example.mail.config.MailConfig;
import com.example.mail.exception.MailException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.util.Properties;
import java.util.concurrent.*;
import java.util.stream.Collectors;
/**
* 邮件发送工具类
*/
public class MailSender {
private static final Logger logger = LoggerFactory.getLogger(MailSender.class);
private static final MailConfig config = MailConfig.getInstance();
private static final ExecutorService executorService;
static {
// 初始化线程池
MailConfig.ThreadPoolConfig threadPoolConfig = config.getThreadPool();
executorService = new ThreadPoolExecutor(
threadPoolConfig.getCorePoolSize(),
threadPoolConfig.getMaximumPoolSize(),
threadPoolConfig.getKeepAliveTime(),
threadPoolConfig.getUnit(),
new LinkedBlockingQueue<>(threadPoolConfig.getQueueCapacity()),
new ThreadPoolExecutor.CallerRunsPolicy()
);
}
/**
* 同步发送邮件
* @param message 邮件消息
* @throws MailException 邮件发送异常
*/
public static void send(MailMessage message) throws MailException {
long startTime = System.currentTimeMillis();
try {
doSend(message);
long duration = System.currentTimeMillis() - startTime;
logger.info("邮件同步发送成功,收件人: {}, 耗时: {}ms",
String.join(",",message.getTo()), duration);
} catch (MessagingException e) {
logger.error("邮件同步发送失败,收件人: {}",
String.join(",", message.getTo()), e);
throw new MailException("邮件发送失败", e);
}
}
/**
* 异步发送邮件
* @param message 邮件消息
* @return Future对象,可用于获取发送结果
*/
public static Future<Boolean> sendAsync(MailMessage message) {
return executorService.submit(() -> {
long startTime = System.currentTimeMillis();
try {
doSend(message);
long duration = System.currentTimeMillis() - startTime;
logger.info("邮件异步发送成功,收件人: {}, 耗时: {}ms",
String.join(",", message.getTo()), duration);
return true;
} catch (MessagingException e) {
logger.error("邮件异步异步发送失败,收件人: {}",
String.join(",", message.getTo()), e);
return false;
}
});
}
/**
* 异步发送邮件(带回调)
* @param message 邮件消息
* @param callback 回调接口
*/
public static void sendAsync(MailMessage message, MailCallback callback) {
executorService.submit(() -> {
long startTime = System.currentTimeMillis();
try {
doSend(message);
long duration = System.currentTimeMillis() - startTime;
logger.info("邮件异步发送成功,收件人: {}, 耗时: {}ms",
String.join(",", message.getTo()), duration);
if (callback != null) {
callback.onSuccess(message, duration);
}
} catch (MessagingException e) {
logger.error("邮件异步发送失败,收件人: {}",
String.join(",", message.getTo()), e);
if (callback != null) {
callback.onFailure(message, e);
}
}
});
}
/**
* 并行发送多封邮件
* @param messages 邮件消息列表
* @return CompletableFuture,可用于获取所有邮件的发送结果
*/
public static CompletableFuture<java.util.List<Boolean>> sendParallel(java.util.List<MailMessage> messages) {
java.util.List<CompletableFuture<Boolean>> futures = messages.stream()
.map(message -> CompletableFuture.supplyAsync(() -> {
long startTime = System.currentTimeMillis();
try {
doSend(message);
long duration = System.currentTimeMillis() - startTime;
logger.info("邮件并行发送成功,收件人: {}, 耗时: {}ms",
String.join(",", message.getTo()), duration);
return true;
} catch (MessagingException e) {
logger.error("邮件并行发送失败,收件人: {}",
String.join(",", message.getTo()), e);
return false;
}
}, executorService))
.collect(Collectors.toList());
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.thenApply(v -> futures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList()));
}
/**
* 批量发送邮件(同一内容,多个收件人)
* @param to 收件人数组
* @param subject 邮件主题
* @param content 邮件内容
* @param attachments 附件数组
* @return CompletableFuture,可用于获取发送结果
*/
public static CompletableFuture<Boolean> sendBatch(String[] to, String subject, String content, java.io.File[] attachments) {
MailMessage message = new MailMessage.Builder()
.to(to)
.subject(subject)
.content(content)
.attachments(attachments)
.build();
return CompletableFuture.supplyAsync(() -> {
long startTime = System.currentTimeMillis();
try {
doSend(message);
long duration = System.currentTimeMillis() - startTime;
logger.info("邮件批量发送成功,收件人数量: {}, 耗时: {}ms",
to.length, duration);
return true;
} catch (MessagingException e) {
logger.error("邮件批量发送失败,收件人数量: {}",
to.length, e);
return false;
}
}, executorService);
}
/**
* 实际发送邮件的内部方法
* @param message 邮件消息
* @throws MessagingException 邮件发送异常
*/
private static void doSend(MailMessage message) throws MessagingException {
// 获取SMTP配置
MailConfig.SmtpConfig smtpConfig = config.getSmtp();
MailConfig.SenderConfig senderConfig = config.getSender();
MailConfig.RetryConfig retryConfig = config.getRetry();
// 创建Properties对象
Properties props = new Properties();
props.put("mail.smtp.host", smtpConfig.getHost());
props.put("mail.smtp.port", smtpConfig.getPort());
props.put("mail.smtp.auth", smtpConfig.isAuth());
props.put("mail.smtp.ssl.enable", smtpConfig.isSslEnable());
props.put("mail.debug", smtpConfig.isDebug());
// 创建Session对象
Session session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(
senderConfig.getEmail(),
senderConfig.getPassword()
);
}
});
// 创建MimeMessage对象
MimeMessage mimeMessage = new MimeMessage(session);
try {
mimeMessage.setFrom(new InternetAddress(senderConfig.getEmail(), senderConfig.getName()));
} catch (java.io.UnsupportedEncodingException e) {
logger.error("设置发件人名称编码失败", e);
throw new MessagingException("设置发件人失败", e);
}
// 设置收件人
if (message.getTo() != null && message.getTo().length > 0) {
mimeMessage.setRecipients(Message.RecipientType.TO,
InternetAddress.parse(String.join(",", message.getTo())));
}
// 设置抄送
if (message.getCc() != null && message.getCc().length > 0) {
mimeMessage.setRecipients(Message.RecipientType.CC,
InternetAddress.parse(String.join(",", message.getCc())));
}
// 设置密送
if (message.getBcc() != null && message.getBcc().length > 0) {
mimeMessage.setRecipients(Message.RecipientType.BCC,
InternetAddress.parse(String.join(",", message.getBcc())));
}
// 设置主题
mimeMessage.setSubject(message.getSubject(), "UTF-8");
// 创建Multipart对象
Multipart multipart = new MimeMultipart();
// 创建邮件正文部分
MimeBodyPart contentPart = new MimeBodyPart();
contentPart.setContent(message.getContent(),
message.isHtml() ? "text/html;charset=UTF-8" : "text/plain;charset=UTF-8");
multipart.addBodyPart(contentPart);
// 添加附件
if (message.getAttachments() != null && message.getAttachments().length > 0) {
for (java.io.File attachment : message.getAttachments()) {
if (attachment.exists() && attachment.isFile()) {
MimeBodyPart attachmentPart = new MimeBodyPart();
FileDataSource dataSource = new FileDataSource(attachment);
attachmentPart.setDataHandler(new DataHandler(dataSource));
try {
attachmentPart.setFileName(javax.mail.internet.MimeUtility.encodeWord(attachment.getName()));
} catch (java.io.UnsupportedEncodingException e) {
logger.error("附件文件名编码失败: {}", attachment.getName(), e);
throw new MessagingException("设置附件文件名失败", e);
}
multipart.addBodyPart(attachmentPart);
} else {
logger.warn("附件不存在或不是文件: {}", attachment.getAbsolutePath());
}
}
}
// 设置邮件内容
mimeMessage.setContent(multipart);
// 发送邮件(带重试机制)
int retryCount = 0;
while (true) {
try {
Transport.send(mimeMessage);
break;
} catch (MessagingException e) {
if (retryCount < retryConfig.getMaxRetries()) {
retryCount++;
logger.warn("邮件发送失败,正在重试第 {} 次...", retryCount, e);
try {
Thread.sleep(retryConfig.getRetryDelay());
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw e;
}
} else {
logger.error("邮件发送失败,已达到最大重试次数: {}", retryConfig.getMaxRetries(), e);
throw e;
}
}
}
}
/**
* 关闭线程池
*/
public static void shutdown() {
executorService.shutdown();
try {
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
}
logger.info("邮件发送线程池已关闭");
}
}
/**
* encoding: utf-8
* 版权所有 2025 ©涂聚文有限公司 ®
* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
* 描述:
* Author : geovindu,Geovin Du 涂聚文.
* IDE : IntelliJ IDEA 2024.3.6 Java 17
* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
* # OS : window10
* Datetime : 2025 - 2025/10/27 - 21:18
* User : geovindu
* Product : IntelliJ IDEA
* Project : swingdemo
* File : MailException.java
* explain : 学习 类
**/
package com.example.mail.exception;
/**
* 邮件发送异常类
*/
public class MailException extends Exception {
private static final long serialVersionUID = 1L;
/**
* 错误码
*/
private String errorCode;
/**
* 构造方法
* @param message 错误消息
*/
public MailException(String message) {
super(message);
}
/**
* 构造方法
* @param message 错误消息
* @param cause 异常原因
*/
public MailException(String message, Throwable cause) {
super(message, cause);
}
/**
* 构造方法
* @param errorCode 错误码
* @param message 错误消息
*/
public MailException(String errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
/**
* 构造方法
* @param errorCode 错误码
* @param message 错误消息
* @param cause 异常原因
*/
public MailException(String errorCode, String message, Throwable cause) {
super(message, cause);
this.errorCode = errorCode;
}
// Getter
public String getErrorCode() {
return errorCode;
}
}
调用:
/**
*
* @param args
*/
public static void main(String[] args) {
//sendEmail();
try {
// 直接加载配置,验证是否成功
MailConfig config = MailConfig.getInstance();
System.out.println("SMTP主机: " + config.getSmtp().getHost());
System.out.println("发送者邮箱: " + config.getSender().getEmail());
} catch (Exception e) {
e.printStackTrace(); // 打印具体异常原因
}
try {
// 测试同步发送邮件
testSyncSend();
// 测试异步发送邮件
testAsyncSend();
// 测试并行发送邮件
testParallelSend();
// 测试批量发送邮件
testBatchSend();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭线程池
MailSender.shutdown();
}
// 初始化依赖
//var userRepository = new InMemoryUserRepository();
//var loginService = new LoginApplicationService(userRepository);
// 启动应用 - 显示登录窗口
//javax.swing.SwingUtilities.invokeLater(() -> new LoginWindow(loginService));
//System.out.println("Hello, World!");
}
/**
* 测试同步发送邮件
*/
private static void testSyncSend() {
System.out.println("=== 测试同步发送邮件 ===");
try {
MailMessage message = new MailMessage.Builder()
.to("geovindu@163.com")
.subject("测试同步发送邮件")
.content("这是一封测试同步发送的邮件")
//.attachments()
.html(false)
.build();
MailSender.send(message);
System.out.println("同步发送邮件成功");
} catch (MailException e) {
System.err.println("同步发送邮件失败: " + e.getMessage());
}
System.out.println();
}
/**
* 测试异步发送邮件
*/
private static void testAsyncSend() throws InterruptedException, ExecutionException {
System.out.println("=== 测试异步发送邮件 ===");
MailMessage message = new MailMessage.Builder()
.to("geovindu@163.com")
.subject("测试异步发送邮件")
.content("这是一封测试异步发送的邮件")
//.attachments()
.html(false)
.build();
Future<Boolean> future = MailSender.sendAsync(message);
System.out.println("异步发送邮件任务已提交");
// 等待发送完成并获取结果
Boolean result = future.get();
System.out.println("异步发送邮件结果: " + (result ? "成功" : "失败"));
System.out.println();
}
/**
* 测试并行发送邮件
*/
private static void testParallelSend() throws InterruptedException, ExecutionException {
System.out.println("=== 测试并行发送邮件 ===");
MailMessage message1 = new MailMessage.Builder()
.to("geovindu@163.com")
.subject("测试并行发送邮件 1")
.content("这是第一封测试并行发送的邮件")
.html(false)
//.attachments()
.build();
MailMessage message2 = new MailMessage.Builder()
.to("413265257@qq.com")
.subject("测试并行发送邮件 2")
.content("这是第二封测试并行发送的邮件")
.html(false)
//.attachments()
.build();
MailMessage message3 = new MailMessage.Builder()
.to("geovindu@hotmial.com")
.subject("测试并行发送邮件 3")
.content("这是第三封测试并行发送的邮件")
.html(false)
//.attachments()
.build();
List<MailMessage> messages = Arrays.asList(message1, message2, message3);
System.out.println("并行发送邮件任务已提交");
// 等待所有邮件发送完成并获取结果
List<Boolean> results = MailSender.sendParallel(messages).get();
long successCount = results.stream().filter(Boolean::booleanValue).count();
System.out.println("并行发送邮件完成,成功: " + successCount + ", 失败: " + (results.size() - successCount));
System.out.println();
}
/**
* 测试批量发送邮件
*/
private static void testBatchSend() throws InterruptedException, ExecutionException {
System.out.println("=== 测试批量发送邮件 ===");
String[] to = {"413265257@qq.com", "geovindu@hotmial.com", "geovindu@163.com"};
String subject = "测试批量发送邮件";
String content = "这是一封测试批量发送的邮件";
// 可以添加附件测试
//File[] attachments = {new File("test.txt"), new File("test.pdf")};
System.out.println("批量发送邮件任务已提交");
// 等待发送完成并获取结果
Boolean result = MailSender.sendBatch(to, subject, content, null).get(); // null attachments
System.out.println("批量发送邮件结果: " + (result ? "成功" : "失败"));
System.out.println();
}
输出:


import com.example.mail.core.MailSender;
import com.example.mail.core.MailMessage;
import com.example.mail.core.Attachment;
import com.example.mail.exception.MailException;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
public class MailAttachmentTest {
// 测试附件路径(resources/attachments下的文件)
private static final String ATTACHMENT_DIR = "attachments/";
private static final String TEXT_FILE = ATTACHMENT_DIR + "test.txt"; // 文本附件
private static final String IMAGE_FILE = ATTACHMENT_DIR + "image.png"; // 图片附件
private static final String PDF_FILE = ATTACHMENT_DIR + "document.pdf"; // PDF附件
// 测试收件人(替换为实际测试邮箱)
private static final String TEST_RECIPIENT = "test@example.com";
private static final List<String> TEST_RECIPIENTS = Arrays.asList(
"test1@example.com", "test2@example.com", "test3@example.com"
);
public static void main(String[] args) {
try {
System.out.println("=== 开始测试同步发送带附件邮件 ===");
testSyncWithAttachments();
System.out.println("\n=== 开始测试异步发送带附件邮件 ===");
testAsyncWithAttachments();
System.out.println("\n=== 开始测试并行发送带附件邮件 ===");
testParallelWithAttachments();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 测试同步发送带附件邮件(单个附件 + 多个附件)
*/
public static void testSyncWithAttachments() throws MailException {
// 1. 测试同步发送:单个文本附件
MailMessage singleAttachmentMsg = MailMessage.builder()
.to(TEST_RECIPIENT)
.subject("【同步测试】带单个文本附件的邮件")
.content("<h1>这是一封同步发送的带单个文本附件的测试邮件</h1>")
.attachment(getAttachment(TEXT_FILE)) // 添加单个附件
.build();
boolean singleSuccess = MailSender.sendEmailSync(singleAttachmentMsg);
System.out.println("同步发送单个附件结果:" + (singleSuccess ? "成功" : "失败"));
// 2. 测试同步发送:多个不同类型附件
MailMessage multiAttachmentsMsg = MailMessage.builder()
.to(TEST_RECIPIENT)
.subject("【同步测试】带多个附件的邮件(文本+图片+PDF)")
.content("<h1>这是一封同步发送的带多个附件的测试邮件</h1>")
.attachments(Arrays.asList( // 添加多个附件
getAttachment(TEXT_FILE),
getAttachment(IMAGE_FILE),
getAttachment(PDF_FILE)
))
.build();
boolean multiSuccess = MailSender.sendEmailSync(multiAttachmentsMsg);
System.out.println("同步发送多个附件结果:" + (multiSuccess ? "成功" : "失败"));
}
/**
* 测试异步发送带附件邮件(单个附件 + 多个附件)
*/
public static void testAsyncWithAttachments() throws ExecutionException, InterruptedException {
// 1. 测试异步发送:单个图片附件
MailMessage singleImgMsg = MailMessage.builder()
.to(TEST_RECIPIENT)
.subject("【异步测试】带单个图片附件的邮件")
.content("<h1>这是一封异步发送的带单个图片附件的测试邮件</h1>")
.attachment(getAttachment(IMAGE_FILE))
.build();
Future<Boolean> singleImgFuture = MailSender.sendEmailAsync(singleImgMsg);
boolean singleImgSuccess = singleImgFuture.get(); // 阻塞等待结果
System.out.println("异步发送单个图片附件结果:" + (singleImgSuccess ? "成功" : "失败"));
// 2. 测试异步发送:多个附件(文本+PDF)
MailMessage multiAsyncMsg = MailMessage.builder()
.to(TEST_RECIPIENT)
.subject("【异步测试】带文本+PDF附件的邮件")
.content("<h1>这是一封异步发送的带多个附件的测试邮件</h1>")
.attachments(Arrays.asList(
getAttachment(TEXT_FILE),
getAttachment(PDF_FILE)
))
.build();
Future<Boolean> multiAsyncFuture = MailSender.sendEmailAsync(multiAsyncMsg);
boolean multiAsyncSuccess = multiAsyncFuture.get();
System.out.println("异步发送多个附件结果:" + (multiAsyncSuccess ? "成功" : "失败"));
}
/**
* 测试并行发送带附件邮件(批量发送给多个收件人,均带附件)
*/
public static void testParallelWithAttachments() {
// 构建多个带附件的邮件消息(每个收件人发送带不同附件的邮件)
List<MailMessage> messages = new ArrayList<>();
for (int i = 0; i < TEST_RECIPIENTS.size(); i++) {
String recipient = TEST_RECIPIENTS.get(i);
// 轮流使用不同附件(模拟不同邮件带不同附件)
Attachment attachment = i % 3 == 0 ? getAttachment(TEXT_FILE) :
i % 3 == 1 ? getAttachment(IMAGE_FILE) :
getAttachment(PDF_FILE);
MailMessage msg = MailMessage.builder()
.to(recipient)
.subject("【并行测试】第" + (i + 1) + "封带附件的邮件")
.content("<h1>这是并行发送的第" + (i + 1) + "封带附件的测试邮件</h1>")
.attachment(attachment)
.build();
messages.add(msg);
}
// 并行发送并等待结果
MailSender.sendEmailsParallel(messages)
.thenAccept(results -> {
long successCount = results.stream().filter(Boolean::booleanValue).count();
System.out.println("并行发送带附件邮件完成:成功" + successCount + "封,失败" + (results.size() - successCount) + "封");
})
.join(); // 阻塞等待所有并行任务完成
}
/**
* 获取附件对象(从resources目录读取文件)
*/
private static Attachment getAttachment(String resourcePath) {
try {
// 读取resources下的附件文件
File file = new File(MailAttachmentTest.class.getClassLoader().getResource(resourcePath).toURI());
return new Attachment(file.getName(), file);
} catch (Exception e) {
throw new RuntimeException("获取附件失败:" + resourcePath, e);
}
}
}
哲学管理(学)人生, 文学艺术生活, 自动(计算机学)物理(学)工作, 生物(学)化学逆境, 历史(学)测绘(学)时间, 经济(学)数学金钱(理财), 心理(学)医学情绪, 诗词美容情感, 美学建筑(学)家园, 解构建构(分析)整合学习, 智商情商(IQ、EQ)运筹(学)生存.---Geovin Du(涂聚文)
浙公网安备 33010602011771号