在企業級應用中,郵件發送是用戶註冊驗證、密碼重置、通知公告等核心場景的標準配置。本文詳細講解如何封裝高可用的 JavaMail 工具類,並整合 Spring 框架實現業務解耦。
<!-- Maven 依賴 -->
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
<!-- Spring Boot 專用 starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
/**
* 企業級郵件發送工具類
* 支援 HTML 內容、附件、內嵌圖片、異步發送
*/
@Component
public class MailUtils {
private static final Logger log = LoggerFactory.getLogger(MailUtils.class);
@Value("${spring.mail.host}")
private String host;
@Value("${spring.mail.port}")
private int port;
@Value("${spring.mail.username}")
private String username;
@Value("${spring.mail.password}")
private String password;
@Value("${spring.mail.from}")
private String from;
/**
* 發送簡單文字郵件
*/
public void sendSimpleMail(String to, String subject, String content) {
sendMail(to, subject, content, false);
}
/**
* 發送 HTML 富文本郵件
*/
public void sendHtmlMail(String to, String subject, String htmlContent) {
sendMail(to, subject, htmlContent, true);
}
/**
* 發送帶附件郵件
*/
public void sendMailWithAttachment(String to, String subject, String content,
File attachment, boolean isHtml) {
try {
MimeMessage message = createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content, isHtml);
helper.addAttachment(attachment.getName(), attachment);
Transport.send(message);
log.info("郵件發送成功:{} -> {}", from, to);
} catch (MessagingException e) {
log.error("郵件發送失敗", e);
throw new BusinessException("郵件發送失敗:" + e.getMessage());
}
}
/**
* 核心發送邏輯
*/
private void sendMail(String to, String subject, String content, boolean isHtml) {
try {
MimeMessage message = createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, isHtml, "UTF-8");
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content, isHtml);
Transport.send(message);
log.info("郵件發送成功:{} -> {}", from, to);
} catch (MessagingException e) {
log.error("郵件發送失敗", e);
throw new BusinessException("郵件發送失敗:" + e.getMessage());
}
}
private MimeMessage createMimeMessage() throws MessagingException {
Properties props = new Properties();
props.put("mail.transport.protocol", "smtp");
props.put("mail.smtp.host", host);
props.put("mail.smtp.port", port);
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true"); // TLS 加密
props.put("mail.debug", "false");
Session session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
return new MimeMessage(session);
}
}
# application.yml
spring:
mail:
host: smtp.exmail.qq.com
port: 465
username: service@yourcompany.com
password: your_auth_code
from: service@yourcompany.com
properties:
mail:
smtp:
ssl:
enable: true
socketFactory:
class: javax.net.ssl.SSLSocketFactory
fallback: false
@Service
@Transactional
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Autowired
private MailUtils mailUtils;
@Override
public void register(User user) {
// 1. 業務邏輯處理
user.setState(0); // 0-未激活
String activationCode = UUID.randomUUID().toString().replace("-", "")
+ UUID.randomUUID().toString().replace("-", "");
user.setCode(activationCode);
userDao.save(user);
// 2. 異步發送激活郵件(避免阻塞主流程)
CompletableFuture.runAsync(() -> {
String activationUrl = "https://yourdomain.com/activate?code=" + activationCode;
String htmlContent = buildActivationEmail(activationUrl);
mailUtils.sendHtmlMail(user.getEmail(), "賬號激活通知", htmlContent);
});
}
private String buildActivationEmail(String activationUrl) {
return "<h1>歡迎註冊</h1>" +
"<p>請點擊下方連結完成賬號激活:</p>" +
"<a href='" + activationUrl + "'>" + activationUrl + "</a>" +
"<p>連結 24 小時內有效</p>";
}
}
| 錯誤現象 | 可能原因 | 解決方案 |
|---|---|---|
| Authentication failed | 密碼錯誤/未開啟 SMTP/需授權碼 | 檢查郵箱設定,使用授權碼而非登入密碼 |
| Connection timeout | 埠號錯誤/防火牆阻擋 | 確認 465(SSL) 或 587(STARTTLS) 埠通暢 |
| 550 Invalid recipient | 收件箱不存在/被封禁 | 驗證郵箱格式,清理無效地址 |
| 中文亂碼 | 編碼未設定 UTF-8 | MimeMessageHelper 指定 UTF-8,Subject 使用 MimeUtility.encodeText |
掌握 JavaMail 核心 API 並結合 Spring 生態封裝,能快速構建穩定可靠的郵件通知系統。關鍵在於:配置正確、異步非阻塞、模板化內容、完善監控與重試機制。