文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

基于 Spring Boot 与 RabbitMQ 的邮件发送:确保 100%消息成功投递

2024-11-29 19:55

关注

技术选型与框架介绍

在构建邮件发送系统时,我们精心挑选了 Spring Boot 和 RabbitMQ 这两个强大的技术框架,并充分利用它们各自的优势来实现高效、可靠的邮件投递功能。

Spring Boot 作为一款出色的快速开发框架,为我们提供了诸多便利。它基于 Spring 框架,但极大地简化了项目的配置和部署流程。凭借其内置的自动配置机制,开发者无需繁琐地处理各种基础配置,能够迅速搭建起项目的基本架构。同时,Spring Boot 对各种主流技术和组件的良好集成性,使得我们能够轻松引入所需的依赖,快速构建功能丰富的应用。

RabbitMQ 则是一款卓越的消息代理和队列服务器,在分布式系统的消息传递中发挥着关键作用。其基于先进的消息队列机制,能够有效地应对高并发场景下的消息处理需求。通过将邮件发送任务转化为消息并放入队列中,RabbitMQ 确保了任务的有序处理和可靠传递,即使在系统面临高负载或出现故障的情况下,也能保证邮件发送不丢失、不重复,从而极大地提高了邮件投递的成功率和稳定性。

将 Spring Boot 和 RabbitMQ 相结合,能够充分发挥两者的优势。Spring Boot 提供了便捷的开发环境和高效的应用架构,而 RabbitMQ 则为邮件发送任务提供了可靠的排队和处理机制,共同保障了邮件发送的高效性和 100%投递成功率。

项目依赖配置(pom.xml)



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.7.10
         
    
    com.icoderoad
    mail-sender
    0.0.1-SNAPSHOT
    MailSender
    基于 Spring Boot 和 RabbitMQ 的邮件发送项目

    
        11
    

    
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.boot
            spring-boot-starter-mail
        
        
            org.springframework.amqp
            spring-rabbit
        
        
            org.springframework.boot
            spring-boot-devtools
            true
        
        
            org.projectlombok
            lombok
            true
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    

YAML 属性文件配置(application.yml)

spring:
  mail:
    host: smtp.example.com  # 替换为您的 SMTP 服务器地址
    port: 587  # 端口
    username: your_email@example.com  # 发件人邮箱
    password: your_password  # 邮箱密码
    properties:
      mail.smtp.auth: true
      mail.smtp.starttls.enable: true

rabbitmq:
  host: localhost  # RabbitMQ 服务器地址
  port: 5672  # 端口
  username: guest
  password: guest

后端代码实现

邮件发送服务类(MailService.java)

import lombok.RequiredArgsConstructor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.util.concurrent.ConcurrentHashMap;

@EnableScheduling
@Service
@RequiredArgsConstructor
public class MailService {

    private final JavaMailSender mailSender;
    private final RabbitTemplate rabbitTemplate;
    private static final int MAX_RETRY = 3; // 最大重试次数
    private static final Log LOGGER = LogFactory.getLog(MailService.class);

    private ConcurrentHashMap retryMap = new ConcurrentHashMap<>();

    public boolean sendMail(String to, String subject, String content) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setTo(to);
        message.setSubject(subject);
        message.setText(content);

        int retryCount = 0;
        boolean sentSuccessfully = false;
        String key = to + "_" + subject;

        while (retryCount < MAX_RETRY &&!sentSuccessfully) {
            try {
                mailSender.send(message);
                sentSuccessfully = true;
                retryMap.remove(key);
            } catch (MailException e) {
                retryCount++;
                LOGGER.error("发送邮件失败,重试次数: " + retryCount + ",收件人: " + to + ",主题: " + subject, e);
                retryMap.put(key, retryCount);
            }
        }

        if (!sentSuccessfully) {
            LOGGER.error("邮件发送最终失败,收件人: " + to + ",主题: " + subject);
        }

        return sentSuccessfully;
    }

    @Scheduled(fixedDelay = 60000) // 每分钟执行一次
    public void retryFailedMails() {
        for (String key : retryMap.keySet()) {
            String[] parts = key.split("_");
            String to = parts[0];
            String subject = parts[1];

            SimpleMailMessage message = new SimpleMailMessage();
            message.setTo(to);
            message.setSubject(subject);

            int retryCount = retryMap.get(key);
            boolean sentSuccessfully = false;

            while (retryCount < MAX_RETRY &&!sentSuccessfully) {
                try {
                    mailSender.send(message);
                    sentSuccessfully = true;
                    retryMap.remove(key);
                } catch (MailException e) {
                    retryCount++;
                    if (!sentSuccessfully) {
                        rabbitTemplate.convertAndSend("retryQueue", key);
                        LOGGER.error("重试邮件发送失败,已发送到队列,收件人: " + to + ",主题: " + subject);
                    }
                }
            }

            if (!sentSuccessfully) {
                LOGGER.error("重试邮件发送最终失败,收件人: " + to + ",主题: " + subject);
            }
        }
    }
}

要合理设置最大重试次数,避免过度重试导致资源浪费。同时,在重试间隔上也需要根据实际情况进行合理的设计,以平衡成功率和性能。还需要对重试过程中的异常情况进行更详细的记录和监控,将重试仍不成功的邮件发送信息发送到队列,方便后续进一步处理,提高了系统的灵活性和容错性。

RabbitMQ 配置类(RabbitMQConfig.java)

import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitMQConfig {

    @Bean
    public Queue mailQueue() {
        return new Queue("mail_queue");
    }
}

RabbitMQ 消费者(MailConsumer.java)

import lombok.RequiredArgsConstructor;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class MailConsumer {

    private final MailService mailService;

    @RabbitListener(queues = "mail_queue")
    public void consumeMailMessage(String message) {
        // 解析消息,提取收件人、主题和内容等信息
        String[] parts = message.split(";");
        String to = parts[0];
        String subject = parts[1];
        String content = parts[2];
        mailService.sendMail(to, subject, content);
    }
}

控制器类(MailController.java)

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MailController {

    private final RabbitTemplate rabbitTemplate;

    public MailController(RabbitTemplate rabbitTemplate) {
        this.rabbitTemplate = rabbitTemplate;
    }

    @PostMapping("/sendMail")
    public String sendMail(@RequestBody MailRequest request) {
        // 将邮件信息转换为字符串,发送到 RabbitMQ 队列
        String message = request.getTo() + ";" + request.getSubject() + ";" + request.getContent();
        // 发送到队列
        rabbitTemplate.convertAndSend("mail_queue", message);
        return "邮件发送请求已提交";
    }
}

前端页面实现

使用 Thymeleaf 模板和 JavaScript 实现前端页面:




    
    邮件发送
    


    

邮件发送




通过以上精心设计的架构和精妙绝伦的代码实现,我们成功地借助 Spring Boot 和 RabbitMQ 的强大力量,构建出一个能够确保 100%消息成功投递的邮件发送系统。在此过程中,RabbitMQ 犹如一位坚定的卫士,确保了邮件发送任务的可靠排队和精细处理;而 Spring Boot 则宛如一位智慧的导师,提供了便捷的开发环境和丰富多样的功能支持。

来源:路条编程内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯