SpringBoot多邮件源发送邮件

前言

  最近由于业务需要,需要使用邮件对用户进行通知,但是单个邮箱有发送限制,当推送量过多时,经常会出现失败,于是考虑使用多个邮箱进行发送,由于spring-boot-starter-mail不支持同时配置多个邮件源,所以决定自己动手实现。

实现思路

  spring-boot-starter-mail会根据spring.mail.xxx相关配置对JavaMailSender进行自动配置。但是只支持单个邮箱。为了实现多邮件源,可以参照上述逻辑。在配置文件内配置好,多个邮件源。然后读取配置文件,手动对JavaMailSender进行配置,并将其初始化完毕的JavaMailSender存储容器内。然后发送时随机取出JavaMailSender进行发送。

引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

邮件yml配置

替换实际的邮件配置

# 配置邮件
mail:
  configs:
    # 账号
    - username: fapiao@QQ.com
      password: 123456
      host: smtp.qq.com
      port: 25
      protocol: smtp
      default-encoding: UTF-8
    # 账号A
    - username: fapiaoa@QQ.com
      password: 123456
      host: smtp.qq.com
      port: 25
      protocol: smtp
      default-encoding: UTF-8

MailConfig

@Data
@Component
@ConfigurationProperties(prefix = "mail")
public class MailConfig {

    private List<MailProperties> configs;

    @Data
    public static class MailProperties {

        /**
         * 密码
         */
        private String username;

        /**
         * 密码
         */
        private String password;

        /**
         * host
         */
        private String host;

        /**
         * 端口
         */
        private Integer port;

        /**
         * 协议
         */
        private String protocol;

        /**
         * 默认编码
         */
        private String defaultEncoding;

    }

}

MailSenderConfig

@Slf4j
@Component
@AllArgsConstructor
public class MailSenderConfig {

    private final MailConfig mailConfig;

    private final List<JavaMailSenderImpl> senderList;

    /**
     * 初始化 sender
     */
    @PostConstruct
    public void buildMailSender(){
        List<MailConfig.MailProperties> mailConfigs = mailConfig.getConfigs();
        log.info("初始化mailSender");
        mailConfigs.forEach(mailProperties -> {

            // 邮件发送者
            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();
    }

}

MailService

public interface MailService {

    /**
     * 发送邮件
     * @return 返回 true 或者 false
     */
    boolean sendMail();

}

MailServiceImpl

@Service
@AllArgsConstructor
public class MailServiceImpl implements MailService {

    private final MailSenderConfig senderConfig;

    @Override
    public boolean sendMail() {

        JavaMailSenderImpl mailSender = senderConfig.getSender();

        //创建SimpleMailMessage对象
        SimpleMailMessage message = new SimpleMailMessage();
        //邮件发送人
        message.setFrom(Objects.requireNonNull(mailSender.getUsername()));
        //邮件接收人
        message.setTo("2583174414@qq.com");
        //邮件主题
        message.setSubject("测试邮件");
        //邮件内容
        message.setText("测试邮件内容");
        //发送邮件
        mailSender.send(message);

        return true;
    }
}

测试

@SpringBootTest
@RunWith(SpringRunner.class)
class MailServiceImplTest {

    @Autowired
    private MailServiceImpl mailService;

    @Test
    void sendMail() {
        mailService.sendMail();
    }
}

测试结果

注意的点

  • 需要检查邮箱配置相关协议是否开启。
  • 如果使用QQ邮箱进行发送,密码不是邮箱密码,而是授权码。

拓展

  上述是将邮箱配置写入配置文件,在没有使用配置中心的情况下,如果邮箱源被限制,更改起来相对麻烦。可以将配置存入数据库,在启动的时候从数据库进行加载。如果邮箱源发生更改,可直接更改数据库邮箱源配置,然后调用MailSenderConfig.clear()方法,等待下次发送的时候,会重新初始化配置。

结尾

  如果觉得对你有帮助,可以多多评论,多多点赞哦,也可以到我的主页看看,说不定有你喜欢的文章,也可以随手点个关注哦,谢谢。

  我是不一样的科技宅,每天进步一点点,体验不一样的生活。我们下期见!

每天进步一点点,体验不一样的生活。

216 声望
459 粉丝
0 条评论
推荐阅读
SpringBoot实现热部署两种方式!
小宅作为一个Java程序员,在日常的工作中,经常需要修改代码,然后重启服务,在验证代码是否生效。如果是小项目还好,重启速度比较快,等待时间比较短。但是随着项目逐渐变大,并且被拆分成多个服务时,改动一些...

不一样的科技宅2阅读 3.8k评论 1

Java 编译器 javac 及 Lombok 实现原理解析
javac 是 Java 代码的编译器12,初学 Java 的时候就应该接触过。本文整理一些 javac 相关的高级用法。Lombok 库,大家平常一直在使用,但可能并不知道实现原理解析,其实 Lombok 实现上依赖的是 Java 编译器的注...

nullwy10阅读 5.9k

与RabbitMQ有关的一些知识
工作中用过一段时间的Kafka,不过主要还是RabbitMQ用的多一些。今天主要来讲讲与RabbitMQ相关的一些知识。一些基本概念,以及实际使用场景及一些注意事项。

lpe2348阅读 1.8k

封面图
spring boot 锁
由于当前的项目中由于多线程操作同一个实体,会出现数据覆盖的问题,后保存的实体把先保存的实体的数据给覆盖了。于是查找了锁的实现的几种方式。但写到最后发现,其实自己可以写sql 更新需要更新的字段即可,这...

weiewiyi3阅读 9.1k

Git操作不规范,战友提刀来相见!
年终奖都没了,还要扣我绩效,门都没有,哈哈。这波骚Git操作我也是第一次用,担心闪了腰,所以不仅做了备份,也做了笔记,分享给大家。问题描述小A和我在同时开发一个功能模块,他在优化之前的代码逻辑,我在开...

王中阳Go5阅读 1.8k评论 2

封面图
Redis 发布订阅模式:原理拆解并实现一个消息队列
“65 哥,如果你交了个漂亮小姐姐做女朋友,你会通过什么方式将这个消息广而告之给你的微信好友?““那不得拍点女朋友的美照 + 亲密照弄一个九宫格图文消息在朋友圈发布大肆宣传,暴击单身狗。”像这种 65 哥通过朋...

码哥字节5阅读 1.1k

封面图
NB的Github项目,看到最后一个我惊呆了!
最近看到不少好玩的、实用的 Github 项目,就来给大家推荐一把。中国制霸生成器最近在朋友圈非常火的一个小网站,可以在线标记 居住、短居、游玩、出差、路过 标记后可生成图片进行社区分享,标记过的信息会记录...

艾小仙5阅读 1.5k评论 1

每天进步一点点,体验不一样的生活。

216 声望
459 粉丝
宣传栏