在企業級應用開發中,定時發送電子郵件是常見需求,例如:定時發送報表、系統通知、生日祝福等。本文將詳細介紹如何在 Java Web 專案中,結合 java.util.Timer 與 JavaMail API,實現應用啟動時自動排程、定時發送郵件的完整方案。
Java 標準庫提供的 java.util.Timer 是一個簡單的排程工具,搭配 TimerTask 即可實現週期性任務執行。其核心方法 schedule(TimerTask task, long delay, long period) 參數說明:
TimerTask 的具體任務類24*60*60*1000 代表每 24 小時執行一次為確保排程器在 Web 應用啟動時自動啟動、關閉時自動銷毀,必須實作 javax.servlet.ServletContextListener 接口,並在 web.xml 中註冊。這樣排程器的生命週期將與整個 Web 應用同步。
public class EmailSchedulerListener implements ServletContextListener {
private Timer timer = null;
@Override
public void contextInitialized(ServletContextEvent sce) {
timer = new Timer(true); // daemon thread
sce.getServletContext().log("排程器已啟動");
// 每 24 小時執行一次發送郵件任務
timer.schedule(new SendEmailTask(sce.getServletContext()), 0, 24 * 60 * 60 * 1000);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
if (timer != null) {
timer.cancel();
sce.getServletContext().log("排程器已銷毀");
}
}
}
繼承 TimerTask,在 run() 方法中整合 JavaMail 發送邏輯。需準備 activation.jar 與 mail.jar 放入專案 WEB-INF/lib 目錄。
public class SendEmailTask extends TimerTask {
private ServletContext context;
public SendEmailTask(ServletContext context) {
this.context = context;
}
@Override
public void run() {
try {
Properties props = new Properties();
props.put("mail.smtp.host", "smtp.163.com");
props.put("mail.smtp.auth", "true");
Session session = Session.getInstance(props);
session.setDebug(true); // 開啟除錯輸出
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("your_email@163.com"));
message.setRecipient(Message.RecipientType.TO, new InternetAddress("recipient@example.com"));
message.setSubject("定時郵件測試");
message.setSentDate(new Date());
// 郵件內容支援 HTML
MimeBodyPart bodyPart = new MimeBodyPart();
bodyPart.setContent("<h1>這是定時發送的測試郵件</h1>", "text/html;charset=utf-8");
MimeMultipart multipart = new MimeMultipart();
multipart.addBodyPart(bodyPart);
message.setContent(multipart);
message.saveChanges();
Transport transport = session.getTransport("smtp");
transport.connect("smtp.163.com", "your_email@163.com", "your_password");
transport.sendMessage(message, message.getAllRecipients());
transport.close();
context.log("郵件發送成功");
} catch (Exception e) {
context.log("郵件發送失敗: " + e.getMessage());
e.printStackTrace();
}
}
}
<web-app>
<listener>
<listener-class>com.example.listener.EmailSchedulerListener</listener-class>
</listener>
</web-app>
run() 方法中必須捕獲所有異常,否則 Timer 會終止後續排程。本方案利用 Servlet 監聽器管理 Timer 生命週期,結合 JavaMail 實現輕量級的定時郵件發送功能,適合中小型專案快速落地。對於高可用、分散式場景,建議升級至 Quartz 或 Spring @Scheduled 搭配分散式鎖方案。