本文目录导读:

下面是一个完整的Java邮件群发案例,包含SMTP配置、HTML邮件、附件发送、多收件人处理以及异常处理。
Maven依赖
<dependencies>
<!-- JavaMail -->
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
<!-- 或使用Jakarta Mail(适用于新版本) -->
<!-- <dependency>
<groupId>org.eclipse.angus</groupId>
<artifactId>angus-mail</artifactId>
<version>2.0.1</version>
</dependency> -->
</dependencies>
邮件配置类
import java.util.Properties;
public class MailConfig {
// SMTP服务器配置
public static final String SMTP_HOST = "smtp.qq.com";
public static final String SMTP_PORT = "465";
public static final String SMTP_SSL = "true";
public static final String AUTH_USERNAME = "your-email@qq.com";
public static final String AUTH_PASSWORD = "your-authorization-code";
public static Properties getMailProperties() {
Properties props = new Properties();
props.put("mail.smtp.host", SMTP_HOST);
props.put("mail.smtp.port", SMTP_PORT);
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.ssl.enable", SMTP_SSL);
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
props.put("mail.smtp.socketFactory.port", SMTP_PORT);
props.put("mail.smtp.connectiontimeout", 5000);
props.put("mail.smtp.timeout", 5000);
props.put("mail.smtp.writetimeout", 5000);
return props;
}
}
邮件实体类
import java.util.List;
import java.util.Map;
public class EmailMessage {
private List<String> toRecipients; // 收件人列表
private List<String> ccRecipients; // 抄送人列表
private List<String> bccRecipients; // 密送人列表
private String subject; // 邮件主题
private String htmlContent; // HTML内容
private String textContent; // 纯文本内容
private Map<String, byte[]> attachments; // 附件列表
// 构造函数、getter和setter
public EmailMessage() {}
public EmailMessage(List<String> toRecipients, String subject, String content) {
this.toRecipients = toRecipients;
this.subject = subject;
this.htmlContent = content;
}
// Getters and Setters
public List<String> getToRecipients() { return toRecipients; }
public void setToRecipients(List<String> toRecipients) { this.toRecipients = toRecipients; }
public List<String> getCcRecipients() { return ccRecipients; }
public void setCcRecipients(List<String> ccRecipients) { this.ccRecipients = ccRecipients; }
public List<String> getBccRecipients() { return bccRecipients; }
public void setBccRecipients(List<String> bccRecipients) { this.bccRecipients = bccRecipients; }
public String getSubject() { return subject; }
public void setSubject(String subject) { this.subject = subject; }
public String getHtmlContent() { return htmlContent; }
public void setHtmlContent(String htmlContent) { this.htmlContent = htmlContent; }
public String getTextContent() { return textContent; }
public void setTextContent(String textContent) { this.textContent = textContent; }
public Map<String, byte[]> getAttachments() { return attachments; }
public void setAttachments(Map<String, byte[]> attachments) { this.attachments = attachments; }
}
邮件发送服务类
import javax.mail.*;
import javax.mail.internet.*;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class EmailSenderService {
private static EmailSenderService instance;
private final Session session;
private final ExecutorService executorService;
private EmailSenderService() {
Properties props = MailConfig.getMailProperties();
session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(
MailConfig.AUTH_USERNAME,
MailConfig.AUTH_PASSWORD
);
}
});
// 开启调试模式(生产环境建议关闭)
// session.setDebug(true);
// 创建线程池用于异步发送
executorService = Executors.newFixedThreadPool(10);
}
public static synchronized EmailSenderService getInstance() {
if (instance == null) {
instance = new EmailSenderService();
}
return instance;
}
/**
* 异步发送邮件
*/
public void sendEmailAsync(EmailMessage emailMessage) {
executorService.submit(() -> {
try {
sendEmail(emailMessage);
} catch (MessagingException e) {
e.printStackTrace();
}
});
}
/**
* 同步发送邮件
*/
public void sendEmail(EmailMessage emailMessage) throws MessagingException {
Message message = createMessage(emailMessage);
Transport.send(message);
System.out.println("邮件发送成功!");
}
/**
* 创建邮件消息
*/
private Message createMessage(EmailMessage emailMessage) throws MessagingException {
MimeMessage message = new MimeMessage(session);
// 发件人
message.setFrom(new InternetAddress(MailConfig.AUTH_USERNAME));
// 收件人
List<String> toList = emailMessage.getToRecipients();
if (toList != null && !toList.isEmpty()) {
InternetAddress[] toAddresses = new InternetAddress[toList.size()];
for (int i = 0; i < toList.size(); i++) {
toAddresses[i] = new InternetAddress(toList.get(i));
}
message.setRecipients(Message.RecipientType.TO, toAddresses);
}
// 抄送
List<String> ccList = emailMessage.getCcRecipients();
if (ccList != null && !ccList.isEmpty()) {
InternetAddress[] ccAddresses = new InternetAddress[ccList.size()];
for (int i = 0; i < ccList.size(); i++) {
ccAddresses[i] = new InternetAddress(ccList.get(i));
}
message.setRecipients(Message.RecipientType.CC, ccAddresses);
}
// 密送
List<String> bccList = emailMessage.getBccRecipients();
if (bccList != null && !bccList.isEmpty()) {
InternetAddress[] bccAddresses = new InternetAddress[bccList.size()];
for (int i = 0; i < bccList.size(); i++) {
bccAddresses[i] = new InternetAddress(bccList.get(i));
}
message.setRecipients(Message.RecipientType.BCC, bccAddresses);
}
// 邮件主题
message.setSubject(emailMessage.getSubject(), "UTF-8");
// 邮件内容
MimeMultipart multipart = new MimeMultipart();
// HTML内容
if (emailMessage.getHtmlContent() != null && !emailMessage.getHtmlContent().isEmpty()) {
BodyPart htmlPart = new MimeBodyPart();
htmlPart.setContent(emailMessage.getHtmlContent(), "text/html;charset=UTF-8");
multipart.addBodyPart(htmlPart);
}
// 纯文本内容
if (emailMessage.getTextContent() != null && !emailMessage.getTextContent().isEmpty()) {
BodyPart textPart = new MimeBodyPart();
textPart.setText(emailMessage.getTextContent());
multipart.addBodyPart(textPart);
}
// 附件
Map<String, byte[]> attachments = emailMessage.getAttachments();
if (attachments != null && !attachments.isEmpty()) {
for (Map.Entry<String, byte[]> entry : attachments.entrySet()) {
BodyPart attachmentPart = new MimeBodyPart();
attachmentPart.setFileName(entry.getKey());
attachmentPart.setContent(entry.getValue(), "application/octet-stream");
multipart.addBodyPart(attachmentPart);
}
}
message.setContent(multipart);
return message;
}
/**
* 关闭线程池
*/
public void shutdown() {
executorService.shutdown();
}
}
模板渲染服务
import java.util.Map;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class TemplateService {
/**
* 简单的模板渲染(支持占位符替换)
* Hello ${name}, welcome!
*/
public static String renderTemplate(String template, Map<String, String> variables) {
for (Map.Entry<String, String> entry : variables.entrySet()) {
template = template.replace("${" + entry.getKey() + "}", entry.getValue());
}
return template;
}
/**
* 创建一个默认的HTML模板
*/
public static String getDefaultTemplate(String title, String content, String footer) {
return String.format("""
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>%s</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 20px;
}
.container {
background-color: #ffffff;
border-radius: 8px;
padding: 30px;
margin: auto;
max-width: 600px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
h1 {
color: #333;
text-align: center;
}
p {
color: #666;
line-height: 1.6;
}
.footer {
color: #999;
font-size: 12px;
text-align: center;
margin-top: 20px;
border-top: 1px solid #eee;
padding-top: 15px;
}
</style>
</head>
<body>
<div class="container">
<h1>%s</h1>
%s
<div class="footer">%s</div>
</div>
</body>
</html>
""", title, title, content, footer);
}
}
批量发送工具类
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class BulkEmailSender {
/**
* 批量发送个性化邮件
* @param recipientList 收件人列表
* @param subject 邮件主题模板
* @param contentTemplate 内容模板(使用${name}等占位符)
* @param variablesList 每个收件人对应的变量列表
*/
public static void sendBulkEmails(List<String> recipientList,
String subject,
String contentTemplate,
List<Map<String, String>> variablesList) {
EmailSenderService sender = EmailSenderService.getInstance();
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (int i = 0; i < recipientList.size(); i++) {
String recipient = recipientList.get(i);
Map<String, String> variables = variablesList.get(i);
// 渲染个性化内容
String personalizedContent = TemplateService.renderTemplate(contentTemplate, variables);
String personalizedSubject = TemplateService.renderTemplate(subject, variables);
// 发送邮件(异步)
EmailMessage email = new EmailMessage();
List<String> recipients = new ArrayList<>();
recipients.add(recipient);
email.setToRecipients(recipients);
email.setSubject(personalizedSubject);
email.setHtmlContent(personalizedContent);
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
sender.sendEmail(email);
} catch (Exception e) {
System.err.println("发送到 " + recipient + " 失败: " + e.getMessage());
}
});
futures.add(future);
}
// 等待所有邮件发送完成
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.join();
}
/**
* 分批发送(避免一次发送过多)
*/
public static void sendBulkEmailsInBatches(List<String> recipients,
String subject,
String content,
int batchSize) {
int total = recipients.size();
int batchCount = (total + batchSize - 1) / batchSize;
for (int i = 0; i < batchCount; i++) {
int fromIndex = i * batchSize;
int toIndex = Math.min((i + 1) * batchSize, total);
List<String> batchRecipients = recipients.subList(fromIndex, toIndex);
List<Map<String, String>> variablesList = new ArrayList<>();
for (String recipient : batchRecipients) {
Map<String, String> vars = new HashMap<>();
vars.put("recipient", recipient);
variablesList.add(vars);
}
String batchSubject = TemplateService.renderTemplate(subject,
Map.of("batch", String.valueOf(i + 1), "total", String.valueOf(batchCount)));
sendBulkEmails(batchRecipients, batchSubject, content, variablesList);
// 批次之间暂停
try {
Thread.sleep(5000); // 5秒后发送下一批
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
使用示例
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class EmailDemo {
public static void main(String[] args) {
// 示例1:发送简单邮件
simpleEmailDemo();
// 示例2:批量个性化邮件
bulkEmailDemo();
// 示例3:带附件的邮件
attachmentEmailDemo();
}
/**
* 简单邮件发送
*/
public static void simpleEmailDemo() {
EmailMessage email = new EmailMessage();
List<String> recipients = new ArrayList<>();
recipients.add("recipient1@example.com");
recipients.add("recipient2@example.com");
email.setToRecipients(recipients);
email.setSubject("【测试邮件】欢迎使用Java邮件服务");
email.setHtmlContent("""
<html>
<body>
<h1>欢迎使用Java邮件服务</h1>
<p>这是一封测试邮件,如果您收到此邮件,说明配置成功。</p>
<p>发送时间:<span style="color: blue;">%s</span></p>
</body>
</html>
""".formatted(new java.util.Date().toString()));
EmailSenderService sender = EmailSenderService.getInstance();
try {
sender.sendEmail(email);
System.out.println("简单邮件发送成功!");
} catch (Exception e) {
System.err.println("发送失败: " + e.getMessage());
}
}
/**
* 批量个性化邮件
*/
public static void bulkEmailDemo() {
// 收件人列表
List<String> recipients = new ArrayList<>();
recipients.add("user1@example.com");
recipients.add("user2@example.com");
recipients.add("user3@example.com");
recipients.add("user4@example.com");
recipients.add("user5@example.com");
// 邮件模板
String subjectTemplate = "【${company}】${name},您的专属优惠来了!";
String contentTemplate = """
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>优惠通知</title>
</head>
<body>
<h2>亲爱的 ${name}:</h2>
<p>您好!${company} 为您准备了专属优惠。</p>
<p>您的专属优惠码:<strong style="color: red;">${coupon}</strong></p>
<p>有效期至:${expireDate}</p>
<p>立即使用:<a href="${website}">点击访问</a></p>
<br>
<p>感谢您的支持!</p>
</body>
</html>
""";
// 每个收件人的个性化变量
List<Map<String, String>> variablesList = new ArrayList<>();
for (int i = 1; i <= recipients.size(); i++) {
Map<String, String> vars = new HashMap<>();
vars.put("name", "用户" + i);
vars.put("company", "Java邮件服务");
vars.put("coupon", "SAVE" + (100 + i * 10));
vars.put("expireDate", "2024年12月31日");
vars.put("website", "https://www.example.com");
vars.put("batch", "1");
vars.put("total", "1");
variablesList.add(vars);
}
// 发送批量邮件
BulkEmailSender.sendBulkEmails(recipients, subjectTemplate, contentTemplate, variablesList);
System.out.println("批量邮件发送完成!");
}
/**
* 带附件的邮件
*/
public static void attachmentEmailDemo() {
EmailMessage email = new EmailMessage();
List<String> recipients = new ArrayList<>();
recipients.add("recipient@example.com");
email.setToRecipients(recipients);
email.setSubject("【资料文件】2014年项目报告");
email.setHtmlContent("""
<html>
<body>
<h2>项目报告</h2>
<p>请查收附件中的项目报告。</p>
<p>如有问题,请随时联系我们。</p>
</body>
</html>
""");
// 添加附件
Map<String, byte[]> attachments = new HashMap<>();
attachments.put("报告文档.txt", "这是文档内容".getBytes());
attachments.put("财务数据.csv", "日期,收入,支出\n2024-01,10000,5000".getBytes());
email.setAttachments(attachments);
EmailSenderService sender = EmailSenderService.getInstance();
try {
sender.sendEmail(email);
System.out.println("带附件邮件发送成功!");
} catch (Exception e) {
System.err.println("发送失败: " + e.getMessage());
}
}
}
配置文件示例 (application.properties)
# SMTP配置 mail.smtp.host=smtp.qq.com mail.smtp.port=465 mail.smtp.auth=true mail.smtp.ssl.enable=true mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory # 账号信息 mail.username=your-email@qq.com mail.password=your-authorization-code # 邮件发送配置 mail.batch.size=50 mail.batch.delay=5000 mail.default.encoding=UTF-8
注意事项
-
SMTP服务器配置:不同的邮箱服务商(QQ邮箱、163邮箱、Gmail等)有不同的SMTP服务器配置,需要根据实际情况调整。
-
授权码:不要使用邮箱密码,使用邮箱服务商提供的授权码(如QQ邮箱的授权码)。
-
发送限制:各大邮件服务商对每日发送数量有限制,请合理控制发送频率和数量。
-
线程安全:
EmailSenderService使用单例模式,并提供了异步发送方法。 -
错误处理:在实际项目中,建议添加完善的日志记录和重试机制。
-
敏感信息:授权码等敏感信息不要硬编码,应该从配置文件或环境变量中读取。