2021.2.24 更新
1 概述
Spring Boot整合邮件服务,包括发送普通的文本邮件以及带附件的邮件。
2 邮箱选择
这里选择的是QQ邮箱作为发送的邮箱,当然也可以选择其他的邮箱,只是具体的配置不一样。
使用QQ邮箱的话,需要在个人设置中开启SMTP服务:


发送短信后完成验证即可,会有一个授权码,先复制下来保存。
3 具体实现
3.1 依赖
提供了starter:
1<dependency> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-mail</artifactId> 4</dependency>
gradle:
implementation 'org.springframework.boot:spring-boot-starter-mail'
3.2 邮件接口
只有两个简单的接口,一个是发送纯文本的,一个是发送带附件的:
1public interface MailService { 2 void sendSimpleMail(String to,String subject,String content); 3 void sendAttachmentMail(String to, String subject, String content, Path file) throws MessagingException; 4}
3.3 接口实现
1@Service 2@RequiredArgsConstructor(onConstructor = @__(@Autowired)) 3public class MailServiceImpl implements MailService{ 4 private final JavaMailSender sender; 5 6 @Value("${spring.mail.username}") 7 private String from; 8 9 @Override 10 public void sendSimpleMail(String to, String subject, String content) { 11 SimpleMailMessage message = new SimpleMailMessage(); 12 message.setFrom(from); 13 message.setTo(to); 14 message.setSubject(subject); 15 message.setText(content); 16 sender.send(message); 17 } 18 19 @Override 20 public void sendAttachmentMail(String to, String subject, String content, Path file) throws MessagingException { 21 MimeMessage message = sender.createMimeMessage(); 22 MimeMessageHelper helper = new MimeMessageHelper(message,true); 23 helper.setFrom(from); 24 helper.setTo(to); 25 helper.setSubject(subject); 26 helper.setText(content); 27 helper.addAttachment(file.getFileName().toString(),new FileSystemResource(file)); 28 sender.send(message); 29 } 30}
JavaMailSender是Spring Boot携带的邮件发送接口,注入后可以发送SimpleMailMessage以及MimeMessage类型的信息。
SimpleMailMessage:简单的邮件信息对象,封装了一些常见的属性,比如寄信地址以及收信地址,发送日期,主题,内容等MimeMessage:发送MIME类型的邮件信息,MIME指的是Multipurpose Internet Mail Extensiosns,是描述消息内容类型的因特网标准,能包含文本,图像,音频,视频以及其他应用程序专用的数据MimeMessageHelper:用于设置MimeMessage属性的类,可以利用其中的addAttachment添加附件setFrom/setTo/setSubject/setText:分别表示设置寄信地址/收信地址/主题/内容
3.4 测试类
1@SpringBootTest 2@RequiredArgsConstructor(onConstructor = @__(@Autowired)) 3class DemoApplicationTests { 4 private final MailService service; 5 6 @Test 7 void contextLoads() throws URISyntaxException, MessagingException { 8 service.sendSimpleMail("xxx@xxx.com","这是主题","这是内容"); 9 service.sendAttachmentMail("xxxx@xx.com","这是主题","这是内容", Path.of(Objects.requireNonNull(getClass().getClassLoader().getResource("pic/1.jpg")).toURI())); 10 //附件为resources下pic/1.jpg 11 service.sendAttachmentMail("xxxx@xxx.com","这是主题","这是内容", Path.of("/","srv","http","1.jpg")); 12 //附件为/srv/http/1.jpg 13 }
发送文本直接指定主题和内容即可,发送带附件的话:
- 如果是
resources下的内容,使用getClass().getClassLoader().getReource("xxx/xxx") - 如果是绝对路径,使用
Path.of("/","path1","path2",...,"filename")
3.5 配置文件
1spring: 2 mail: 3 host: smtp.qq.com 4 username: xxxxxxx@qq.com 5 password: xxxxxxxxxx 6 port: 465 7 properties: 8 mail: 9 smtp: 10 ssl: 11 enable: true 12 auth: true 13 starttls: 14 enable: true 15 required: true
作为Demo使用只需要修改username以及password即可。
username:发送的用户邮箱password:不是邮箱密码,而是授权码,就是刚才开启SMTP服务出现的授权码
其他配置说明:
host:SMTP服务器地址port:端口,可以选择465/587,host以及port可以参考QQ邮箱文档properties:里面都是一些安全设置,开启SSL以及认证等
3.6 测试
修改测试类的邮箱,运行单元测试即可。

如果没通过,可以参考这里,罗列了常见的错误码以及可能的解决方案。
4 加密
由于用户名以及密码都直接写在了配置文件中,如果泄露的话会很危险,因此需要对配置文件进行加密。
具体的话可以参考笔者之前的原力计划文章,戳这里。
4.1 依赖
1<dependency> 2 <groupId>com.github.ulisesbocchio</groupId> 3 <artifactId>jasypt-spring-boot-starter</artifactId> 4 <version>3.0.3</version> 5</dependency>
gradle:
implementation("com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.3")
4.2 配置文件
配置文件只需要加上加密口令即可:
1jasypt: 2 encryptor: 3 password: test
默认使用的是PBE加密算法,PBE其实是一种组合加密算法,默认是采用HCMA算法(混合CMA-ES算法)+SHA512消息摘要算法+AES256对称加密算法。
另外,如果不想在配置文件直接写上加密的口令,可以使用以下三种方法对口令进行参数化:
命令行参数(运行时设置):
java -jar xxx.jar --jasypt.encryptor.password=test
应用环境变量(运行时设置):
java -Djasypt.encryptor.password=test -jar xxx.jar
系统环境变量(在配置文件中设置):
1jasypt: 2 encryptor: 3 password: ${TEST} 4# 表示获取环境变量TEST的值作为加密口令
4.3 测试类
新建一个测试类:
1@SpringBootTest 2@RequiredArgsConstructor(onConstructor = @__(@Autowired)) 3public class EncryptAndDecrypt { 4 private final StringEncryptor encryptor; 5 @Value("${spring.mail.username}") 6 private String username; 7 @Value("${spring.mail.password}") 8 private String password; 9 10 @Test 11 public void encrypt() 12 { 13 System.out.println(encryptor.encrypt(username)); 14 System.out.println(encryptor.encrypt(password)); 15 } 16 17 @Test 18 public void decrypt() 19 { 20 System.out.println(username); 21 System.out.println(password); 22 } 23}
4.4 获取密文
假设明文如下:

运行encrypt即可,输出如下:

4.5 替换明文
加上前缀ENC(以及后缀)去替换明文:

4.6 测试
获取明文直接运行decrypt即可,输出:

这样就完成加密了。
5 源码
Java版:
Kotlin版: