明月当天,不晓得你有没有怀念的人

前言

之前其实曾经写过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层

@Repositorypublic 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 * 邮箱发送实现类 */@Servicepublic 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 * 邮箱发送-前端传输参数 */@Datapublic class MailDTO implements Serializable {    /*** 承受邮箱账户*/    private String mail;    /*** 邮箱题目*/    private String title;    /** * 要发送的内容*/    private String content;}

2.4、MailSenderConfig 配置类

/** * @author crush */@Slf4j@Component@AllArgsConstructorpublic 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的,必定会把专栏写完的。