使用SpringBoot发送邮件
邮件发送其实是一个非常常见的需求,用户注册,找回密码等地方,都会用到,Spring Boot 中对于邮件发送,提供了相关的自动化配置类,使得邮件发送变得非常容易。
1、前置工作
目前国内大部分的邮件服务商都不允许直接使用用户名/密码的方式来在代码中发送邮件,都是要先申请授权码,这里以 QQ 邮箱为例,向大家演示授权码的申请流程:
首先我们需要先登录 QQ 邮箱网页版,点击上方的设置按钮:然后点击账户选项卡:在账户选项卡中找到开启POP3/SMTP选项,如下:
点击开启,开启相关功能,开启过程需要手机号码验证,按照步骤操作即可,不赘述。开启成功之后,即可获取一个授权码,将该号码保存好,一会使用。
2、引入依赖、配置邮箱基本信息
<!--集成发送邮件的功能-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
然后在yml配置文件中进行配置
spring:
mail:
host: smtp.qq.com # 设置邮箱主机
port: 587 # SMTP 服务器的端口
username: yyds@qq.com # 设置用户名
password: yyds # 设置密码,该处的密码是QQ邮箱开启SMTP的授权码而非QQ密码
mail:
from: ${spring.mail.username}
to: yyds@163.com
做完这些之后,Spring Boot 就会自动帮我们配置好邮件发送类,相关的配置在
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration
类中,部分源码如下:
@Configuration
@ConditionalOnClass({ MimeMessage.class, MimeType.class, MailSender.class })
@ConditionalOnMissingBean(MailSender.class)
@Conditional(MailSenderCondition.class)
@EnableConfigurationProperties(MailProperties.class)
@Import({ MailSenderJndiConfiguration.class, MailSenderPropertiesConfiguration.class })
public class MailSenderAutoConfiguration {
}
可以看到,导入了另外一个配置 MailSenderPropertiesConfiguration
类,这个类中,提供了邮件发送相关的工具类,源码如下:
@Configuration
@ConditionalOnProperty(prefix = "spring.mail", name = "host")
class MailSenderPropertiesConfiguration {
private final MailProperties properties;
MailSenderPropertiesConfiguration(MailProperties properties) {
this.properties = properties;
}
@Bean
@ConditionalOnMissingBean
public JavaMailSenderImpl mailSender() {
JavaMailSenderImpl sender = new JavaMailSenderImpl();
applyProperties(sender);
return sender;
}
}
可以看到,这里创建了一个 JavaMailSenderImpl
的实例, JavaMailSenderImpl
是 JavaMailSender
的一个实现,我们将使用 JavaMailSenderImpl
来完成邮件的发送工作。
3、Service层代码
自定义的MailProperties配置类,用于解析mail开头的配置属性
package com.yyds.domain;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "mail")
public class MailProperties {
private String from;
private String to;
}
service层
package com.yyds.service;
import freemarker.template.TemplateException;
import javax.mail.MessagingException;
import java.io.IOException;
import java.util.Map;
public interface MailService {
void sendSimpleMail(String subject, String text) ;
void sendHtmlMail(String subject, String text, Map<String, String> attachmentMap) throws MessagingException;
void sendTemplateMail(String subject, Map<String, Object> params) throws MessagingException, IOException, TemplateException;
}
package com.yyds.service.impl;
import com.yyds.domain.MailProperties;
import com.yyds.service.MailService;
import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
import java.io.IOException;
import java.util.Map;
@Service
public class MailServiceImpl implements MailService {
@Autowired
private JavaMailSender javaMailSender;
@Autowired
private MailProperties myMailProperties;
/**
* 发送简单文本邮件
*/
@Override
public void sendSimpleMail(String subject, String text) {
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setFrom(myMailProperties.getFrom());
mailMessage.setTo(myMailProperties.getTo());
mailMessage.setSubject(subject);
mailMessage.setText(text);
javaMailSender.send(mailMessage);
}
/**
* 发送带有链接和附件的复杂邮件
*/
@Override
public void sendHtmlMail(String subject, String text, Map<String, String> attachmentMap) throws MessagingException {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
//是否发送的邮件是富文本(附件,图片,html等)
MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true);
messageHelper.setFrom(myMailProperties.getFrom());
messageHelper.setTo(myMailProperties.getTo());
messageHelper.setSubject(subject);
messageHelper.setText(text, true);//重点,默认为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);
}
/**
* 发送模版邮件
*/
@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(myMailProperties.getFrom());
helper.setTo(myMailProperties.getTo());
freemarker.template.Configuration configuration = new freemarker.template.Configuration(freemarker.template.Configuration.VERSION_2_3_19);
TemplateLoader templateLoader = new ClassTemplateLoader(this.getClass(), "/templates/");
configuration.setTemplateLoader(templateLoader);
Template template = configuration.getTemplate("mail.ftl");
String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, params);
helper.setSubject(subject);
helper.setText(html, true);//重点,默认为false,显示原始html代码,无效果
javaMailSender.send(mimeMessage);
}
}
4、发送邮件
4.1 测试发送简单文本邮件
@SpringBootTest(classes = BootStartApplication.class)
public class MimeMailTest {
@Autowired
private MailService mailService;
@Test
public void sendMail() {
mailService.sendSimpleMail("测试Springboot发送邮件", "发送邮件...");
}
}
4.2 测试发送带有链接和附件的复杂邮件
package com.yyds;
import com.yyds.service.MailService;
import freemarker.template.TemplateException;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import javax.mail.MessagingException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@SpringBootTest(classes = BootStartApplication.class)
public class MimeMailTest {
@Autowired
private MailService mailService;
@Test
public void testMail() throws MessagingException {
Map<String, String> attachmentMap = new HashMap<>();
attachmentMap.put("附件", "D:\\D_ENL_MRO数据统计.xlsx");
mailService.sendHtmlMail("测试Springboot发送带附件的邮件2", "欢迎进入<a href=\"http://www.baidu.com\">百度首页</a>", attachmentMap);
}
}
4.3 测试发送发送模版邮件
首先需要引入 Freemarker 依赖:
<!--整合freemarker-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
然后在 resources/templates
目录下创建一个 mail.ftl
作为邮件发送模板:
<html>
<body>
<h3>你好, <span style="color: red;">${username}</span>, 这是一封模板邮件!</h3>
</body>
</html>
package com.yyds;
import com.yyds.service.MailService;
import freemarker.template.TemplateException;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import javax.mail.MessagingException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@SpringBootTest(classes = BootStartApplication.class)
public class MimeMailTest {
@Autowired
private MailService mailService;
@Test
public void testFreemarkerMail() throws MessagingException, IOException, TemplateException {
Map<String, Object> params = new HashMap<>();
params.put("username", "Tom");
mailService.sendTemplateMail("测试Springboot发送模版邮件", params);
}
}