邮件发送其实是一个非常常见的需求,用户注册,找回密码等地方,都会用到,使用 JavaSE 代码发送邮件,步骤还是挺繁琐的,Spring Boot 中对于邮件发送,提供了相关的自动化配置类,使得邮件发送变得非常容易,本文我们就来一探究竟!看看使用 Spring Boot 发送邮件的 5 中姿势
邮件基础 我们经常会听到各种各样的邮件协议,比如 SMTP、POP3、IMAP ,那么这些协议有什么作用,有什么区别?我们先来讨论一下这个问题。
SMTP 是一个基于 TCP/IP 的应用层协议,江湖地位有点类似于 HTTP,SMTP 服务器默认监听的端口号为 25 。看到这里,小伙伴们可能会想到既然 SMTP 协议是基于 TCP/IP 的应用层协议,那么我是不是也可以通过 Socket 发送一封邮件呢?回答是肯定的。
这三个步骤可以分别对应我们的邮件发送过程,假设从 aaa@qq.com 发送邮件到 111@163.com :
aaa@qq.com 先将邮件投递到腾讯的邮件服务器 腾讯的邮件服务器将我们的邮件投递到网易的邮件服务器 111@163.com 登录网易的邮件服务器查看邮件
SMTP 协议全称为 Simple Mail Transfer Protocol,译作简单邮件传输协议,它定义了邮件客户端软件与 SMTP 服务器之间,以及 SMTP 服务器与 SMTP 服务器之间的通信规则。
也就是说 aaa@qq.com 用户先将邮件投递到腾讯的 SMTP 服务器这个过程就使用了 SMTP 协议,然后腾讯的 SMTP 服务器将邮件投递到网易的 SMTP 服务器这个过程也依然使用了 SMTP 协议,SMTP 服务器就是用来收邮件。
而 POP3 协议全称为 Post Office Protocol ,译作邮局协议,它定义了邮件客户端与 POP3 服务器之间的通信规则,那么该协议在什么场景下会用到呢?当邮件到达网易的 SMTP 服务器之后, 111@163.com 用户需要登录服务器查看邮件,这个时候就该协议就用上了:邮件服务商都会为每一个用户提供专门的邮件存储空间,SMTP 服务器收到邮件之后,就将邮件保存到相应用户的邮件存储空间中,如果用户要读取邮件,就需要通过邮件服务商的 POP3 邮件服务器来完成。
开启 SMTP、POP3 点进QQ邮箱,点击设置点击账户,往下面拉,开启SMTP服务
Idea创建一个Java项目 加入web依赖,和发送邮件的依赖 依赖如下所示:
< dependency> < groupId> org. springframework. boot< / groupId> < artifactId> spring- boot- starter- mail< / artifactId> < / dependency> < dependency> < groupId> org. springframework. boot< / groupId> < artifactId> spring- boot- starter- web< / artifactId> < / dependency>
配置application.yml 每个配置项,我都添加了注释的
#配置 SMTP 服务器地址 spring. mail. host= smtp. qq. com#SMTP 服务器的端口 spring. mail. port= 465 #配置邮箱用户名 spring. mail. username= 857903497 @qq. com #配置密码,注意,不是真正的密码,而是刚刚申请到的授权码 spring. mail. password= * * * * * * * * * * * * * #默认的邮件编码 spring. mail. default - encoding= UTF- 8 #配饰 SSL 加密工厂 spring. mail. properties. mail. smtp. socketFactoryClass= javax. net. ssl. SSLSocketFactory #表示开启 DEBUG 模式,这样,邮件发送过程的日志会在控制台打印出来,方便排查错误 spring. mail. properties. mail. debug= true#官方建议使用 465 端口,而 465 端口是 SSL 协议的,所以不仅要换端口, #还需要进行 SSL 协议替换。下面是在 application. properties 进行的邮件发送相关配置, spring. mail. protocol= smtp spring. mail. properties. mail. smtp. ssl. enable= true spring. mail. properties. mail. smtp. socketFactory. port= 465
下面开始发送邮件
第一种、发送简单邮件 建立测试类,idea在创建项目的时候在test文件夹下面创建了一个,我用的就是这个
@AutowiredJavaMailSender javaMailSender; @Testpublic void sendSimpleMail ( ) { SimpleMailMessage message = new SimpleMailMessage ( ) ; message. setSubject ( "这是一封测试邮件" ) ; message. setFrom ( "857903497@qq.com" ) ; message. setTo ( "1559***2@qq.com" ) ; message. setSentDate ( new Date ( ) ) ; message. setText ( "这是测试邮件的正文" ) ; javaMailSender. send ( message) ; }
效果如下
第二种、发送带附件的邮件 @Testpublic void sendAttachFileMail ( ) throws MessagingException { MimeMessage mimeMessage = javaMailSender. createMimeMessage ( ) ; MimeMessageHelper helper = new MimeMessageHelper ( mimeMessage, true) ; helper. setSubject ( "这是一封测试邮件" ) ; helper. setFrom ( "857903497@qq.com" ) ; helper. setTo ( "1559***26@qq.com" ) ; helper. setSentDate ( new Date ( ) ) ; helper. setText ( "这是测试邮件的正文" ) ; helper. addAttachment ( "测试图片.jpg" , new File ( "C:\\Users\\Administrator\\Desktop\\11.jpg" ) ) ; javaMailSender. send ( mimeMessage) ; }
第三种、带图片资源的邮件 @Testpublic void sendImgResMail ( ) throws MessagingException { MimeMessage mimeMessage = javaMailSender. createMimeMessage ( ) ; MimeMessageHelper helper = new MimeMessageHelper ( mimeMessage, true) ; helper. setSubject ( "这是一封测试邮件" ) ; helper. setFrom ( "857903497@qq.com" ) ; helper. setTo ( "1559908926@qq.com" ) ; helper. setSentDate ( new Date ( ) ) ; helper. setText ( "hello 大家好,这是一封测试邮件,这封邮件包含两种图片,分别如下
第一张图片:
第二张图片:
" , true) ; helper. addInline ( "p01" , new FileSystemResource ( new File ( "C:\\Users\\Administrator\\Desktop\\11.jpg" ) ) ) ; helper. addInline ( "p02" , new FileSystemResource ( new File ( "C:\\Users\\Administrator\\Desktop\\11.jpg" ) ) ) ; javaMailSender. send ( mimeMessage) ; }
这里的邮件 text 是一个 HTML 文本,里边涉及到的图片资源先用一个占位符占着,setText 方法的第二个参数 true 表示第一个参数是一个 HTML 文本。
setText 之后,再通过 addInline 方法来添加图片资源。
最后执行该方法,发送邮件,效果如下: 在公司实际开发中,第一种和第三种都不是使用最多的邮件发送方案。因为正常来说,邮件的内容都是比较的丰富的,所以大部分邮件都是通过 HTML 来呈现的,如果直接拼接 HTML 字符串,这样以后不好维护,为了解决这个问题,一般邮件发送,都会有相应的邮件模板。最具代表性的两个模板就是 Freemarker 模板和 Thyemeleaf 模板了
第四种 Freemarker 邮件模板 引入Freemarker依赖
< dependency> < groupId> org. springframework. boot< / groupId> < artifactId> spring- boot- starter- freemarker< / artifactId> < / dependency>
在templatest文件夹下面创建mail.ftl文件,模板如下所示
< ! DOCTYPE html> < html lang= "en" > < head> < meta charset= "UTF-8" > < title> Title< / title> < / head> < body> < #-- Freemarker 作邮件模板-- > < p> hello 欢迎加入 xxx 大家庭,您的入职信息如下:< / p> < table border= "1" > < tr> < td> 姓名< / td> < td> ${ username} < / td> < / tr> < tr> < td> 工号< / td> < td> ${ num} < / td> < / tr> < tr> < td> 薪水< / td> < td> ${ salary} < / td> < / tr> < / table> < div style= "color: #ff1a0e" > 一起努力创造辉煌< / div> < / body> < / html>
接下来,将邮件模板渲染成 HTML ,然后发送即可。发送模板代码如下,
@Testpublic void sendFreemarkerMail ( ) throws MessagingException, IOException, TemplateException { MimeMessage mimeMessage = javaMailSender. createMimeMessage ( ) ; MimeMessageHelper helper = new MimeMessageHelper ( mimeMessage, true) ; helper. setSubject ( "这是一封测试邮件" ) ; helper. setFrom ( "857903497@qq.com" ) ; helper. setTo ( "1559908926@qq.com" ) ; helper. setSentDate ( new Date ( ) ) ; Configuration configuration = new Configuration ( Configuration. VERSION_2_3_0) ; ClassLoader loader = JhjmailApplication. class. getClassLoader ( ) ; configuration. setClassLoaderForTemplateLoading ( loader, "templates" ) ; Template template = configuration. getTemplate ( "mail.ftl" ) ; User user = new User ( ) ; user. setUsername ( "蒋皓洁" ) ; user. setNum ( 1 ) ; user. setSalary ( 99999 ) ; StringWriter out = new StringWriter ( ) ; template. process ( user, out) ; helper. setText ( out. toString ( ) , true) ; javaMailSender. send ( mimeMessage) ; }
需要注意的是,虽然引入了 Freemarker 的自动化配置,但是我们在这里是直接 new Configuration 来重新配置 Freemarker 的,所以 Freemarker 默认的配置这里不生效,因此,在填写模板位置时,值为 templates 。
当然里面涉及到一个new一个User对象,则要新建一个User类
public class User { private String username; private int num; private int Salary; public String getUsername ( ) { return username; } public void setUsername ( String username) { this. username = username; } public int getNum ( ) { return num; } public void setNum ( int num) { this. num = num; } public int getSalary ( ) { return Salary; } public void setSalary ( int salary) { Salary = salary; } }
调用sendFreemarkerMail发送email如下所示
第五种、使用 Thymeleaf 作邮件模板 推荐在 Spring Boot 中使用 Thymeleaf 来构建邮件模板。因为 Thymeleaf 的自动化配置提供了一个 TemplateEngine,通过 TemplateEngine 可以方便的将 Thymeleaf 模板渲染为 HTML ,同时,Thymeleaf 的自动化配置在这里是继续有效的 。
首先,引入 Thymeleaf 依赖:
< dependency> < groupId> org. springframework. boot< / groupId> < artifactId> spring- boot- starter- thymeleaf< / artifactId> < / dependency>
Thymeleaf 模板如下
< ! DOCTYPE html> < html lang= "en" xmlns: th= "http://www.thymeleaf.org" > < head> < meta charset= "UTF-8" > < title> Title< / title> < / head> < body> < p> hello 欢迎加入 xxx 大家庭,您的入职信息如下:< / p> < table border= "1" > < tr> < td> 姓名< / td> < td th: text= "${username}" > < / td> < / tr> < tr> < td> 工号< / td> < td th: text= "${num}" > < / td> < / tr> < tr> < td> 薪水< / td> < td th: text= "${salary}" > < / td> < / tr> < / table> < div style= "color: #ff1a0e" > 一起努力创造辉煌< / div> < / body> < / html>
发送邮件如下
@AutowiredTemplateEngine templateEngine; @Testpublic void sendThymeleafMail ( ) throws MessagingException { MimeMessage mimeMessage = javaMailSender. createMimeMessage ( ) ; MimeMessageHelper helper = new MimeMessageHelper ( mimeMessage, true) ; helper. setSubject ( "这是一封测试邮件" ) ; helper. setFrom ( "857903497@qq.com" ) ; helper. setTo ( "1559908926@qq.com" ) ; helper. setSentDate ( new Date ( ) ) ; Context context = new Context ( ) ; context. setVariable ( "username" , "javaboy" ) ; context. setVariable ( "num" , "000001" ) ; context. setVariable ( "salary" , "99999" ) ; String process = templateEngine. process ( "mail.html" , context) ; helper. setText ( process, true) ; javaMailSender. send ( mimeMessage) ; }
注意一点,下面这个Context类不是自定义的,是thymeleaf.context.Context中的
Context context = new Context ( ) ;
所有要引入下面这个
import org. thymeleaf. context. Context;
结果如下所示 下午没什么事情刚好看到一篇发邮件的博客,自己就倒腾起来,学习了一些东西,博客来自
https: / / mp. weixin. qq. com/ s? __biz= MzI1NDY0MTkzNQ== & mid= 2247487459 & idx= 2 & sn= 6 d1405b414e1787d3fa08806ae096fd2& scene= 21 #wechat_redirect
共同学习,共同进步