拒绝繁琐邮件封装!JakartaMailUtil 极简实现邮件发送 + 附件 + 抄送 + 密送
简介
在企业应用开发中,邮件发送是一个常见但繁琐的功能:用户注册验证、密码找回、订单通知、系统告警……每次都要处理SMTP连接、MIME类型、附件编码等底层细节。原生的JavaMail API虽然功能强大,但使用起来非常复杂,仅发送一封简单的邮件就需要几十行代码。Hutool 的 JakartaMailUtil 对JavaMail进行了深度封装,让邮件发送变得像调用一个方法一样简单。
JakartaMailUtil 的主要应用场景:
- 用户通知:注册验证、密码重置、订单状态更新
- 系统告警:异常监控、性能预警、定时任务报告
- 营销推广:活动通知、优惠券发放、会员服务
- 业务报表:日报周报、数据统计、财务对账
- 团队协作:任务提醒、审批通知、会议邀请
核心概念
SMTP协议
SMTP(Simple Mail Transfer Protocol)是发送邮件的标准协议。邮件发送需要配置SMTP服务器地址、端口、认证信息等参数。
常见邮件服务商SMTP配置:
- QQ邮箱:smtp.qq.com,端口465/587(SSL)
- 163邮箱:smtp.163.com,端口465/994(SSL)
- Gmail:smtp.gmail.com,端口465/587(SSL)
- 企业邮箱:一般由企业IT提供
邮件账户配置
JakartaMailUtil使用MailAccount对象封装邮件账户信息,包括SMTP服务器、端口、用户名、密码、发件人信息等。可以通过代码创建或从配置文件加载。
邮件类型
- 纯文本邮件:简单的文本内容,不支持格式
- HTML邮件:支持富文本、图片、样式等,体验更好
- 带附件邮件:可附带文件、图片等资源
环境准备
Maven依赖
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-extra</artifactId>
<version>5.8.16</version>
</dependency>
<!-- Jakarta Mail API -->
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>jakarta.mail</artifactId>
<version>2.0.1</version>
</dependency>
配置文件(可选)
在resources目录下创建mail.setting文件(可选,也可以纯代码配置):
# SMTP服务器地址
host = smtp.qq.com
# SMTP端口
port = 465
# 发件人邮箱
from = your_email@qq.com
# 用户名(一般与发件人邮箱相同)
user = your_email@qq.com
# 密码(QQ邮箱使用授权码,不是登录密码)
pass = your_authorization_code
# 是否使用SSL
sslEnable = true
注意:QQ邮箱、163邮箱等需要开启SMTP服务并获取授权码,不能直接使用登录密码。
常用API详解
1. 邮件账户配置
1.1 代码方式创建账户 - MailAccount
方法签名:
MailAccount account = new MailAccount();
account.setHost(String host);
account.setPort(Integer port);
account.setFrom(String from);
account.setUser(String user);
account.setPass(String pass);
account.setSslEnable(Boolean sslEnable);
功能:通过代码创建邮件账户配置对象。
示例:
// 创建邮件账户配置(QQ邮箱示例)
MailAccount account = new MailAccount();
account.setHost("smtp.qq.com");
account.setPort(465);
account.setFrom("sender@qq.com");
account.setUser("sender@qq.com");
account.setPass("your_authorization_code"); // QQ邮箱授权码
account.setSslEnable(true);
// 163邮箱配置
MailAccount account163 = new MailAccount();
account163.setHost("smtp.163.com");
account163.setPort(465);
account163.setFrom("sender@163.com");
account163.setUser("sender@163.com");
account163.setPass("your_password");
account163.setSslEnable(true);
// 企业邮箱配置
MailAccount corpAccount = new MailAccount();
corpAccount.setHost("smtp.exmail.qq.com");
corpAccount.setPort(465);
corpAccount.setFrom("admin@company.com");
corpAccount.setUser("admin@company.com");
corpAccount.setPass("your_password");
corpAccount.setSslEnable(true);
1.2 配置文件方式 - getSession()
方法签名:
static Session getSession(MailAccount mailAccount, boolean isSingleton)
功能:根据邮件账户配置获取邮件会话对象。
参数:
- mailAccount:邮件账户配置
- isSingleton:是否单例(true表示复用会话,性能更好)
示例:
// 获取邮件会话(单例模式)
MailAccount account = new MailAccount();
account.setHost("smtp.qq.com");
account.setPort(465);
account.setFrom("sender@qq.com");
account.setUser("sender@qq.com");
account.setPass("your_code");
account.setSslEnable(true);
Session session = MailUtil.getSession(account, true);
2. 发送文本邮件
2.1 发送给单个收件人 - sendText()
方法签名:
static String sendText(String to, String subject, String content, File... files)
功能:使用配置文件中的账户发送纯文本邮件。
参数:
- to:收件人邮箱(多个用逗号或分号分隔)
- subject:邮件主题
- content:邮件正文(纯文本)
- files:附件文件(可选)
返回值:邮件ID
示例:
// 发送简单文本邮件
String messageId = MailUtil.sendText(
"receiver@qq.com",
"系统通知",
"您的账号已激活,欢迎使用我们的服务!"
);
System.out.println("邮件发送成功,ID: " + messageId);
// 发送给多个收件人(逗号分隔)
MailUtil.sendText(
"user1@qq.com,user2@163.com",
"会议通知",
"本周五下午3点召开项目会议,请准时参加。"
);
// 发送给多个收件人(分号分隔)
MailUtil.sendText(
"user1@qq.com;user2@163.com",
"假期通知",
"国庆节放假7天,祝大家节日快乐!"
);
// 带附件的文本邮件
File report = new File("report.pdf");
MailUtil.sendText(
"manager@company.com",
"月度报告",
"请查收本月工作报告",
report
);
2.2 发送给多人(集合方式) - sendText()
方法签名:
static String sendText(Collection<String> tos, String subject, String content, File... files)
功能:使用集合方式指定多个收件人,发送纯文本邮件。
示例:
// 使用List指定收件人
List<String> recipients = Arrays.asList(
"user1@qq.com",
"user2@163.com",
"user3@gmail.com"
);
MailUtil.sendText(
recipients,
"系统维护通知",
"系统将于今晚22:00-24:00进行维护,期间服务暂停。"
);
// 动态构建收件人列表
List<User> users = userService.findAllActiveUsers();
List<String> emails = users.stream()
.map(User::getEmail)
.collect(Collectors.toList());
MailUtil.sendText(
emails,
"账户安全提醒",
"请及时修改初始密码,保护账户安全。"
);
3. 发送HTML邮件
3.1 基础HTML邮件 - sendHtml()
方法签名:
static String sendHtml(String to, String subject, String content, File... files)
static String sendHtml(Collection<String> tos, String subject, String content, File... files)
功能:发送支持HTML格式的邮件,可以包含样式、图片、链接等。
示例:
// 发送简单HTML邮件
String htmlContent = "<html>" +
"<body>" +
"<h2 style='color: blue;'>欢迎注册</h2>" +
"<p>尊敬的用户,您好!</p>" +
"<p>您的账号已成功注册,请点击下方链接激活:</p>" +
"<a href='https://example.com/activate?token=123'>点击激活</a>" +
"</body>" +
"</html>";
MailUtil.sendHtml(
"newuser@qq.com",
"账号激活邮件",
htmlContent
);
// 发送带样式的HTML邮件
String styledContent = "<html>" +
"<head>" +
"<style>" +
".container { padding: 20px; background: #f5f5f5; }" +
".title { color: #333; font-size: 24px; }" +
".content { line-height: 1.6; }" +
".button { " +
" display: inline-block; " +
" padding: 10px 20px; " +
" background: #007bff; " +
" color: white; " +
" text-decoration: none; " +
"}" +
"</style>" +
"</head>" +
"<body>" +
"<div class='container'>" +
"<h1 class='title'>订单确认</h1>" +
"<div class='content'>" +
"<p>您的订单已确认,订单号:202401150001</p>" +
"<p>商品总价:¥299.00</p>" +
"<a href='https://example.com/order/202401150001' class='button'>查看订单详情</a>" +
"</div>" +
"</div>" +
"</body>" +
"</html>";
MailUtil.sendHtml(
"customer@qq.com",
"订单确认通知",
styledContent
);
3.2 带内嵌图片的HTML邮件 - sendHtml()
方法签名:
static String sendHtml(String to, String subject, String content, Map<String,InputStream> imageMap, File... files)
功能:发送HTML邮件并内嵌图片,图片直接显示在邮件中而不是作为附件。
参数:
- imageMap:图片映射,key为图片ID(在HTML中引用),value为图片输入流
示例:
// 准备内嵌图片
Map<String, InputStream> imageMap = new HashMap<>();
imageMap.put("logo", new FileInputStream("logo.png"));
imageMap.put("banner", new FileInputStream("banner.jpg"));
// HTML内容中引用图片(使用cid:图片ID)
String htmlContent = "<html>" +
"<body>" +
"<img src='cid:logo' width='200'/>" +
"<h2>产品推荐</h2>" +
"<img src='cid:banner' width='600'/>" +
"<p>我们为您精选了以下优质商品...</p>" +
"</body>" +
"</html>";
MailUtil.sendHtml(
"customer@qq.com",
"每周精选推荐",
htmlContent,
imageMap
);
// 实际应用:营销邮件
Map<String, InputStream> images = new HashMap<>();
images.put("product1", getClass().getResourceAsStream("/images/product1.jpg"));
images.put("product2", getClass().getResourceAsStream("/images/product2.jpg"));
String marketingHtml = "<html>" +
"<body style='font-family: Arial;'>" +
"<h1 style='color: #e74c3c;'>限时特惠</h1>" +
"<div>" +
"<img src='cid:product1' width='300'/>" +
"<p>商品A - 原价¥199,现价¥99</p>" +
"</div>" +
"<div>" +
"<img src='cid:product2' width='300'/>" +
"<p>商品B - 原价¥299,现价¥199</p>" +
"</div>" +
"</body>" +
"</html>";
MailUtil.sendHtml(
vipEmails,
"VIP会员专属优惠",
marketingHtml,
images
);
4. 通用发送方法
4.1 完整参数发送 - send()
方法签名:
static String send(String to, String cc, String bcc, String subject, String content, boolean isHtml, File... files)
static String send(Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, boolean isHtml, File... files)
功能:最完整的邮件发送方法,支持抄送、密送、HTML/文本、附件等所有功能。
参数:
- to/tos:收件人
- cc/ccs:抄送人
- bcc/bccs:密送人
- subject:主题
- content:内容
- isHtml:是否HTML格式
- files:附件
示例:
// 发送带抄送和密送的邮件
MailUtil.send(
"recipient@qq.com", // 收件人
"cc@qq.com", // 抄送
"bcc@qq.com", // 密送
"项目进度报告",
"项目已完成80%,预计下周交付。",
false, // 纯文本
new File("progress.xlsx") // 附件
);
// 发送给多人,带抄送和密送
List<String> recipients = Arrays.asList("user1@qq.com", "user2@qq.com");
List<String> ccs = Arrays.asList("manager@qq.com");
List<String> bccs = Arrays.asList("admin@qq.com");
MailUtil.send(
recipients,
ccs,
bccs,
"团队周报",
"<h3>本周工作总结</h3><p>完成功能开发3个...</p>",
true, // HTML格式
new File("weekly_report.pdf")
);
4.2 指定账户发送 - send()
方法签名:
static String send(MailAccount mailAccount, String to, String subject, String content, boolean isHtml, File... files)
static String send(MailAccount mailAccount, Collection<String> tos, String subject, String content, boolean isHtml, File... files)
功能:使用指定的邮件账户发送邮件,而不是使用配置文件中的默认账户。
示例:
// 使用特定账户发送
MailAccount notifyAccount = new MailAccount();
notifyAccount.setHost("smtp.163.com");
notifyAccount.setPort(465);
notifyAccount.setFrom("notify@163.com");
notifyAccount.setUser("notify@163.com");
notifyAccount.setPass("password");
notifyAccount.setSslEnable(true);
MailUtil.send(
notifyAccount,
"user@qq.com",
"系统通知",
"您的订单已发货",
false
);
// 不同类型邮件使用不同账户
MailAccount marketingAccount = createMarketingAccount();
MailAccount systemAccount = createSystemAccount();
// 营销邮件用营销账户
MailUtil.send(
marketingAccount,
vipUsers,
"新品上市",
marketingHtml,
true
);
// 系统通知用系统账户
MailUtil.send(
systemAccount,
adminUsers,
"系统告警",
alertContent,
false
);
5. 带内嵌图片的完整发送
方法签名:
static String send(String to, String cc, String bcc, String subject, String content, Map<String,InputStream> imageMap, boolean isHtml, File... files)
static String send(MailAccount mailAccount, Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, Map<String,InputStream> imageMap, boolean isHtml, File... files)
功能:最完整的发送方法,支持所有功能包括内嵌图片。
示例:
// 完整功能邮件发送
Map<String, InputStream> images = new HashMap<>();
images.put("chart", new FileInputStream("sales_chart.png"));
images.put("logo", new FileInputStream("company_logo.png"));
String reportHtml = "<html>" +
"<body>" +
"<img src='cid:logo' width='150'/>" +
"<h2>销售月报</h2>" +
"<p>本月销售额增长15%</p>" +
"<img src='cid:chart' width='600'/>" +
"</body>" +
"</html>";
MailUtil.send(
"ceo@company.com", // 收件人
"manager@company.com", // 抄送
"finance@company.com", // 密送
"2024年1月销售报告",
reportHtml,
images, // 内嵌图片
true, // HTML格式
new File("detailed_report.xlsx") // 附件
);
实战场景
场景1:用户注册邮件验证
用户注册后发送激活邮件,包含激活链接。
示例代码:
@Service
public class UserRegistrationService {
@Autowired
private UserRepository userRepository;
public void registerUser(UserRegisterDTO dto) {
// 1. 创建用户
User user = new User();
user.setUsername(dto.getUsername());
user.setEmail(dto.getEmail());
user.setPassword(encryptPassword(dto.getPassword()));
user.setStatus(0); // 未激活
userRepository.save(user);
// 2. 生成激活token
String token = generateActivationToken(user.getId());
// 3. 发送激活邮件
sendActivationEmail(user.getEmail(), user.getUsername(), token);
}
private void sendActivationEmail(String email, String username, String token) {
String activationUrl = "https://www.example.com/activate?token=" + token;
String htmlContent = "<html>" +
"<body style='font-family: Arial, sans-serif;'>" +
"<div style='max-width: 600px; margin: 0 auto; padding: 20px;'>" +
"<h2 style='color: #333;'>欢迎注册我们的服务</h2>" +
"<p>尊敬的 <strong>" + username + "</strong>,您好!</p>" +
"<p>感谢您注册我们的服务。请点击下方按钮激活您的账户:</p>" +
"<div style='text-align: center; margin: 30px 0;'>" +
"<a href='" + activationUrl + "' " +
"style='display: inline-block; padding: 12px 30px; " +
"background-color: #007bff; color: white; " +
"text-decoration: none; border-radius: 5px;'>" +
"激活账户" +
"</a>" +
"</div>" +
"<p style='color: #666; font-size: 12px;'>" +
"如果按钮无法点击,请复制以下链接到浏览器:<br/>" +
activationUrl +
"</p>" +
"<p style='color: #666; font-size: 12px;'>" +
"此链接24小时内有效,请尽快激活。" +
"</p>" +
"</div>" +
"</body>" +
"</html>";
try {
MailUtil.sendHtml(
email,
"账户激活邮件 - 请验证您的邮箱",
htmlContent
);
log.info("激活邮件已发送至: {}", email);
} catch (Exception e) {
log.error("发送激活邮件失败: {}", e.getMessage());
}
}
private String generateActivationToken(Long userId) {
// 生成包含用户ID和过期时间的token
String data = userId + ":" + System.currentTimeMillis();
return Base64.getEncoder().encodeToString(data.getBytes());
}
private String encryptPassword(String password) {
return SecureUtil.md5(password);
}
}
场景2:密码重置功能
用户忘记密码时发送重置链接。
示例代码:
@Service
public class PasswordResetService {
@Autowired
private UserRepository userRepository;
@Autowired
private RedisTemplate<String, String> redisTemplate;
public void sendResetEmail(String email) {
// 1. 验证用户是否存在
User user = userRepository.findByEmail(email);
if (user == null) {
throw new BusinessException("邮箱未注册");
}
// 2. 生成重置token(存入Redis,30分钟过期)
String token = UUID.randomUUID().toString().replace("-", "");
String redisKey = "password_reset:" + token;
redisTemplate.opsForValue().set(redisKey, user.getId().toString(), 30, TimeUnit.MINUTES);
// 3. 发送重置邮件
sendResetEmailNotification(email, user.getUsername(), token);
}
private void sendResetEmailNotification(String email, String username, String token) {
String resetUrl = "https://www.example.com/reset-password?token=" + token;
String htmlContent = "<html>" +
"<body style='font-family: Arial;'>" +
"<div style='max-width: 600px; margin: 0 auto; padding: 20px; " +
"border: 1px solid #ddd; border-radius: 10px;'>" +
"<h2 style='color: #e74c3c;'>密码重置请求</h2>" +
"<p>您好,<strong>" + username + "</strong>!</p>" +
"<p>我们收到了您的密码重置请求。如果这不是您的操作,请忽略此邮件。</p>" +
"<p>点击下方按钮重置密码:</p>" +
"<div style='text-align: center; margin: 30px 0;'>" +
"<a href='" + resetUrl + "' " +
"style='display: inline-block; padding: 12px 30px; " +
"background-color: #e74c3c; color: white; " +
"text-decoration: none; border-radius: 5px;'>" +
"重置密码" +
"</a>" +
"</div>" +
"<p style='color: #666; font-size: 12px;'>" +
"此链接30分钟内有效。" +
"</p>" +
"<p style='color: #666; font-size: 12px;'>" +
"如有疑问,请联系客服:support@example.com" +
"</p>" +
"</div>" +
"</body>" +
"</html>";
MailUtil.sendHtml(
email,
"密码重置验证 - 请勿转发此邮件",
htmlContent
);
}
public void resetPassword(String token, String newPassword) {
// 1. 验证token
String redisKey = "password_reset:" + token;
String userId = redisTemplate.opsForValue().get(redisKey);
if (userId == null) {
throw new BusinessException("重置链接已失效");
}
// 2. 更新密码
User user = userRepository.findById(Long.parseLong(userId))
.orElseThrow(() -> new BusinessException("用户不存在"));
user.setPassword(SecureUtil.md5(newPassword));
userRepository.save(user);
// 3. 删除token
redisTemplate.delete(redisKey);
// 4. 发送确认邮件
sendPasswordChangedNotification(user.getEmail(), user.getUsername());
}
private void sendPasswordChangedNotification(String email, String username) {
String textContent = "尊敬的 " + username + ",\n\n" +
"您的密码已成功修改。如果这不是您的操作,请立即联系客服。\n\n" +
"客服邮箱:support@example.com\n" +
"客服电话:400-123-4567";
MailUtil.sendText(
email,
"密码修改成功通知",
textContent
);
}
}
场景3:订单通知系统
订单状态变更时自动发送邮件通知。
示例代码:
@Service
public class OrderNotificationService {
public void sendOrderConfirmation(Order order, User user) {
String htmlContent = buildOrderConfirmationHtml(order, user);
MailUtil.sendHtml(
user.getEmail(),
"订单确认 - " + order.getOrderNo(),
htmlContent
);
}
public void sendShippingNotification(Order order, User user, String trackingNo) {
String htmlContent = "<html>" +
"<body>" +
"<h2>您的订单已发货</h2>" +
"<p>订单号:" + order.getOrderNo() + "</p>" +
"<p>物流单号:" + trackingNo + "</p>" +
"<p>预计3-5天送达</p>" +
"<a href='https://www.example.com/track?no=" + trackingNo + "'>查看物流信息</a>" +
"</body>" +
"</html>";
MailUtil.sendHtml(
user.getEmail(),
"订单已发货 - " + order.getOrderNo(),
htmlContent
);
}
public void sendDeliveryNotification(Order order, User user) {
String textContent = "尊敬的客户,\n\n" +
"您的订单 " + order.getOrderNo() + " 已签收。\n" +
"感谢您的购买,期待再次为您服务!\n\n" +
"如有问题,请联系客服。";
MailUtil.sendText(
user.getEmail(),
"订单已签收 - " + order.getOrderNo(),
textContent
);
}
private String buildOrderConfirmationHtml(Order order, User user) {
StringBuilder html = new StringBuilder();
html.append("<html><body style='font-family: Arial;'>");
html.append("<div style='max-width: 600px; margin: 0 auto; padding: 20px;'>");
html.append("<h2 style='color: #27ae60;'>订单确认</h2>");
html.append("<p>尊敬的 ").append(user.getUsername()).append(",您好!</p>");
html.append("<p>您的订单已确认,详情如下:</p>");
html.append("<table style='width: 100%; border-collapse: collapse;'>");
html.append("<tr style='background: #f5f5f5;'>");
html.append("<th style='padding: 10px; text-align: left;'>商品</th>");
html.append("<th style='padding: 10px; text-align: right;'>数量</th>");
html.append("<th style='padding: 10px; text-align: right;'>金额</th>");
html.append("</tr>");
for (OrderItem item : order.getItems()) {
html.append("<tr>");
html.append("<td style='padding: 10px;'>").append(item.getProductName()).append("</td>");
html.append("<td style='padding: 10px; text-align: right;'>").append(item.getQuantity()).append("</td>");
html.append("<td style='padding: 10px; text-align: right;'>¥").append(item.getAmount()).append("</td>");
html.append("</tr>");
}
html.append("</table>");
html.append("<p style='text-align: right; font-size: 18px; color: #e74c3c;'>");
html.append("订单总额:<strong>¥").append(order.getTotalAmount()).append("</strong>");
html.append("</p>");
html.append("<div style='text-align: center; margin: 30px 0;'>");
html.append("<a href='https://www.example.com/order/").append(order.getOrderNo()).append("' ");
html.append("style='padding: 12px 30px; background: #3498db; color: white; text-decoration: none;'>");
html.append("查看订单详情");
html.append("</a>");
html.append("</div>");
html.append("</div></body></html>");
return html.toString();
}
}
场景4:系统监控告警
系统异常时自动发送告警邮件给运维人员。
示例代码:
@Component
public class SystemMonitorService {
@Value("${monitor.alert.emails}")
private List<String> alertEmails;
public void sendErrorAlert(String errorType, String errorMessage, String stackTrace) {
String subject = "[严重] 系统异常告警 - " + errorType;
String htmlContent = "<html>" +
"<body style='font-family: monospace;'>" +
"<div style='background: #ffe6e6; padding: 20px; border-left: 5px solid #e74c3c;'>" +
"<h2 style='color: #e74c3c;'>⚠ 系统异常告警</h2>" +
"<p><strong>异常类型:</strong>" + errorType + "</p>" +
"<p><strong>发生时间:</strong>" + LocalDateTime.now() + "</p>" +
"<p><strong>错误信息:</strong></p>" +
"<pre style='background: #f5f5f5; padding: 10px;'>" + errorMessage + "</pre>" +
"<p><strong>堆栈信息:</strong></p>" +
"<pre style='background: #f5f5f5; padding: 10px; font-size: 12px;'>" + stackTrace + "</pre>" +
"</div>" +
"</body>" +
"</html>";
MailUtil.sendHtml(
alertEmails,
subject,
htmlContent
);
}
public void sendPerformanceAlert(String metric, double value, double threshold) {
String content = String.format(
"性能指标告警\n\n" +
"指标名称:%s\n" +
"当前值:%.2f\n" +
"阈值:%.2f\n" +
"告警时间:%s\n\n" +
"请及时处理!",
metric, value, threshold, LocalDateTime.now()
);
MailUtil.sendText(
alertEmails,
"[警告] 性能指标超限 - " + metric,
content
);
}
public void sendDailyReport(SystemStats stats) {
// 准备图表
Map<String, InputStream> images = new HashMap<>();
images.put("cpu_chart", generateCpuChart(stats));
images.put("memory_chart", generateMemoryChart(stats));
String htmlContent = "<html>" +
"<body>" +
"<h2>系统日报 - " + LocalDate.now() + "</h2>" +
"<h3>CPU使用率</h3>" +
"<img src='cid:cpu_chart' width='600'/>" +
"<h3>内存使用率</h3>" +
"<img src='cid:memory_chart' width='600'/>" +
"<h3>统计数据</h3>" +
"<ul>" +
"<li>请求总数:" + stats.getTotalRequests() + "</li>" +
"<li>错误数:" + stats.getErrorCount() + "</li>" +
"<li>平均响应时间:" + stats.getAvgResponseTime() + "ms</li>" +
"</ul>" +
"</body>" +
"</html>";
File logFile = new File("system_" + LocalDate.now() + ".log");
MailUtil.sendHtml(
alertEmails,
"系统日报 - " + LocalDate.now(),
htmlContent,
images,
logFile
);
}
private InputStream generateCpuChart(SystemStats stats) {
// 生成图表并返回输入流
// 实际项目中可使用JFreeChart等图表库
return null;
}
private InputStream generateMemoryChart(SystemStats stats) {
return null;
}
}
场景5:定时任务报告
每日/每周生成报表并通过邮件发送。
示例代码:
@Component
public class ReportScheduler {
@Autowired
private OrderService orderService;
@Autowired
private UserService userService;
@Value("${report.recipients}")
private List<String> reportRecipients;
// 每天早上8点发送日报
@Scheduled(cron = "0 0 8 * * ?")
public void sendDailyReport() {
LocalDate yesterday = LocalDate.now().minusDays(1);
// 统计数据
DailyStats stats = orderService.getDailyStats(yesterday);
// 生成Excel报表
File excelFile = generateDailyExcel(stats, yesterday);
String htmlContent = buildDailyReportHtml(stats, yesterday);
MailUtil.sendHtml(
reportRecipients,
"日报 - " + yesterday,
htmlContent,
excelFile
);
}
// 每周一早上9点发送周报
@Scheduled(cron = "0 0 9 ? * MON")
public void sendWeeklyReport() {
LocalDate endDate = LocalDate.now().minusDays(1);
LocalDate startDate = endDate.minusDays(6);
WeeklyStats stats = orderService.getWeeklyStats(startDate, endDate);
// 生成PDF报告
File pdfFile = generateWeeklyPdf(stats, startDate, endDate);
String htmlContent = buildWeeklyReportHtml(stats, startDate, endDate);
MailUtil.sendHtml(
reportRecipients,
String.format("周报 - %s至%s", startDate, endDate),
htmlContent,
pdfFile
);
}
private String buildDailyReportHtml(DailyStats stats, LocalDate date) {
return "<html>" +
"<body style='font-family: Arial;'>" +
"<h2>日报 - " + date + "</h2>" +
"<table style='border-collapse: collapse; width: 100%;'>" +
"<tr><td>订单数:</td><td><strong>" + stats.getOrderCount() + "</strong></td></tr>" +
"<tr><td>销售额:</td><td><strong>¥" + stats.getTotalSales() + "</strong></td></tr>" +
"<tr><td>新增用户:</td><td><strong>" + stats.getNewUsers() + "</strong></td></tr>" +
"<tr><td>活跃用户:</td><td><strong>" + stats.getActiveUsers() + "</strong></td></tr>" +
"</table>" +
"<p>详细数据请查看附件。</p>" +
"</body>" +
"</html>";
}
private String buildWeeklyReportHtml(WeeklyStats stats, LocalDate start, LocalDate end) {
return "<html>" +
"<body>" +
"<h2>周报</h2>" +
"<p>统计周期:" + start + " 至 " + end + "</p>" +
"<h3>业绩概览</h3>" +
"<ul>" +
"<li>总订单数:" + stats.getTotalOrders() + "</li>" +
"<li>总销售额:¥" + stats.getTotalRevenue() + "</li>" +
"<li>较上周增长:" + stats.getGrowthRate() + "%</li>" +
"</ul>" +
"<h3>热门商品Top5</h3>" +
"<ol>" +
stats.getTopProducts().stream()
.map(p -> "<li>" + p.getName() + " - 销量:" + p.getSales() + "</li>")
.collect(Collectors.joining()) +
"</ol>" +
"</body>" +
"</html>";
}
private File generateDailyExcel(DailyStats stats, LocalDate date) {
// 使用POI生成Excel
return new File("daily_" + date + ".xlsx");
}
private File generateWeeklyPdf(WeeklyStats stats, LocalDate start, LocalDate end) {
// 使用iText生成PDF
return new File("weekly_" + start + "_" + end + ".pdf");
}
}
快速使用指南
Maven依赖:
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-extra</artifactId>
<version>5.8.16</version>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>jakarta.mail</artifactId>
<version>2.0.1</version>
</dependency>
最简使用示例:
// 发送简单文本邮件
MailUtil.sendText(
"receiver@qq.com",
"测试邮件",
"这是一封测试邮件"
);
// 发送HTML邮件
MailUtil.sendHtml(
"receiver@qq.com",
"欢迎注册",
"<h2>欢迎</h2><p>注册成功!</p>"
);
// 发送带附件邮件
MailUtil.sendText(
"receiver@qq.com",
"报告",
"请查收附件",
new File("report.pdf")
);
常见问题
Q:如何获取QQ邮箱的授权码?
A:登录QQ邮箱 -> 设置 -> 账户 -> POP3/SMTP服务 -> 开启服务 -> 生成授权码。注意授权码不是登录密码。
Q:发送邮件失败,提示连接超时?
A:检查SMTP服务器地址和端口是否正确,确认网络能访问SMTP服务器,检查防火墙设置。
Q:发送邮件失败,提示认证失败?
A:确认用户名、密码(授权码)是否正确,部分邮箱需要开启SMTP服务。
Q:HTML邮件样式显示不正常?
A:邮件客户端对CSS支持有限,建议使用内联样式,避免使用复杂的CSS3特性。
Q:如何发送给大量用户?
A:分批发送,每批不超过50个收件人,避免被判定为垃圾邮件。可以使用定时任务分批处理。
Q:内嵌图片和附件有什么区别?
A:内嵌图片直接显示在邮件正文中(使用cid引用),附件需要下载后查看。
总结
JakartaMailUtil提供了简洁高效的邮件发送能力,让复杂的JavaMail操作变得简单。
核心功能:
- 文本邮件:sendText() 快速发送纯文本
- HTML邮件:sendHtml() 支持富文本和样式
- 完整发送:send() 支持抄送、密送、附件
- 内嵌图片:通过imageMap实现图片内嵌
- 多账户:支持指定账户发送
典型应用:
- 用户通知:注册验证、密码重置
- 订单系统:订单确认、发货通知
- 系统监控:异常告警、性能报告
- 定时报表:日报周报自动发送
- 营销推广:活动通知、优惠信息
使用建议:
- 使用授权码而不是登录密码
- HTML邮件使用内联样式
- 大批量发送要分批处理
- 重要邮件添加异常处理和日志
- 敏感信息不要明文写在邮件中
JakartaMailUtil是企业应用中邮件功能的首选工具,配合模板引擎和定时任务可以构建完整的邮件通知系统。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)