springboot系列(十六):如何实现发送邮件提醒,附完整源码(完结篇)

Posted bug菌¹

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springboot系列(十六):如何实现发送邮件提醒,附完整源码(完结篇)相关的知识,希望对你有一定的参考价值。

👨‍🎓作者:bug菌

🚫特别声明:原创不易,转载请附上原文出处链接和本文声明,谢谢配合。

🙏版权声明:文章里可能部分文字或者图片来源于互联网或者百度百科,如有侵权请联系bug菌处理。

【开发云】年年都是折扣价,不用四处薅羊毛

         嗨,家人们,我是bug菌呀,我又来啦。今天我们来聊点什么咧,OK,接着为大家更《springboot零基础入门教学》系列文章吧。希望能帮助更多的初学者们快速入门!

       小伙伴们在批阅文章的过程中如果觉得文章对您有一丝丝帮助,还请别吝啬您手里的赞呀,大胆的把文章 点亮👍吧,您的点赞三连( 收藏⭐️+关注👨‍🎓+留言📃)就是对bug菌我创作道路上最好的鼓励与支持😘。时光不弃🏃🏻‍♀️,创作不停💕,加油☘️

一、前言🔥

       先不开始这期的内容,我们先来回顾一下吧,考考大家, 上几篇都讲了些什么知识点呀,不知道大家都还有印象没?如果实在回忆不起,那也没关系,bug菌再集中给大家复盘下,让大家都能系统性的掌握这整块知识点,好吧。

       springboot如何整合邮件发送提醒功能?这个业务场景虽然平时开发比较少接触,毕竟一般邮件开发基本都是一些用于什么人员oa、pm、财务等管理系统,但这些早就已经被系统集成过了,一般情况下也不会说拿出来二次开发或者迭代,但是身为开发,多了解一些总归没有坏处,万一那天就排上用场了,说不定你还得回来感谢bug菌我哦。

        再者,此次带大家了解加实践,也算是有过开发邮件业务的经验咯,你们说是不是。

如下呢,是上几期的教学大纲,大家可以看一下:

       然而,今天是最后一期啦,啊呸呸,不是我要最后一期,而是这块知识点啦,要与大家说再见啦。如果有小伙伴直接中途插入,还请麻烦先去看上几期的内容,要不然贸然跟着学,肯定要吃大亏,去我的专栏《SpringBoot零基础入门》从头开始跟进。

       首先,我先给大家整理下上几期所开发实现的代码吧,我尽量把完整代码都粘贴出来,一来方便大家系统性的阅读(cv大法),二来也能有个标准核对自己的代码,如果有运行不起来的,也好有个标准答案可以借鉴,哈哈哈哈哈哈。

二、方法类🔥

        如下就是上几期所实现的不同邮件发送方法类,需要的小伙伴自行存取,尽情拿去造吧~

package com.example.demo.component.mail.build;

import com.example.demo.component.mail.model.AccessoryMail;
import com.example.demo.component.mail.model.ImgResMail;
import com.example.demo.component.mail.model.Mail;
import com.example.demo.component.mail.model.ThymeleafMail;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import org.thymeleaf.context.Context;
import org.thymeleaf.spring5.SpringTemplateEngine;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;



/**
 * @author luoYong
 * @version 1.0
 * @date 2022/1/18 9:36
 */
@Component
public class SendMailBuild 
    @Autowired
    private JavaMailSender javaMailSender;
    @Autowired
    private SpringTemplateEngine templateEngine;    //创建模板引擎
    @Autowired    private UserService userService;

    /**
     * 发送简单邮件
     */
    public void sendSimpleMail(Mail model)  

        //构建邮件内容对象
        SimpleMailMessage msg = new SimpleMailMessage();        //邮件发送者
        msg.setFrom(model.getSendMailAccount());        //邮件接收者
        msg.setTo(model.getAcceptMailAccount());        //邮件主题
        msg.setSubject(model.getTheme());        //邮件正文
        msg.setText(model.getMailText());        //邮件发送时间
        msg.setSentDate(model.getSendTime());
        javaMailSender.send(msg);
     

   /**
    * 发送带附件的邮件
    */
    public void sendAccessoryMail(AccessoryMail model) throws MessagingException 

        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        MimeMessageHelper msg = new MimeMessageHelper(mimeMessage, true);        //邮件发送者
        msg.setFrom(model.getSendMailAccount());        //邮件接收者
        msg.setTo(model.getAcceptMailAccount());        //邮件主题
        msg.setSubject(model.getTheme());        //邮件正文
        msg.setText(model.getMailText());        //邮件发送时间
        msg.setSentDate(model.getSendTime());        //添加附件
        msg.addAttachment(model.getAttachmentName(), new File(model.getAttachmentPath())); 
       javaMailSender.send(mimeMessage); 
   

    /** 
     * 发送带图片资源的邮件
     * 图片资源和附件的区别就在于:图片资源是放在邮件正文中的,就是一打开邮件就能看到图片。
     */
    public void sendImgResMail(ImgResMail model) throws MessagingException 

        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        MimeMessageHelper msg = new MimeMessageHelper(mimeMessage, true);        //邮件发送者
        msg.setFrom(model.getSendMailAccount());        //邮件接收者
        msg.setTo(model.getAcceptMailAccount());        //邮件主题
        msg.setSubject(model.getTheme());        //邮件发送时间
        msg.setSentDate(model.getSendTime());        //邮件正文
        msg.setText(model.getMailText(),true);        //添加图片链接
        for (int i = 0; i < model.getContentIds().size(); i++) 
            msg.addInline(model.getContentIds().get(i), new FileSystemResource(new File(model.getPaths().get(i))));
                javaMailSender.send(mimeMessage);
    

    /**
     * 配置静态模板 这里使用了Thymeleaf 作为邮件模板
     */
    public void sendThymeleafMail(ThymeleafMail model) throws MessagingException 
        
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        MimeMessageHelper msg = new MimeMessageHelper(mimeMessage, true);        //邮件发送者
        msg.setFrom(model.getSendMailAccount());        //邮件接收者
        msg.setTo(model.getAcceptMailAccount());        //邮件主题
        msg.setSubject(model.getTheme());        //邮件发送时间
        msg.setSentDate(model.getSendTime());

        Context context = new Context();        //添加模板数据
        model.getVariables().forEach(p -> 
            context.setVariable(p.getName(), p.getValue());
        );        //指定静态页面模板
        String process = templateEngine.process(model.getTemplate(), context);
        msg.setText(process, true);
        javaMailSender.send(mimeMessage);
    

        如上是这几期发送邮件功能点的核心,大家有空一定要好好研究,虽然我也有的是参考了网上大佬的教学才自己去进行了尝试,我希望你们也能跟我一样,能把这些方法分别断点研究,看看每一处代码类都是在干一件什么事!

       其实邮件发送,由于被springboot集成过后,一切使用就变得超级简单了,你只需要学习SimpleMailMessage 与  MimeMessage 这两邮件创建类是如何工作的,基本就了解到这儿就可以了,毕竟一般业务中也不怎么会接触到这个,了解使用为主,不必深入研究,好吧。

三、vo类🔥

Mail.java

package com.example.demo.component.mail.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.Date;

/**
 * 基本邮件参数
 *
 * @author luoYong
 * @version 1.0
 * @date 2022/1/18 9:37
 */
@ApiModel(value = "基本邮件参数",description = "基本邮件参数")
public class Mail 

    @ApiModelProperty("发件人邮箱账号")
    private String sendMailAccount;

    @ApiModelProperty("收件人邮箱账号")
    private String acceptMailAccount;

    @ApiModelProperty("邮件主题")
    private String theme;

    @ApiModelProperty("邮件内容")
    private String mailText;

    @ApiModelProperty("发送时间")
    private Date sendTime = new Date();

    public String getTheme() 
        return theme;
    
    public void setTheme(String theme) 
        this.theme = theme;
    
    public String getSendMailAccount() 
        return sendMailAccount;
    
    public void setSendMailAccount(String sendMailAccount) 
        this.sendMailAccount = sendMailAccount;
    
    public String getAcceptMailAccount() 
        return acceptMailAccount;
    
    public void setAcceptMailAccount(String acceptMailAccount) 
        this.acceptMailAccount = acceptMailAccount;
    
    public Date getSendTime() 
        return sendTime;
     
    public void setSendTime(Date sendTime) 
        this.sendTime = sendTime;
     
    public String getMailText() 
        return mailText;
    
    public void setMailText(String mailText) 
        this.mailText = mailText;
    

ImgResMail.java

package com.example.demo.component.mail.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;

/**
 * 发送带图片资源邮件参数
 *
 * @author luoYong
 * @version 1.0
 * @date 2022/1/18 10:54
 */
@ApiModel(value = "发送带图片资源邮件参数",description = "发送带图片资源邮件参数")
public class ImgResMail extends Mail 

    @ApiModelProperty("对于的图片标记id")
    private List<String> contentIds;

    @ApiModelProperty("图片地址")
    private List<String> paths;

    public List<String> getContentIds() 
        return contentIds;
    
    public void setContentIds(List<String> contentIds) 
        this.contentIds = contentIds;
    
    public List<String> getPaths() 
        return paths;
    
    public void setPaths(List<String> paths) 
        this.paths = paths;
    

AccessoryMail.java

package com.example.demo.component.mail.model;
import io.swagger.annotations.ApiModelProperty;

/**
 * 发送带附件的邮件参数
 *
 * @author luoYong
 * @version 1.0
 * @date 2022/1/18 10:57
 */
public class AccessoryMail extends Mail 

    @ApiModelProperty("附件地址")
    private String attachmentPath;

    @ApiModelProperty("附件名")
    private String attachmentName;

    public String getAttachmentPath() 
        return attachmentPath;
    
    public void setAttachmentPath(String attachmentPath) 
        this.attachmentPath = attachmentPath;
    
    public String getAttachmentName() 
       return attachmentName;
    
    public void setAttachmentName(String attachmentName) 
        this.attachmentName = attachmentName;
    

Variable.java

package com.example.demo.component.mail.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

/**
 * 静态文件对应的key-value
 *
 * @author luoYong
 * @version 1.0
 * @date 2022/1/18 11:25
 */
@ApiModel(value = "静态文件对应的key-value",description = "静态文件对应的key-value")
public class Variable 

    @ApiModelProperty("参数名")
    private String name;

    @ApiModelProperty("值")
    private String value;

    public String getName() 
        return name;
    
    public void setName(String name) 
        this.name = name;
    
    public String getValue()  
       return value;
    
    public void setValue(String value) 
        this.value = value;
    

ThymeleafMail.java

package com.example.demo.component.mail.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

/**
 * 静态文件对应的key-value
 *
 * @author luoYong
 * @version 1.0
 * @date 2022/1/18 11:25
 */
@ApiModel(value = "静态文件对应的key-value",description = "静态文件对应的key-value")
public class Variable 

    @ApiModelProperty("参数名")
    private String name;

    @ApiModelProperty("值")
    private String value;

    public String getName()  
       return name; 
   
    public void setName(String name) 
        this.name = name;
    
    public String getValue() 
        return value;
    
    public void setValue(String value) 
        this.value = value;
    

四、test-case类🔥

       至于test-case,可能每个人书写习惯不一样,大家都有自己独特的代码习惯,你们也可以按照自己的风格来写,毕竟主要是为了测试邮件方法,别的倒没啥,测试方法功能点是否正常即可。如下是我的:仅供参考:

package com.example.demo.component.build;

import com.example.demo.component.mail.build.SendMailBuild;
import com.example.demo.component.mail.model.*;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.mail.MessagingException;import java.util.ArrayList;
import java.util.Date;import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class MailTest 

    @Autowired
    private SendMailBuild sendMailBuild;

    /**
     * 发送简单邮件
     */
    @Test
     void sendSimpleMail() 

        Mail mailModel = new Mail();
        mailModel.setTheme("title:这是一封测试邮件哈!"); // 设置邮件主题
        mailModel.setSendMailAccount("luoyong0603@foxmail.com"); // 设置邮箱发送者
        mailModel.setAcceptMailAccount("luoyong0603@foxmail.com"); // 设置邮件接收者,可以有多个接收者
        mailModel.setSendTime(new Date());    // 设置邮件发送日期
        mailModel.setMailText("text:这是测试邮件的正文内容:我是testMail");   // 设置邮件的正文
        sendMailBuild.sendSimpleMail(mailModel);
    
   /**
     * 发送带附件的邮件
     */
    @Test
    void sendSimpleMailForDoc() throws MessagingException 

        AccessoryMail mailModel = new AccessoryMail();
        mailModel.setTheme("这是一封测试邮件"); // 设置邮件主题
        mailModel.setSendMailAccount("luoyong0603@foxmail.com"); // 设置邮箱发送者
        mailModel.setAcceptMailAccount("luoyong0603@foxmail.com"); // 设置邮件接收者,可以有多个接收者
        mailModel.setSendTime(new Date());    // 设置邮件发送日期
        mailModel.setMailText("这是测试邮件的正文");   // 设置邮件的正文
        mailModel.setAttachmentName("2022.png");//附件名
        mailModel.setAttachmentPath("C:\\\\Users\\\\Administrator\\\\Desktop\\\\2022.png");//附件地址
        sendMailBuild.sendAccessoryMail(mailModel);
        
    /**
     * 发送带图片资源的邮件
     * 图片资源和附件的区别就在于 图片资源是放在邮件正文中的,就是一打开邮件就能看到图片
     */
    @Test
    public void sendImgResMail() throws MessagingException 

        ImgResMail mailModel = new ImgResMail();
        mailModel.setTheme("这是一封测试邮件"); // 设置邮件主题
        mailModel.setSendMailAccount("luoyong0603@foxmail.com"); // 设置邮箱发送者
        mailModel.setAcceptMailAccount("luoyong0603@foxmail.com"); // 设置邮件接收者,可以有多个接收者
        mailModel.setSendTime(new Date());    // 设置邮件发送日期
        mailModel.setMailText("<p>hello 大家好,我是一封测试邮件,我包含了两张图片,分别如下</p><p>第一张图片:</p><img src='cid:img1'/><p>第二张图片:</p><img src='cid:img2'/>");
        
        List<String> paths = new ArrayList<>();
        paths.add("C:\\\\Users\\\\Administrator\\\\Desktop\\\\2022.png");
        paths.add("C:\\\\Users\\\\Administrator\\\\Desktop\\\\test.png");
        mailModel.setPaths(paths);
        
        List<String> contentIds = new ArrayList<>();
        contentIds.add("img1");
        contentIds.add("img2");
        mailModel.setContentIds(contentIds);
        sendMailBuild.sendImgResMail(mailModel);
    
    /**
     * 配置静态模板 这里使用了Thymeleaf 邮件模板
     */
    @Test
    public void testSendThymeleafMail() throws MessagingException 

        ThymeleafMail mailModel = new ThymeleafMail();
        mailModel.setTheme("这是一封测试邮件"); // 设置邮件主题
        mailModel.setSendMailAccount("luoyong0603@foxmail.com"); // 设置邮箱发送者
        mailModel.setAcceptMailAccount("luoyong0603@foxmail.com"); // 设置邮件接收者,可以有多个接收者
        mailModel.setSendTime(new Date());    // 设置邮件发送日期

        List<Variable> variables = new ArrayList<>();
        Variable variable1 = new Variable();
        variable1.setName("school");
        variable1.setValue("清华附属小学");
        Variable variable2 = new Variable();
        variable2.setName("className");
        variable2.setValue("六(1)班");
        Variable variable3 = new Variable();
        variable3.setName("name");
        variable3.setValue("小罗");
        variables.add(variable1);
        variables.add(variable2);
        variables.add(variable3);

        mailModel.setVariables(variables);
        mailModel.setTemplate("mail.html");
        sendMailBuild.sendThymeleafMail(mailModel);
    

如下是我实现这个功能块的项目结构。 

        大家也可以像我一样,一个组件就是一个功能点,然后所涉及的model类,单独封装方法一个component中,日后,项目进行维护,后人一看也就明白了,原来这一组件就是干了一件邮件发送等功能点,自己用起来或他人进行调用,一看文件目录便知。

五、静态模板文件🔥

1、mail.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Thymeleaf邮件模板</title>
</head>
<body>
<p>这是一份学生名单:请查收</p>
<table border="1">
    <tr>
        <td>学校</td>
        <td th:text="$school"></td>
    </tr>
    <tr>
        <td>班级</td>
        <td th:text="$className"></td>
    </tr>
    <tr>
        <td>姓名</td>
        <td th:text="$name"></td>
    </tr>
</table>
<div style="color: red;">以上是学生名单!</div>
</body>
</html>

2、user.html

这套模板暂时没用上,这主要是一个循环遍历集合的模板。也供大家参考:

<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta content="text/html;charset=UTF-8"/>
</head>
<body>
<h6>Thymeleaf 模板引擎</h6>
<table border="1" bgcolor="#f0ffff">
    <thead>
    <tr>
        <th>姓名</th>
        <th>年龄</th>
        <th>性别</th>
        <th>地址</th>
    </tr>
    </thead>
    <!--th:each表示循环遍历,和Vue一样-->
    <tbody th:each="user : $users">
    <tr>
        <td th:text="$user.name"></td>
        <td th:text="$user.age"></td>
        <td th:text="$user.sex"></td>
        <td th:text="$user.address"></td>
    </tr>
    </tbody>
</table>
</body>
</html>

        这里我就有必要向大家介绍一下:html的xmlns属性。

问:为什么返回的是集合 数组结构的,xmlns属性配了两个链接指向?

        答:xmlns 属性 是可以配置多个命名空间的,就比如上方,我就配置了两个命名空间。该属性可以放在文档内任何元素的开始标签中,比如:<div xmlns="http://www.w3.org/1999/Math/MathMl">这是一个div</div>。然后该属性的值类似于url,定义了一个命名空间,在进行浏览器访问的时候,就会将此命名空间用于该属性所在元素内的所有内容。

       例如,如果需要使用符合 XML 规范的 XHTML 文档,则应该在文档中的<html> 标签中至少使用一个 xmlns 属性,以指定整个文档所使用的主要命名空间:

<html xmlns="http://www.w3.org/1999/xhtml">

一个简单的 XHTML 文档,带有最少的必需标签应该如此,大家请看:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta charset="utf-8"> 
  <title>文档标题</title>
</head>
<body>
  文档内容......
</body>

</html>

       以上是对html 的xmlns属性拓展。供大家参考。

接着,如下是我的静态模板目录结构:

        如果是要指定返回静态模板类,那你就要配置环境了,比如spring.thymeleaf.xxx 相关属性值了,其中就有一个属性是配置这个templeates文件夹的,这个在我以前的教程中,也专门出了一期,大家想看的也可以去看看,至于为啥我本文没有配置静态路径,却邮件模板能正确找到呢?这个大家可以思考一下,为何能正确找到mail.html.

        说到这儿,就要跟大家说拜拜了,以上就是针对如何代码实现邮件提醒功能的全部内容啦,如果你还卡在途中某个点,但说无妨,bug菌是不会嘲笑你的,只会耐心的对你的疑惑进行全面解答,我为人人,人人才会为我!对吧,没有付出,哪有回报,所以尽情的把问题抛出来把,下下方留言或者加我的交流群,都可。可能就会有小伙伴问了,bug菌你这么倾囊相授,到底图啥呀?图我们回报你啥呀?

        如果非要论回报,那就帮我把文章左上角的大拇指点亮吧。如果能一键三连,那bug菌更是喜笑颜开啦,更加充满动力为大家奉献自己的时间,要知道上班时间拿来写文章,是一件多么危险的事。

 ... ...

       ok,以上就是我这期的全部内容啦,如果还想学习更多,你可以看看我的往期热文推荐哦,每天积累一个奇淫小知识,日积月累下去,你一定能成为令人敬仰的大佬的。好啦,咱们下期见~

六、往期推荐🔥

七、文末🔥

       如果还想要学习更多,小伙伴们可关注bug菌专门为大家创建的专栏《springboot零基础入门教学》,从无到有,从零到一!希望能帮助到更多小伙伴们。

【开发云】年年都是折扣价,不用四处薅羊毛

       我是bug菌,一名想走👣出大山改变命运的程序猿。接下来的路还很长,都等待着我们去突破、去挑战。来吧,小伙伴们,我们一起加油!未来皆可期,fighting!

        最后送大家两句我很喜欢的话,与诸君共勉!


☘️做你想做的人,没有时间限制,只要愿意,什么时候都可以start。

🍀你能从现在开始改变,也可以一成不变,这件事,没有规矩可言,你可以活出最精彩的自己。


​​​

💌如果文章对您有所帮助,就请留下您的吧!(#^.^#);

💝如果喜欢bug菌分享的文章,就请给bug菌点个关注吧!(๑′ᴗ‵๑)づ╭❤~;

💗如果对文章有任何疑问,还请文末留言或者加群吧;

💞鉴于个人经验有限,所有观点及技术研点,如有异议,请直接回复参与讨论(请勿发表攻击言论,谢谢);

💕版权声明:原创不易,转载请附上原文出处链接和本文声明,版权所有,盗版必究!!!谢谢。

以上是关于springboot系列(十六):如何实现发送邮件提醒,附完整源码(完结篇)的主要内容,如果未能解决你的问题,请参考以下文章

springboot系列(十六):如何实现发送邮件提醒,附完整源码(完结篇)

SpringBoot | 第二十六章:邮件发送

springboot系列:如何实现邮件发送提醒,你一定得会(准备篇)

springboot系列:如何实现邮件发送提醒,你一定得会(准备篇)

springboot系列(十三):如何实现发送普通邮件?你一定得会|超级详细,建议收藏

springboot系列(十三):如何实现发送普通邮件?你一定得会|超级详细,建议收藏