1、前言
發(fā)送郵件應(yīng)該是網(wǎng)站的必備拓展功能之一笛匙,注冊(cè)驗(yàn)證侨把,忘記密碼或者是給用戶發(fā)送營(yíng)銷信息。正常我們會(huì)用JavaMail相關(guān)api來寫發(fā)送郵件的相關(guān)代碼妹孙,但現(xiàn)在springboot提供了一套更簡(jiǎn)易使用的封裝秋柄。
2、Mail依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>${spring-boot-mail.version}</version>
</dependency>
來看看其依賴樹:
可以看到spring-boot-starter-mail-xxx.jar對(duì)Sun公司的郵件api功能進(jìn)行了相應(yīng)的封裝蠢正。
3骇笔、Mail自動(dòng)配置類: MailSenderAutoConfiguration
其實(shí)肯定可以猜到Spring Boot對(duì)Mail功能已經(jīng)配置了相關(guān)的基本配置信息,它是Spring Boot官方提供嚣崭,其類為MailSenderAutoConfiguration:
//MailSenderAutoConfiguration
@Configuration
@ConditionalOnClass({ MimeMessage.class, MimeType.class })
@ConditionalOnMissingBean(MailSender.class)
@Conditional(MailSenderCondition.class)
@EnableConfigurationProperties(MailProperties.class)
@Import(JndiSessionConfiguration.class)
public class MailSenderAutoConfiguration {
private final MailProperties properties;
private final Session session;
public MailSenderAutoConfiguration(MailProperties properties,
ObjectProvider<Session> session) {
this.properties = properties;
this.session = session.getIfAvailable();
}
@Bean
public JavaMailSenderImpl mailSender() {
JavaMailSenderImpl sender = new JavaMailSenderImpl();
if (this.session != null) {
sender.setSession(this.session);
}
else {
applyProperties(sender);
}
return sender;
}
//other code...
}
首先笨触,它會(huì)通過注入Mail的屬性配置類MailProperties:
@ConfigurationProperties(prefix = "spring.mail")
public class MailProperties {
private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
/**
* SMTP server host.
*/
private String host;
/**
* SMTP server port.
*/
private Integer port;
/**
* Login user of the SMTP server.
*/
private String username;
/**
* Login password of the SMTP server.
*/
private String password;
/**
* Protocol used by the SMTP server.
*/
private String protocol = "smtp";
/**
* Default MimeMessage encoding.
*/
private Charset defaultEncoding = DEFAULT_CHARSET;
/**
* Additional JavaMail session properties.
*/
private Map<String, String> properties = new HashMap<String, String>();
/**
* Session JNDI name. When set, takes precedence to others mail settings.
*/
private String jndiName;
/**
* Test that the mail server is available on startup.
*/
private boolean testConnection;
//other code...
}
在MailSenderAutoConfiguration自動(dòng)配置類中,創(chuàng)建了一個(gè)Bean雹舀,其類為JavaMailSenderImpl芦劣,它是Spring專門用來發(fā)送Mail郵件的服務(wù)類,SpringBoot也使用它來發(fā)送郵件说榆。它是JavaMailSender接口的實(shí)現(xiàn)類虚吟,通過它的send()方法來發(fā)送不同類型的郵件,主要分為兩類签财,一類是簡(jiǎn)單的文本郵件稍味,不帶任何html格式,不帶附件荠卷,不帶圖片等簡(jiǎn)單郵件模庐,還有一類則是帶有html格式文本或者鏈接,有附件或者圖片的復(fù)雜郵件油宜。
4掂碱、發(fā)送郵件
通用配置application.properties:
# 設(shè)置郵箱主機(jī)
spring.mail.host=smtp.qq.com
# 設(shè)置用戶名
spring.mail.username=xxxxxx@qq.com
# 設(shè)置密碼怜姿,該處的密碼是QQ郵箱開啟SMTP的授權(quán)碼而非QQ密碼
spring.mail.password=pwvtabrwxogxidac
# 設(shè)置是否需要認(rèn)證,如果為true,那么用戶名和密碼就必須的疼燥,
# 如果設(shè)置false沧卢,可以不設(shè)置用戶名和密碼,當(dāng)然也得看你的對(duì)接的平臺(tái)是否支持無密碼進(jìn)行訪問的醉者。
spring.mail.properties.mail.smtp.auth=true
# STARTTLS[1] 是對(duì)純文本通信協(xié)議的擴(kuò)展但狭。它提供一種方式將純文本連接升級(jí)為加密連接(TLS或SSL),而不是另外使用一個(gè)端口作加密通信撬即。
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
mail.from=${spring.mail.username}
mail.to=yyyyyy@qq.com
由于使用QQ郵箱的用戶占多數(shù)立磁,所以這里選擇QQ郵箱作為測(cè)試。還有注意的是spring.mail.password這個(gè)值不是QQ郵箱的密碼剥槐,而是QQ郵箱給第三方客戶端郵箱生成的授權(quán)碼唱歧。具體要登錄QQ郵箱,點(diǎn)擊設(shè)置粒竖,找到SMTP服務(wù):
默認(rèn)SMTP服務(wù)是關(guān)閉的颅崩,即默認(rèn)狀態(tài)為關(guān)閉狀態(tài),如果是第一次操作蕊苗,點(diǎn)擊開啟后沿后,會(huì)通過驗(yàn)證會(huì)獲取到授權(quán)碼;而我之前已經(jīng)開啟過SMTP服務(wù)朽砰,所以直接點(diǎn)擊生成授權(quán)碼后通過驗(yàn)證獲取到授權(quán)碼尖滚。
自定義的MailProperties配置類,用于解析mail開頭的配置屬性:
@Component
@ConfigurationProperties(prefix = "mail")
public class MailProperties {
private String from;
private String to;
//getter and setter...
}
4.1锅移、測(cè)試發(fā)送簡(jiǎn)單文本郵件
@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class SimpleMailTest {
@Autowired
private MailService mailService;
@Test
public void sendMail(){
mailService.sendSimpleMail("測(cè)試Springboot發(fā)送郵件", "發(fā)送郵件...");
}
}
sendSimpleMail():
@Override
public void sendSimpleMail(String subject, String text) {
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setFrom(mailProperties.getFrom());
mailMessage.setTo(mailProperties.getTo());
mailMessage.setSubject(subject);
mailMessage.setText(text);
javaMailSender.send(mailMessage);
}
觀察結(jié)果:
4.2熔掺、測(cè)試發(fā)送帶有鏈接和附件的復(fù)雜郵件
事先準(zhǔn)備一個(gè)文件file.txt饱搏,放在resources/public/目錄下非剃。
@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class MimeMailTest {
@Autowired
private MailService mailService;
@Test
public void testMail() throws MessagingException {
Map<String, String> attachmentMap = new HashMap<>();
attachmentMap.put("附件", "file.txt的絕對(duì)路徑");
mailService.sendHtmlMail("測(cè)試Springboot發(fā)送帶附件的郵件", "歡迎進(jìn)入<a href=\"http://www.baidu.com\">百度首頁</a>", attachmentMap);
}
}
sendHtmlMail():
@Override
public void sendHtmlMail(String subject, String text, Map<String, String> attachmentMap) throws MessagingException {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
//是否發(fā)送的郵件是富文本(附件,圖片推沸,html等)
MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true);
messageHelper.setFrom(mailProperties.getFrom());
messageHelper.setTo(mailProperties.getTo());
messageHelper.setSubject(subject);
messageHelper.setText(text, true);//重點(diǎn)备绽,默認(rèn)為false,顯示原始html代碼鬓催,無效果
if(attachmentMap != null){
attachmentMap.entrySet().stream().forEach(entrySet -> {
try {
File file = new File(entrySet.getValue());
if(file.exists()){
messageHelper.addAttachment(entrySet.getKey(), new FileSystemResource(file));
}
} catch (MessagingException e) {
e.printStackTrace();
}
});
}
javaMailSender.send(mimeMessage);
}
觀察結(jié)果:
4.3肺素、測(cè)試發(fā)送模版郵件
這里使用Freemarker作為模版引擎。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
<version>${spring-boot-freemarker.version}</version>
</dependency>
事先準(zhǔn)備一個(gè)模版文件mail.ftl
<html>
<body>
<h3>你好宇驾, <span style="color: red;">${username}</span>, 這是一封模板郵件!</h3>
</body>
</html>
模版測(cè)試類:
@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class MailTemplateTest {
@Autowired
private MailService mailService;
@Test
public void testFreemarkerMail() throws MessagingException, IOException, TemplateException {
Map<String, Object> params = new HashMap<>();
params.put("username", "Cay");
mailService.sendTemplateMail("測(cè)試Springboot發(fā)送模版郵件", params);
}
}
sendTemplateMail():
@Override
public void sendTemplateMail(String subject, Map<String, Object> params) throws MessagingException, IOException, TemplateException {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
helper.setFrom(mailProperties.getFrom());
helper.setTo(mailProperties.getTo());
Configuration configuration = new Configuration(Configuration.VERSION_2_3_28);
configuration.setClassForTemplateLoading(this.getClass(), "/templates");
String html = FreeMarkerTemplateUtils.processTemplateIntoString(configuration.getTemplate("mail.ftl"), params);
helper.setSubject(subject);
helper.setText(html, true);//重點(diǎn)倍靡,默認(rèn)為false,顯示原始html代碼课舍,無效果
javaMailSender.send(mimeMessage);
}
觀察結(jié)果: