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

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

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

1,配置

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

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-mail</artifactId>
</dependency>
复制代码

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

spring.mail.host=邮件的smtp服务器
spring.mail.username=你的邮箱账户
spring.mail.password=邮箱授权码(注意是授权码不是密码)
spring.mail.default-encoding=UTF-8
复制代码

这样就配置好了!

前提是你的邮箱需要开启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.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
spring.mail.properties.mail.smtp.socketFactory.port=465
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
复制代码
分类:
后端
标签:
分类:
后端
标签: