明月当天,不知道你有没有思念的人

前言

之前其实已经写过SpringBoot异步发送邮件,但是今天在一个小项目中要用到发送邮件时,我突然觉得邮件发送人只有一个,并且固定写在yml文件中,就是非常的不妥当,就想着怎么整成一个动态的。

在写之前已经翻过很多博客了,该踩的坑都踩的差不多了,我是实现之后写的文章,有问题大家可以一起交流。

小声bb(对于CSDN我真的逐渐变得麻木了,简称CV大法现场,虽然我本人也是CSDN的一名小小博主,也是资深用户,对于文章的这块很多时候真的没法说,除了能说加油也没有了吧)。

于是就有了下面这篇文章啦....


一、需求分析

默认大家都已经会 SpringBoot 集成 邮件发送啦哈,不行的,点一下上文的链接啦。

我先说说我想要达到什么样的效果:

  1. 邮件发送人可以是多个,yml文件中是兜底配置(即数据库中没有一个可用时,使用yml文件中配置的邮件发送人)
  2. 项目启动后,我也可以临时增加邮件发送人,或者禁用掉某个邮件发送人(操作完也无需重启项目即可生效)
  3. 发送邮件内容为html;另外异步发送邮件(可有可无,大家都会)

思路其实蛮简单的,就只要做到每次我们新添加或者修改邮件发送人配置的时候,对JavaSendMailImpl这个类重新初始化即可。这个地方没啥可讲的,就是不让框架给我们自动配置,我们手动来即可。


二、详细步骤

2.1、编码

1)yml配置文件

spring:  mail:host: smtp.163.comusername: nxxxxxx@163.compassword: IXXXXXXXXXN(开启允许第三方登录后的授权码)default-encoding: utf-8protocol: smtpsproperties:mail:smtp:port: 465auth: truestarttls:enable: truerequired: true

注意:关于邮件的协议protocol:smtps的配置,我最开始也是配置的smtp,我当时报的错误是一个no provider for smtp错误,我之前也写过一直用的是这个smtp协议,但是报了这个错误,我就去搜索,然后找到有篇博客说,

SMTPS协议

SMTPS (SMTP-over-SSL)是SMTP协议基于SSL安全协议之上的一种变种协议,它继承了SSL安全协议的非对称加密的高度安全可靠性,可防止邮件泄露。SMTPSSMTP协议一样,也是用来发送邮件的,只是更安全些,防止邮件被黑客截取泄密,还可实现邮件发送者抗抵赖功能。防止发送者发送之后删除已发邮件,拒不承认发送过这样一份邮件。端口465和587便是基于SMTPS协议开放的。

465端口(SMTPS)︰它是SMTPS协议服务所使用的其中一个端口,它在邮件的传输过程中是加密传输(SSL/TLS)的,相比于SMTP协议攻击者无法获得邮件内容,邮件在一开始就被保护了起来。

所以实际上我们使用的配置应该是stmps


另外建个properties资源类 与 配置文件一一对应

/*** @author crush*/
@Data
@Component
@ConfigurationProperties(prefix = "spring.mail")
public class MailProperties {/**  * 用户名 */private String username;/** * 授权码 */private String password;/** * host */private String host;/** * 端口 */private Integer port;/*** 协议 */private String protocol;/** * 默认编码*/private String defaultEncoding;
}

2.2、建表

根据yml文件,我们大致知道了要建立张什么样的数据表了哈。

这些大家都可以自定义哈,根据自己需求来建哈。

根据数据表建一个pojo类。

/*** @Author: crush* @Date: 2021-11-26 18:28* version 1.0*/
@Data
@Accessors(chain = true)
@TableName("tb_email")
public class MailPO {private String emailHost;private String emailUsername;private String emailPassword;private Integer emailPort=465;/** * 协议 */private String protocol="smtps";/** * 默认编码 */private String defaultEncoding="utf-8";/*** 使用状态,1:正在使用,2:禁用,3:停用* TODO 后期应该更改为 枚举类来进行实现*/private Integer state=1;/** * 创建时间 */@TableField(fill = FieldFill.INSERT)private LocalDateTime createTime;/*** 修改时间 */@TableField(fill = FieldFill.INSERT_UPDATE)private LocalDateTime  updateTime;
}

如果不是用mybatis-plus 可以把创建时间和修改时间去掉@TableField(fill = FieldFill.INSERT)是Mybatis-plus中的注解。另外我主键是设置了自增,所以就空了。至于返回的类我用的vo包下的。

2.3、mapper、service层

@Repository
public interface MailMapper extends BaseMapper<MailPO> {
}

service

/*** @Author: crush* @Date: 2021-11-26 15:55* version 1.0*/
public interface MailService {void send(MailDTO mailDTO);boolean addMailPerson(MailPO mailPO);
}

impl

import cn.hutool.core.util.IdUtil;
/*** @author crush* 邮箱发送实现类*/
@Service
public class MailServiceImpl implements MailService {@AutowiredMailSenderConfig senderConfig;@AutowiredMailProperties mailProperties;@AutowiredMailMapper mailMapper;// 这里之前配置了一个线程池,上文的链接中有,就不说了哈// @Async("taskExecutor")@Overridepublic void send(MailDTO mailDTO) {String context = "<!DOCTYPE html>\n" +"<html lang=\"en\">\n" +"\n" +"<head>\n" +"    <meta charset=\"UTF-8\" />\n" +"    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n" +"    <title>xxxx邮件</title>\n" +"    <style>\n" +"        body {\n" +"            margin: 0;\n" +"            padding: 0;\n" +"        }\n" +"        \n" +"        .email {\n" +"            position: relative;\n" +"            width: 100%;\n" +"            /* background-color: rgba(0, 0, 0, 1); */\n" +"        }\n" +"        \n" +"        .main {\n" +"            left: 0;\n" +"            right: 0;\n" +"            margin: auto;\n" +"            width: 80%;\n" +"            max-width: 800px;\n" +"            box-sizing: content-box;\n" +"        }\n" +"        \n" +"        .main .title {\n" +"            /* color: white; */\n" +"            display: inline-flex;\n" +"            align-items: center;\n" +"        }\n" +"        \n" +"        .main .title span {\n" +"            margin: 0 10px;\n" +"        }\n" +"        \n" +"        .main table {\n" +"            width: 100%;\n" +"        }\n" +"        \n" +"        .main table tbody td {\n" +"            /* background-color: white; */\n" +"            padding: 20px;\n" +"            text-align: left;\n" +"            border-bottom: 1px solid rgb(161, 161, 161);\n" +"        }\n" +"        \n" +"        tfoot td p {\n" +"            color: rgb(161, 161, 161);\n" +"            font-size: 13px;\n" +"        }\n" +"        \n" +"        a {\n" +"            color: rgb(161, 161, 161);\n" +"            text-decoration: none;\n" +"        }\n" +"        \n" +"        a:hover {\n" +"            border-bottom: 1px solid rgb(161, 161, 161);\n" +"        }\n" +"    </style>\n" +"</head>\n" +"\n" +"<body>\n" +"    <div class=\"email\">\n" +"        <div class=\"main\">\n" +"            <table>\n" +"                <thead>\n" +"                    <tr>\n" +"                        <td>\n" +"                            <h1 class=\"title\">\n" +"                                <img width=\"60\" src=\"xxxxx\" alt=\"\" />\n" +"                                <span>" + mailDTO.getTitle() + "</span>\n" +"                            </h1>\n" +"                        </td>\n" +"                    </tr>\n" +"                </thead>\n" +"                <tbody>\n" +"                    <tr>\n" +"                        <td>\n" +"                            " + mailDTO.getContent() + "\n" +"                        </td>\n" +"                    </tr>\n" +"                </tbody>\n" +"                <tfoot>\n" +"                    <tr>\n" +"                        <td>\n" +"                            <p>邮件由系统自动发送,请勿直接回复。</p>\n" +"                            <p>官方网站:\n" +"                                <a href=\"https://blog.csdn.net/weixin_45821811?spm=1000.2115.3001.5343\">宁在春博客</a>\n" +"                            </p>\n" +"                        </td>\n" +"                    </tr>\n" +"                </tfoot>\n" +"            </table>\n" +"        </div>\n" +"    </div>\n" +"</body>\n" +"\n" +"</html>";JavaMailSenderImpl mailSender = senderConfig.getSender();//创建一个SimpleMailMessage对象MimeMessage mimeMessage = mailSender.createMimeMessage();//需要创建一个MimeMessageHelper对象,相关参数和简单邮件类似try {MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);//发件人helper.setFrom(mailSender.getUsername());//收件人 这个收件人可以是数组的,只是我这只需要单个 就没多做了。helper.setTo(mailDTO.getMail());helper.setSubject("验证码");//将邮件内容设置为html格式// 发送helper.setText( context, true);mailSender.send(mimeMessage);} catch (MessagingException e) {e.printStackTrace();}}// 添加就清空初始化的信息,重新初始化一遍即可。@Overridepublic boolean addMailPerson(MailPO mailPO) {if(mailMapper.insert(mailPO)>0){senderConfig.clear();senderConfig.buildMailSender();return true;}return false;}
}

用到的MailDto

/*** @author crush* 邮箱发送-前端传输参数*/
@Data
public class MailDTO implements Serializable {/*** 接受邮箱账户*/private String mail;/*** 邮箱标题*/private String title;/** * 要发送的内容*/private String content;
}

2.4、MailSenderConfig 配置类

/*** @author crush*/
@Slf4j
@Component
@AllArgsConstructor
public class MailSenderConfig {private final List<JavaMailSenderImpl> senderList;private final MailProperties mailProperties;private final MailMapper mailMapper;/*** 初始化 sender* PostConstruct注解用于需要在依赖注入完成后执行任何初始化的方法。 必须在类投入使用之前调用此方法* 因为刚开始我觉得这种方式(@PostConstruct) 不合适,就是没能做到修改了马上就能用的那种感觉。* 但是后来写完才发现,其实只要每次添加新的邮件发送人时,都重新初始化一次就可以了。* 后来我又用启动事件监听器。@PostConstruct 后来就没去测试了。* 理论添加、修改完 调用这个初始化方法就可以了。*/
//    @PostConstructpublic void buildMailSender() {log.info("初始化mailSender");List<MailPO> mails = mailMapper.selectList(new QueryWrapper<MailPO>().eq("state", 1));/*** 需求:原本就是打算做成一个动态的邮件发送人,因为如果总是用一个邮件发送验证码或者是那种打扰短信,速度一旦太过于频繁,就会造成邮件发送错误。* 思路:从数据库中拿到所有可用的邮件发送人,然后封装起来,之后发送邮件时,再进行随机的选择即可。* 另外一种方式就是这是动态的。* 最后就是加个兜底的,如果数据库中查询不到邮件发送人,我们使用配置文件中的发送邮件的配置。*/if(mails!=null&&!mails.isEmpty()){mails.forEach(mail -> {JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();javaMailSender.setDefaultEncoding(mail.getDefaultEncoding());javaMailSender.setHost(mail.getEmailHost());javaMailSender.setPort(mail.getEmailPort());javaMailSender.setProtocol(mail.getProtocol());javaMailSender.setUsername(mail.getEmailUsername());javaMailSender.setPassword(mail.getEmailPassword());// 添加数据senderList.add(javaMailSender);});}else{JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();javaMailSender.setDefaultEncoding(mailProperties.getDefaultEncoding());javaMailSender.setHost(mailProperties.getHost());javaMailSender.setPort(mailProperties.getPort());javaMailSender.setProtocol(mailProperties.getProtocol());javaMailSender.setUsername(mailProperties.getUsername());javaMailSender.setPassword(mailProperties.getPassword());// 添加数据senderList.add(javaMailSender);}}/*** 获取MailSender** @return CustomMailSender*/public JavaMailSenderImpl getSender() {if (senderList.isEmpty()) {buildMailSender();}// 随机返回一个JavaMailSenderreturn senderList.get(new Random().nextInt(senderList.size()));}/*** 清理 sender*/public void clear() {senderList.clear();}
}

2.5、监听器

一两句没啥说的,可以直接通过idea进去看源码上的doc注解。下次再一起研究。

/*** 初始化操作* 目前只定义了动态设置邮件发送人的操作* @Author: crush* @Date: 2021-11-26 19:51* version 1.0*/
@Slf4j
@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
public class StartListener implements ApplicationListener<ApplicationStartedEvent> {MailSenderConfig mailSenderConfig;public StartListener(MailSenderConfig mailSenderConfig) {this.mailSenderConfig = mailSenderConfig;}@SneakyThrows@Overridepublic void onApplicationEvent(@NotNull ApplicationStartedEvent event) {this.mailSenderConfig.buildMailSender();}
}

2.6、controller

/*** @Author: crush* @Date: 2021-11-26 16:10* version 1.0*/
@RestController
@RequestMapping("/email")
public class MailController {@Autowiredprivate MailService mailService;@PostMapping("/send")public String send(@RequestBody MailDTO mailDTO){mailService.send(mailDTO);return "发送成功!!!可能会稍有延迟,请查看邮箱信息!!";}@PostMapping("/addConfig")public String addMailPerson(@RequestBody MailPO mailPO){String message=mailService.addMailPerson(mailPO)?"添加成功!!!不过,请注意:可能会有延迟":"添加失败,请稍后重试!!";return message;}}

三、测试

模板大致就是如下状态吧。

是添加进去的

多点了一次哈。

我再点击发送邮件,因为是随机数的方式,我们多测试几次,总会用到这个错误的邮件发送人的,用到了就表示我们已经成功啦哈。

因为添加的随便输入的,肯定是失败的哈。但是可以确定我们用到了我们项目启动后加入的邮件发送人啦。 你们可以填入争取的试一试。

结束了结束啦。

没写小demo,没啥源码。


后语

大家一起加油!!!如若文章中有不足之处,请大家及时指出,在此郑重感谢。

一分钟弄懂SpringBoot 动态设置邮件发送人相关推荐

  1. 你有没有觉得邮件发送人固定配置在yml文件中是不妥当的呢?SpringBoot 动态设置邮件发送人

    明月当天,不知道你有没有思念的人 前言 之前其实已经写过SpringBoot异步发送邮件,但是今天在一个小项目中要用到发送邮件时,我突然觉得邮件发送人只有一个,并且固定写在yml文件中,就是非常的不妥 ...

  2. 职称计算机证是继续教育的内容吗,豆腐网教你一分钟弄懂继续教育学时认定表及上传注意事项~...

    原标题:豆腐网教你一分钟弄懂继续教育学时认定表及上传注意事项~ 大家好,我是豆腐网王老师,专注于南京工程师职称评审政策解读,关注我,让您轻松面对职称评审,少走弯路!!! 南京中高级职称申报已有段时间, ...

  3. 5分钟弄懂语音识别技术原理

    5分钟弄懂语音识别技术原理 首先,我们知道声音实际上是一种波.常见的mp3.wmv等格式都是压缩格式,必须转成非压缩的纯波形文件来处理,比如Windows PCM文件,也就是俗称的wav文件.wav文 ...

  4. 十分钟弄懂什么是跳表,不懂可以来打我

    引言 今天我们来学习一种可以快速查找.插入.删除的数据结构,据说可以代替红黑树.就是本文的标题--跳表(SkipList).跳表还有一个优点是实现起来简单. redis中的有序集合,其实就是基于跳表实 ...

  5. 5分钟弄懂Docker

    尽管之前久闻Docker的大名了,但是天资愚钝,对其到底是个啥东西一直摸不清,最近花了一段时间整理了一下,算是整理出一点头绪来. 官网的介绍是这样的: Docker is an open platfo ...

  6. 十分钟弄懂最快的APP自动化工具uiautomator2

    相信很多使用appium做过APP自动化的人都深有感触: appium运行慢.时间长 uiautomatorviewer定位元素时得关掉appium server 在低版本的appium上获取toas ...

  7. 10分钟弄懂当前各主流区块链架构

    最近区块链的概念可谓十分火热,从风投的投资到企业招聘区块链人才,似乎处处暗示着该技术将会给人类带来巨大改变.废话不多说,咱们就从技术角度来了解一下当前最主流的区块链诸如比特币.以太坊.HyperLed ...

  8. 一个列子让你弄懂SpringBoot实现后台框架的搭建

    首先项目搭建 首先项目基于idea来写的,下面演示项目搭建d     首先项目搭建 记住Application文件一定要在根目录底下不然程序会运行不起来的 然后开始新建包. constant :常量包 ...

  9. 再见乱码:5分钟读懂MySQL字符集设置

    一.内容概述 在MySQL的使用过程中,了解字符集.字符序的概念,以及不同设置对数据存储.比较的影响非常重要.不少同学在日常工作中遇到的"乱码"问题,很有可能就是因为对字符集与字符 ...

最新文章

  1. 怎样提高WebService的性能
  2. jquery php 异步图片上传实例,php结合jquery异步上传图片(ajaxSubmit)
  3. 可打开可关闭的选项卡,单纯无污染,改改样式就能用
  4. c#类中字段和方法中变量的声明问题
  5. 微信高并发资金交易系统设计方案——百亿红包背后的技术支撑
  6. 低版本VC2010打开高版本VC2012的方法
  7. 标准盒模型与IE盒模型的区别
  8. 僵尸网络研究报告(2016)
  9. org.eclipse.jdt版本更新导致包引入问题
  10. 计算机基础知识表格斜线,在WORD中,其中一个表格里画一斜线怎么画?
  11. 电脑连不上网,WiFi没有显示出来
  12. 模拟QQ自动隐藏窗体
  13. 安徽省二计算机office试题及答案,计算机二级(MSOFFICE)模拟考试题及答案题目2
  14. OpenCV - GrabCut 算法抠图(Python实现)
  15. JQuery滚动条及位置相关方法
  16. CAS:385437-57-0,DSPE-PEG-Biotin,磷脂-聚乙二醇-生物素用于生物分子的检测
  17. 笑谈贝叶斯网络(干货)上
  18. console.log()打印花样颜色
  19. 01-HTML学习笔记
  20. Ubuntu 18 安装eclipse

热门文章

  1. c语言错排公式编程,不容易系列2-题解(C++代码)【递归算法 错排公式秒杀】
  2. 【Nginx系列】- 初识Nginx
  3. 数说CS|北航人工智能是怎样的存在?
  4. (附源码)计算机毕业设计SSM基于的优质房源房租管理系统
  5. Android中录音的使用
  6. Cefsharp支持MP4和MP3的CEF库cef.redist.x86.3.2623,对应Cefsharp49
  7. indesign 显示黑屏_我的苹果电脑老是莫名其妙黑屏为什么?
  8. python路径怎么查_如何查看python路径
  9. 蔚来,还有几张底牌可打?
  10. c语言编写平方根函数不用库函数,不使用库函数sqrt实现求一个数的平方根