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

前言

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

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

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

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


一、需求分析

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

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

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

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


二、详细步骤

2.1、编码

1)yml配置文件

spring:
mail:
host: smtp.163.com
username: nxxxxxx@163.com
password: IXXXXXXXXXN(开启允许第三方登录后的授权码)
default-encoding: utf-8
protocol: smtps
properties:
mail:
smtp:
port: 465
auth: true
starttls:
enable: true
required: 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 { @Autowired
MailSenderConfig senderConfig; @Autowired
MailProperties mailProperties; @Autowired
MailMapper mailMapper; // 这里之前配置了一个线程池,上文的链接中有,就不说了哈
// @Async("taskExecutor")
@Override
public 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();
} } // 添加就清空初始化的信息,重新初始化一遍即可。
@Override
public 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 后来就没去测试了。
* 理论添加、修改完 调用这个初始化方法就可以了。
*/
// @PostConstruct
public 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();
}
// 随机返回一个JavaMailSender
return 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
@Override
public 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 { @Autowired
private 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,没啥源码。


后语

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

纸上得来终觉浅,绝知此事要躬行。

大家好,我是博主宁在春主页

一名喜欢文艺却踏上编程这条道路的小青年。

希望:我们,待别日相见时,都已有所成


难得回到后端肝篇文,又拾起后端了,之后还会接着写Vue的,肯定会把专栏写完的。

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

  1. Jenkins邮件配置,实现邮件发送策略(可实现每个Job对应不同的发送邮箱)

    前言: 首先,要有一个用来发送的邮箱,首选网易!参考:http://www.cnblogs.com/EasonJim/p/6051636.html,这里我注册了网易的免费企业邮箱. 并且我新建没多个邮 ...

  2. Java 邮件发送

    <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId&g ...

  3. python SMTP邮件发送(转载)

    Python SMTP发送邮件 SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式. py ...

  4. 【Java EE 学习 21 下】【使用java实现邮件发送、邮件验证】

    一.邮件发送 1.邮件发送使用SMTP协议或者IMAP协议,这里使用SMTP协议演示. SMTP协议使用的端口号:25 rfc821详细记载了该协议的相关信息 (1)使用telnet发送邮件(使用12 ...

  5. redmine邮件发送功能配置详解

    redmine的邮件发送功能还是很有用的.像项目有更新啦,任务分配啦,都能邮件发送的相关责任人.我自己在linux服务器上安装并启动了redmine后,邮件一直发送了不了.查了网上的资料,都是讲修改下 ...

  6. Java远程调用邮件服务器,实现邮件发送

    写这篇文章的背景是公司Android客户端需要实现一个功能,实现类似于密码找回或者用户注册完发送一个邮件给用户的功能,当然这些逻辑客户端只负责请求自己的服务端,自己的服务端再去请求邮件服务器. 邮件服 ...

  7. 邮件发送 java

    package com.sun.mail; import java.io.File;import java.io.IOException;import java.io.UnsupportedEncod ...

  8. java 邮件发送工具类

    首先需要下载mail.jar文件,我个人通常是使用maven中心库的那个: <dependency> <groupId>javax.mail</groupId> & ...

  9. 基于javaMail的邮件发送--excel作为附件

    基于JavaMail的Java邮件发送 Author xiuhong.chen@hand-china.com Desc 简单邮件发送 Date 2017/12/8 项目中需要根据物料资质的状况实时给用 ...

随机推荐

  1. 激活NX窗口的按钮

    原理:取得按钮名称以后,通过运行宏文件激活按钮 Imports System.IO Imports System.Runtime.InteropServices Imports NXOpen.Menu ...

  2. Zookeeper+Dubbo环境搭建与Demo测试

     环境准备: 1. zookeeper-3.4.14     (下载地址:http://archive.apache.org/dist/zookeeper/) 2. dubbo-0.2.0 (下载地址 ...

  3. django 中的hello word 开心,通过申请博客了,,发个随笔庆祝一下~~~~~~~

    django 中的hello word! 准备:[pymsql,pycharm,django3.0.7] >>>终端中:django-admin.py startproject [项 ...

  4. Java:异常小记

    Java:异常小记 对 Java 中的 异常 ,做一个微不足道的小小小小记 Error 和 Exception 相同点: Exception 和Error 都是继承了 Throwable 类,在 Ja ...

  5. 提升使用Linux效率的小操作

    提升使用Linux效率的小操作 保存更新? 本文记录了个人在使用Linux时觉得好用的一些快捷方式/功能: 为那种知道了能提高效率,但是的不知道也并没有影响的操作. 历史命令 该操作用于快速查看已使用 ...

  6. Intellij IDEA 2021.2.3 最新版免费激活教程(可激活至 2099 年,亲测有效)

    ​ 申明,本教程 Intellij IDEA 最新版破解.激活码均收集与网络,请勿商用,仅供个人学习使用,如有侵权,请联系作者删除.如条件允许,建议大家购买正版. 本教程更新于:2021 年 10 月 ...

  7. Mysql的入门和连接问题

    Mysql的连接问题 最近学完了mysql的基础语法,基本上是掌握了mysql的简单运用. 1.入门mysql 我是通过看<漫画sql>入门的,这个视频案例很到位,跟着2倍速学前9章就可以 ...

  8. Vue:Vue的介绍以及组件剖析

    介绍 现在,随着基于JavaScript的单页应用程序(SPA)和服务器端渲染(SSR)的兴起,可以用JavaScript编写整个前端应用程序,并整洁地管理和维护该应用程序的前端代码.诸如Angula ...

  9. PSS--待看

    转载:浅谈可移植激励规范(PSS)复用策略_路科验证-CSDN博客 译者按 :当今硬件设计变得愈加复杂,如何创建出足够的测试来保证设计的正确性是每个硬件工程师需要面对的问题.Accellera的可移植 ...

  10. 51nod_1001 数组中和等于K的数对(二分)

    题意: 给出一个整数K和一个无序数组A,A的元素为N个互不相同的整数,找出数组A中所有和等于K的数对.例如K = 8,数组A:{-1,6,5,3,4,2,9,0,8},所有和等于8的数对包括(-1,9 ...