SpringBoot優雅地發送郵件
- 2019 年 10 月 4 日
- 筆記
在小明經歷的多個項目開發中,總會遇到消息通知的場景,比如某個廣告主提交一個表單,我們要通知提醒運營人員及時查看。
消息通知的形式也有很多,比如:簡訊、郵件、app推送等,本文主要給大家描述一下郵件通知的形式,因為郵件相比較其他通知渠道更方便實用(免費),除了簡單文本郵件(已經滿足大多數情形),本文還會重點說一下集成Thymeleaf模版引擎,使用HTML的形式發送郵件,儘管HTML內容不是標準化的消息格式,但是許多郵件客戶端至少支援標記語言的子集,這種方式相比較純文本展現形式更加友好。
準備
一個普通再也普通不了的SpringBoot項目
簡單文本發送
還是那句老話,在SpringBoot看來一切都是這麼便捷。它已經集成郵件發送所必需的庫模組,我們只需將以下依賴添加到pom.xml即可。
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-mail --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency>
郵箱服務結構
Spring框架中用於Java郵件支援的介面和類組織如下:
- MailSender interface:發送簡單基礎電子郵件的頂級介面;
- JavaMailSender interface:是
MailSender的子介面。它支援MIME消息,並且主要與MimeMessageHelper類一起用於創建MimeMessage。建議在此介面實現類JavaMailSenderImpl中使用MimeMessagePreparator機制; - JavaMailSenderImpl class:實現了
JavaMailSender的介面,它支援MimeMessage和SimpleMailMessage; - SimpleMailMessage class:用於創建簡單的郵件消息,包括from,to,cc,subject和text欄位;
- MimeMessagePreparator interface:提供一個回調介面,用於編寫MIME消息;
- MimeMessageHelper class:用於創建MIME消息的幫助類。它為HTML布局中的影像,典型郵件附件和文本內容提供支援。
在以下部分中,我將向大家展示如何使用這些介面和類:
配置文件
下面舉例163郵箱(最常用的):
spring: mail: host: smtp.163.com # 發件伺服器 username: [email protected] # 帳號 password: xxxx # 密碼(163需要授權第三方登錄密碼,請查看設置-客戶端授權碼密碼開通) port: 465 protocol: smtp default-encoding: utf-8 # 下面這些配置大家不用深究,主要用於配置ssl properties: mail: imap: ssl: socketFactory: fallback: false smtp: auth: true ssl: enable: true socketFactory: class: com.fintech.modules.base.util.mail.MailSSLSocketFactory starttls: enable: true required: true test-connection: false
程式碼
service層
按照常見的程式碼結構,我們先定義一個發送郵件的介面,負責創建和發送新的郵件消息。
public interface EmailService { /** * 發送簡單文本內容 * @param to 發件人 * @param subject 主題 * @param text 內容 */ void sendSimpleMessage(String to, String subject, String text); } 我們可以將一些常用的配置添加到yml配置文件當中
# 郵件配置 xiaoming: email: subject: "程式設計師小明" from: "[email protected]" to: "[email protected]" # 抄送人:類型定義為數組,可以配置多個 cc: - "[email protected]"
然後再通過註解注入到一個實體類中,這樣很優雅,隨用隨取:
@Configuration @ConfigurationProperties(prefix = "xiaoming.email") @Data public class EmailConfig { private String subject; private String from; private String to; private String[] cc; } 我們再定義一個類去實現這個介面:
@Slf4j @Service public class EmailServiceImpl implements EmailService { @Autowired public JavaMailSender emailSender; @Autowired private EmailConfig emailConfig; @Override public void sendSimpleMessage(String to, String subject, String text) { try { SimpleMailMessage message = new SimpleMailMessage(); message.setTo(to); message.setFrom("[email protected]"); message.setSubject(subject); message.setText(text); emailSender.send(message); } catch (MailException exception) { log.error(ExceptionUtil.stacktraceToString(exception)); } } } 測試
我們做一個簡單的測試:簡單的郵件是否能夠發送成功。
@RunWith(SpringRunner.class) @SpringBootTest public class EmailTest { @Autowired private EmailService emailService; @Test public void testSimple(){ emailService.sendSimpleMessage("[email protected]","XX籃球","你好,我想讓周琦代言!"); } } 使用html作為模版發送郵件
正在洋洋得意(準備划水)的時候,我們的產品突然對我說,「用簡單的文本發送郵件也太簡陋了吧,顯示不出來我們的產品檔次」,然後給我了一個樣式,讓我以這種形式發送,好啊,什麼都難不倒小明。我連忙找到我們的前端,(假裝低三下四地)讓她幫忙排一個頁面給我(這個工作我實在不想做,一是懶,二是人家前端肯定比我專業啊),為了保密,我簡化一下,大概是這樣的:
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head></head> <body> 姓 名:<span th:text="${userName}"></span> 性 別:<span th:text="${gender}"></span> </body> </html> 其實樣式很好看的,但是這都不是重點,我們就以此作為模版舉個例子,語法使用的都是thymeleaf,在此處就不再贅述,如果有想了解的可以去官網找。
增加Thymeleaf dependency
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
service層
創建另一個服務類,它主要通過讀取html模版封裝數據準備郵件內容,在我們之前的示例中,這是一個簡單的文本消息。
@Service public class MailContentBuilder { @Autowired private TemplateEngine templateEngine; @Autowired public MailContentBuilder(TemplateEngine templateEngine) { this.templateEngine = templateEngine; } public String build(Map<String, Object> message) { Context context = new Context(); context.setVariables(message); return templateEngine.process("email", context); } } 在EmailService增加介面:
public interface EmailService { /** * 發送簡單文本內容 * @param to 發件人 * @param subject 主題 * @param text 內容 */ void sendSimpleMessage(String to, String subject, String text); /** * 傳遞多個變數,用於動態更換頁面模版內容 * @param emailInfoMap */ void prepareAndSend(Map<String,Object> emailInfoMap); } 在EmailServiceImpl增加發送html形式郵件的實現方法:
@Override public void prepareAndSend(Map<String,Object> emailInfoMap) { MimeMessagePreparator messagePreparator = mimeMessage -> { MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage); messageHelper.setFrom(emailConfig.getFrom()); messageHelper.setTo(emailConfig.getTo()); messageHelper.setCc(emailConfig.getCc()); messageHelper.setSubject(emailConfig.getSubject()); // messageHelper.setText(message); String content = mailContentBuilder.build(info); messageHelper.setText(content,true); }; try { emailSender.send(messagePreparator); } catch (MailException e) { // runtime exception; compiler will not force you to handle it } } 測試
@RunWith(SpringRunner.class) @SpringBootTest public class EmailTest { @Autowired private EmailService emailService; @Test public void testHtml(){ HashMap<String, Object> map = new HashMap<>(); map.put("userName","程式設計師小明"); map.put("gender","男"); emailService.prepareAndSend(map); } } 整個Springboot發送郵件的場景已經復盤結束,大家如果有用到的速速體驗吧!