Spring Boot发送邮件以及阿里云服务器无法发送邮件的问题解决

1,616 阅读4分钟

网站邮件发送是一个很实用的功能,例如验证码,通知等等。其实使用Spring Boot发送邮件是一件非常简单的事情。

1,配置

首先在项目pom.xml文件中添加依赖:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-mail</artifactId>
</dependency>

然后打开Spring Boot配置文件application.yml,在里面加入邮件配置:

# 发件邮件配置
spring:
  mail:
    host: "邮箱SMTP服务器"
    username: "你的邮箱(用于发件)"
    password: "邮箱授权码(注意是授权码不是密码)"
    default-encoding: "UTF-8"

这样就配置好了!这里使用的是yaml格式的配置文件,properties格式同理。

前提是你的邮箱需要开启SMTP服务,以163邮箱为例:

image.png

开启任意一个即可,然后按照指引操作,最后会得到一个授权码,建议复制到一个文本文档记下来,这个页面也可以看到smtp地址,复制到配置里面即可:

image.png

2,发送简单文字邮件

在需要调用邮件发送的类中使用@Autowired自动注入JavaMailSender对象,然后创建SimpleMailMessage实例,进行发送即可,下面给出实例:

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

@Autowired
private JavaMailSender mailSender;

public void sendNotifyMail(String email, String title, String text) {
	SimpleMailMessage message = new SimpleMailMessage();
	message.setFrom(sender);
	message.setTo(email);
	message.setSubject(title);
	message.setText(text);
	try {
		mailSender.send(message);
	} catch (Exception e) {
		e.printStackTrace();
	}
}

上面有一个sender变量使用@Value注解注入了我们配置的邮箱值,因为发件人邮箱也需要在Java程序中发送邮件时写,方便起见注入配置文件的值即可而不是再写一遍邮箱地址。

以及上面写了个发邮件的方法sendNotifyMail,这里就是发邮件的方法。可见发邮件只需要先自动注入JavaMailSender对象,然后创建SimpleMailMessage实例,并设定SimpleMailMessage实例的发件人、收件人、邮件标题、邮件内容,最后调用JavaMailSender实例的send方法发送SimpleMailMessage实例即可。

3,发送富文本(HTML)邮件

我们现在见到的很多网站的邮件验证码,都是有一个网页样式的。事实上,我们可以借助JavaMailSenderThymeleaf模板引擎实现富文本邮件发送。

首先记得添加Thymeleaf依赖:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

Thymeleaf模板文件默认位于项目文件夹/src/main/resources/templates目录下,我们在这个目录下创建html的网页模板文件作为邮件模板。Thymeleaf路径是可以修改的,具体修改方法可以在我的其它一篇博客里面找到。

我这里在默认模板目录下创建一个网页模板miyakomailtemplate.html如下:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
	<title th:text="${title}"></title>
	<style>
		* {
			margin: 0;
			padding: 0;
		}

		body {
			background-color: rgb(224, 224, 224);
		}

		.background {
			position: absolute;
			width: 390px;
			height: 450px;
			background-color: white;
		}

		.background .head {
			position: relative;
			height: 10px;
			background-color: rgb(0, 153, 255);
		}

		.background .content .title,
		.text {
			position: relative;
			margin-top: 3%;
			margin-left: 5%;
			width: 90%;
		}

		.background .content .title {
			color: rgb(0, 153, 255);
			font-weight: 700;
			font-size: 30px;
		}

		.background .content .text {
			position: relative;
			padding: 8px;
			box-sizing: border-box;
			margin-top: 3%;
			margin-left: 5%;
			height: 275px;
			border: 1.5px blue solid;
			overflow: auto;
		}

		.background .content .text p {
			display: inline;
			border-bottom: 1px green dashed;
		}

		.background .miyako {
			position: absolute;
			bottom: 14px;
			right: 5%;
			display: flex;
			justify-content: flex-end;
			align-items: center;
			width: 300px;
		}

		.background .miyako .from {
			position: relative;
			margin-right: 16px;
			font-size: 20px;
			font-weight: 600;
			color: rgb(0, 110, 255);
		}

		.background .miyako img {
			position: relative;
			width: 58px;
			height: 58px;
			border: 2px solid blueviolet;
			border-radius: 50%;
		}

		@media (max-width: 768px) {
			.background {
				width: 100%;
			}
		}
	</style>
</head>

<body>
	<div class="background">
		<div class="head"></div>
		<div class="content">
			<div class="title" th:text="${title}">标题</div>
			<div class="text">
				<p th:text="${content}">内容</p>
			</div>
		</div>
		<div class="miyako">
			<div class="from">From 出云宫子</div>
			<img src="https://s6.jpg.cm/2021/10/27/I07fQS.png" />
		</div>
	</div>
</body>

</html>

这个就是我们的网页邮件模板,可以看到,最上面html标签加上了xmlns:th="http://www.thymeleaf.org"表示这是一个Thymeleaf模板文件,然后在模板中,我们可以设定一些变量,给标签加上th:text=${变量名}属性,那么在模板引擎读取时就会把该标签内容渲染成相应的值。当然这些变量需要我们后端发送邮件时先指定变量名和值,最后网页就会渲染成相应的样子。

对于富文本邮件网页,我们编写时需要注意:存放我们主体内容的元素(例如我上述中类名为backgrounddiv元素)不要去设置它的位置(lefttop)!就保持它在默认位置(一般是在body中的lefttop都为0的地方)即可,否则收到的邮件显示会异常。如果不写响应式布局,那么存放我们内容的容器也需要用具体数值来规定其宽高。

当然,我建议还是做一下移动端适配,在网页head中加上:

<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">

然后使用媒体查询,适配移动端,这样效果会比较好。

媒体查询中存放主体内容的标签就建议把宽度设置为100%

变量部分其实就是Thymeleaf的基本语法,这里不再赘述。

现在,我们来编写后端,封装一个方法发送富文本邮件:

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

@Autowired
private JavaMailSender mailSender;

@Autowired
private TemplateEngine templateEngine; // 注入模板引擎读取模板文件

@Override
public void sendHtmlNotifyMail(String email, String title, String content) throws MessagingException {
	// 通过Context对象构建模板中变量需要的值
	Context context = new Context();
	context.setVariable("title", title);
	context.setVariable("content", content);
	// 传入变量,并渲染模板
	String mimeString = templateEngine.process("miyakomailtemplate.html", context);
	// 创建富文本信息对象
	MimeMessage message = mailSender.createMimeMessage();
	MimeMessageHelper helper = new MimeMessageHelper(message, true);
	helper.setFrom(sender);
	helper.setTo(email);
	helper.setSubject(title);
	// 给helper设置内容为我们渲染的模板内容,第二个参数为true表示内容是html格式
	helper.setText(mimeString, true);
	// 发送邮件
	try {
		mailSender.send(message);
	} catch (Exception e) {
		e.printStackTrace();
	}
}

其实大体思路和上面发送简单文本是很相似的,只不过先创建了个Context对象,在这个对象里面储存网页模板中的变量名和对应的变量值(setVariable("变量名", "变量值"),我们上面网页模板中有titlecontent这两个变量,也可见在Java代码中我们在context这个对象中设定了这两个变量的值),然后使用templateEngine将模板渲染,传入网页模板位置(相对于Thymeleaf目录的位置,这里文件直接放在该目录下,因此传入文件名即可)和Context对象,即可渲染出实际的值。得到网页源代码字符串,发送邮件时将其作为内容发送即可。

我们调用该方法测试一下:

@PostConstruct
public void test() {
	try {
		sendHtmlNotifyMail("我的邮箱@163.com", "宫子恰布丁-密码重置", "您的密码重置邮箱验证码为:" + (int) ((Math.random() * 9 + 1) * 100000));
	} catch (MessagingException e) {
		e.printStackTrace();
	}
}

效果:

image.png

4,将Spring Boot配置到阿里云后无法发送邮件的问题解决

我在本地开发时测试发送邮件正常,但是放到阿里云上面就发不出去了。查资料得知因为邮件默认通过25端口发送,而出于安全考虑阿里云默认禁用25端口,因此需要配置加密的465端口才行。

我们只需要基于上述配置文件内容继续加入下列配置即可:

# 发件邮件配置
spring:
  mail:
    # 省略其它配置...
    # 配置开启TLS加密
    properties:
      "[mail.smtp.ssl.enable]": true
      "[mail.smtp.starttls.enable]": true

开启SSL加密连接以及STARTTLS机制即可。