记录一下,Spring Boot如何发送邮件。分为以下五种

  • 发送文本邮件
  • 发送html邮件
  • 发送附件邮件
  • 发送图片邮件
  • 发送模板邮件

配置环境

引入maven坐标。spring-boot-starter-mailspring-boot-starter-thymeleaf

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!--模板引擎-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--模板引擎-->

配置配置文件

1
2
3
4
5
6
spring:
mail:
host: smtp.qq.com #smtp.126.com
username: 928301810@qq.com
password: ···· #POP3授权码
default-encoding: UTF-8

这里的password,并不是你邮箱的登录密码,而是POP3授权码。

配置邮箱(以qq邮箱为例)

点击邮箱的设置,然后点击账户

image-20220808212318162

将获取的POP3授权码,设置到配置文件中。

发送邮件

注入JavaMailSender对象,这是一个接口。然后获取配置文件中username配置信息。作为发送方

1
2
3
4
5
@Value("${spring.mail.username}")
private String from;

@Autowired
private JavaMailSender sender;

发送文本文件

Service层

这里先用SimpleMailMessage对象,封装消息,包括:发送方,接收方、邮件主题、邮件内容。

然后使用JavaMailSender对象,发送消息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Service
public class MailServiceImpl implements MailService {

@Value("${spring.mail.username}")
private String from;

@Autowired
private JavaMailSender sender;
@Override
public void sendmail(String to, String subject, String content) {
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(to);
message.setSubject(subject);
message.setText(content);
message.setFrom(from);

sender.send(message);

}
}

测试

1
2
3
4
5
@Test
void contextLoads() {
service.sendmail("928301810@qq.com","HELLO","这是我用SrongBoot发送的第一封邮件");

}
  • to:收件方
  • subject:邮件主题
  • content:邮件内容

发送html文件

Service层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Service
public class MailServiceImpl implements MailService {

@Value("${spring.mail.username}")
private String from;

@Autowired
private JavaMailSender sender;

@Override
public void sendhtml(String to, String subject, String content) throws MessagingException {
MimeMessage message = sender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message,true);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content,true);
sender.send(message);
}
}

这是使用JavaMailSendercreateMimeMessage方法,来获取MimeMessage对象。

MimeMessageHelper的构造方法的两个参数,一个是message,另一个是true

true表示发送的邮件是multipart邮件。简单来说,multpart是一种可以内嵌html,包含附件的邮件类型。

然后测试代码如下:

1
2
3
4
5
6
7
8
9
10
11
@Test
void TestSendHTML() throws MessagingException {
String content = "<html>\n"+
"<body>\n"+
"<h3>这是我用SrongBoot发送的第二封邮件</h3>\n"+
"</body>\n"+
"</html>";

service.sendhtml("928301810@qq.com","HELLO",content);

}

发送带附件的邮件

Service层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Service
public class MailServiceImpl implements MailService {

@Value("${spring.mail.username}")
private String from;

@Autowired
private JavaMailSender sender;

@Override
public void sendhtmlwithFile(String to, String subject, String content, String[] filepaths) throws MessagingException, FileNotFoundException {
MimeMessage message = sender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message,true);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content,true);

for (String filepath : filepaths) {
FileSystemResource file = new FileSystemResource(new File(filepath));
String filename = file.getFilename();
assert filename != null;
helper.addAttachment(filename,file);
}

sender.send(message);
}
}

从参数String[] filepaths,可以看出,它是可以携带多个附件的。与发送html不同的是,多了如下代码

1
2
3
4
5
6
for (String filepath : filepaths) {
FileSystemResource file = new FileSystemResource(new File(filepath));
String filename = file.getFilename();
assert filename != null;
helper.addAttachment(filename,file);
}

测试代码如下:

1
2
3
4
5
6
7
8
9
10
@Test
void TestSendwithFile() throws MessagingException, FileNotFoundException {
String content = "<html>\n"+
"<body>\n"+
"<h3>这是我用SrongBoot发送的第三封带附件的邮件</h3>\n"+
"</body>\n"+
"</html>";
String[] filepaths = {"C:\\Users\\TJS\\Desktop\\力扣算法题链接.md", "C:\\Users\\TJS\\Desktop\\nginx-1.16.1.tar.gz"};
service.sendhtmlwithFile("928301810@qq.com","HELLO",content, filepaths);
}

发送带有图片的邮件

Service层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Service
public class MailServiceImpl implements MailService {

@Value("${spring.mail.username}")
private String from;

@Autowired
private JavaMailSender sender;

@Override
public void sendImage(String to, String subject, String content,String[][] images) throws MessagingException {
MimeMessage message = sender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message,true);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content,true);

for (String[] image : images) {
String path = image[0];
String rscId = image[1];
FileSystemResource resource = new FileSystemResource(new File(path));
helper.addInline(rscId,resource);
}
sender.send(message);
}
}

可以内嵌多张图片,传入images字符串数组。

images[i][0]:图片的路径,可以是绝对路径,也可以是相对路径。

images[i][1]:图片的id。因为它内嵌到邮件中,实际就是以html的方式内嵌到邮件中,因此需要使用<img>标签

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Test
void TestSendImage() throws MessagingException {
String[][] images = new String[][]{
{"src/main/resources/static/2.JPG","002"},
{"src/main/resources/static/3.JPG","003"},
};


StringBuilder content = new StringBuilder("<html>\n" +
"<body>\n" +
"<h3>这是我用SrongBoot发送的第四封带图片的邮件</h3>\n");

//-------------------------------------------------------------------------------
for (String[] image : images) {
content.append("<img src='cid:").append(image[1]).append("'></img>");
}
//<img src="cid:image[1]"></img>
//----------------------------------------------------------------------------------

content.append("</body>\n"+ "</html>");

service.sendImage("928301810@qq.com","HELLO", content.toString(),images);
}

发送模板邮件

生活中有很多场景特别适用模板邮件,比如:

  • 用户注册
  • 忘记密码

这些邮件都有一个特点:邮件的主体内容不会变化,变化的是用户的信息。在这个使用的模板引擎是:thymeleaf

maven坐标已经再前面引入。service层使用发送html的就可以。

然后再resouce的templates文件夹中,创建html模板。

image-20220808215552489

html代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<!--声明thymeleaf-->
<head>
<meta charset="UTF-8"/>
<!-- 必须闭合 meta标签-->
<title>邮件模板</title>
</head>
<body>
您好,感谢您的注册,这是一封验证邮件,请点击下面的链接完成注册,感谢您的支持!
<!--/*@thymesVar id="id" type="java"*/-->
<a href="#" th:href="@{http://www.ityouknow.com/register/{id}(id=${id})}">激活账号</a>
</body>
</html>

我们可以看到只有id是变化的。{id}(id=${id})

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@SpringBootTest
class SpringbootMailApplicationTests {

@Autowired
private MailService service;

@Autowired
private TemplateEngine templateEngine;

@Test
public void TestTemplete() throws MessagingException {
Context context = new Context();
context.setVariable("id","006");

String emailTemplate = templateEngine.process("EmailTemplate", context);
service.sendhtml("928301810@qq.com","HELLO",emailTemplate);
}
}

我们需要注入TemplateEngine来解析html模板。

创建Context对象,来封装变量。然后使用TemplateEngine来解析模板,因此需要传入Context对象。

关于异常的处理

我们看到,在发送邮件过程中,会产生例如MessagingException异常。我们处理的方法是不断的向外抛。

但在项目中的操作通常是一个异步的操作,因此它不必要去影响主业务。因此这个异常需要我们自己来处理,而不是统统抛出去。这种情况下,我们需要使用Log,以日志的形式记录下来。

以发送HTML邮件的代码为例,原代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Service
public class MailServiceImpl implements MailService {
@Value("${spring.mail.username}")
private String from;

@Autowired
private JavaMailSender sender;

@Override
public void sendhtml(String to, String subject, String content) throws MessagingException {
MimeMessage message = sender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message,true);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content,true);
sender.send(message);
}
}

使用try···catch来捕获异常,并记录日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Service
public class MailServiceImpl implements MailService {


private final Logger logger = LoggerFactory.getLogger(this.getClass());//日志对象

@Value("${spring.mail.username}")
private String from;

@Autowired
private JavaMailSender sender;

@Override
public void sendhtml(String to, String subject, String content) {
logger.info("发送静态邮件开始,接收方{},{}",to,subject);
MimeMessage message = sender.createMimeMessage();
MimeMessageHelper helper = null;
try {
helper = new MimeMessageHelper(message,true);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content,true);
sender.send(message);
logger.info("发送成功!");
} catch (MessagingException e) {
logger.error("发送失败,{}",e.toString());
}
}
}

常见错误

  • 421 HL:ICC该IP同时并发连接数过大
  • 451 Requested mail action not taken: too much fail …登录失败次数过多,被临时禁止登录。
  • 553 authentication is required 认证失败【账号密码有可能不对,或者协议配置不对,等等】

参考地址:http://help.163.com/09/1224/17/5RAJ4LMHO0753VB8.html【它会对每一个错误进行解释】

__END__