SpringBoot实现邮件推送 SpringBoot实现邮

SpringBoot实现邮件推送

在项目中经常会遇到SpringBoot推送消息的业务,除了站内推送通知,邮件推送也是一种常见的方式,本次小鹿就带大家实现邮件推送。

引入依赖

1
2
3
4
5
6
7
8
9
10
xml复制代码<!-- spring mail -->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- thymeleaf -->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
  1. spring-boot-starter-mail:
* 作用:提供了使用Spring Framework的邮件发送功能的起步依赖。
* 功能:使得在Spring Boot应用中可以轻松地配置和使用邮件发送功能,包括发送简单文本邮件、HTML邮件、附件邮件等。
* 使用:结合Spring的邮件模块,你可以方便地在你的应用程序中集成邮件发送功能,无论是用于发送通知、验证邮件还是其他目的。
  1. spring-boot-starter-thymeleaf:
* 作用:提供了使用Thymeleaf模板引擎的起步依赖。
* 功能:Thymeleaf是一种流行的Java模板引擎,用于在Web应用中创建动态HTML模板。
* 使用:结合Spring Boot和Thymeleaf,你可以使用Thymeleaf的模板语言来生成动态内容,比如渲染服务器端数据到HTML页面上,以便在Web应用中更灵活地展示数据。

在项目中,使用第二个依赖再结合静态的html文件就可以实现,将邮件以预定义模板的形式发送出去。

image-20240402174901485

在实际中只需要将对应的值以Map的方式填入到对应字段中即可,别急~接下来小鹿会带大家实现的。

0_8518639

配置

在项目配置中加入如下配置

yml格式如下:

1
2
3
4
5
6
7
8
yaml复制代码spring:
 # 邮箱配置
mail:
  host: smtp.qq.com
   # 用户名 替换成你实际的用户名
  username: test@foxmail.com
   # 授权码 可以去官方申请 不是个人邮箱密码
  password: xxxxxxxxxx

application.properties文件格式如下:

1
2
3
4
5
6
7
8
9
ini复制代码# 需要开启 smtp qq邮箱为例
spring.mail.host=smtp.qq.com
spring.mail.port=465
# 发件人的邮箱
spring.mail.username=xxxxx
# qq 邮箱的第三方授权码 并非个人密码
spring.mail.password=xxxx
#开启ssl 否则 503 错误 但是实际测试发现其实不加也不会报错 但是最好还是加上
spring.mail.properties.mail.smtp.ssl.enable=true

代码具体实现

创建邮件实体封装类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
kotlin复制代码package com.ican.model.dto;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Map;

/**
* 邮箱DTO
* @author xiayexiaolu
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "邮箱DTO")
public class MailDTO {

   /**
    * 接收者邮箱号
    */
   @ApiModelProperty(value = "接收者邮箱号")
   private String toEmail;

   /**
    * 主题
    */
   @ApiModelProperty(value = "主题")
   private String subject;

   /**
    * 内容
    */
   @ApiModelProperty(value = "内容")
   private String content;

   /**
    * 内容信息
    */
   @ApiModelProperty(value = "内容信息")
   private Map<String, Object> contentMap;

   /**
    * 邮件模板
    */
   @ApiModelProperty(value = "邮件模板")
   private String template;
}

创建邮件服务接口并实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
java复制代码package com.ican.service;

import com.ican.model.dto.MailDTO;

/**
* 邮件服务接口
*
* @author xiaoyexiaolu
**/
public interface EmailService {

   /**
    * 发送简单邮件
    *
    * @param mailDTO 邮件信息
    */
   void sendSimpleMail(MailDTO mailDTO);

   /**
    * 发送HTML邮件
    *
    * @param mailDTO 邮件信息
    */
   void sendHtmlMail(MailDTO mailDTO);
}

对接口进行实现,下面为模板代码,可直接使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
ini复制代码package com.ican.service.impl;

import com.ican.model.dto.MailDTO;
import com.ican.service.EmailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;

/**
* 邮件服务接口实现类
*
* @author xiayexiaolu
**/
@Service
public class EmailServiceImpl implements EmailService {

   /**
    * 邮箱号
    */
   @Value("${spring.mail.username}")
   private String email;

   @Autowired
   private JavaMailSender javaMailSender;

   @Autowired
   private TemplateEngine templateEngine;

   @Override
   public void sendSimpleMail(MailDTO mailDTO) {
       SimpleMailMessage simpleMail = new SimpleMailMessage();
       simpleMail.setFrom(email);
       simpleMail.setTo(mailDTO.getToEmail());
       simpleMail.setSubject(mailDTO.getSubject());
       simpleMail.setText(mailDTO.getContent());
       javaMailSender.send(simpleMail);
  }

   @Override
   public void sendHtmlMail(MailDTO mailDTO) {
       try {
           MimeMessage mimeMessage = javaMailSender.createMimeMessage();
           MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage);
           Context context = new Context();
           context.setVariables(mailDTO.getContentMap());
           String process = templateEngine.process(mailDTO.getTemplate(), context);
           mimeMessageHelper.setFrom(email);
           mimeMessageHelper.setTo(mailDTO.getToEmail());
           mimeMessageHelper.setSubject(mailDTO.getSubject());
           mimeMessageHelper.setText(process, true);
           javaMailSender.send(mimeMessage);
      } catch (MessagingException e) {
           e.printStackTrace();
      }
  }
}

其实到这里发送邮件就已经能用了,但是如果使用原生发送邮件的方式可能会有少许缺点。使用消息队列有以下好处

  1. 异步处理:通过消息队列,你可以将邮件发送操作异步化,即使发送邮件的过程比较耗时,也不会阻塞主线程,提高了应用程序的响应速度和吞吐量。
  2. 解耦:使用消息队列可以将邮件发送操作解耦合,发送邮件的业务逻辑与其他业务逻辑相互独立。这意味着你可以轻松地更改或扩展邮件发送的实现方式,而不影响其他业务逻辑。
  3. 负载均衡:通过消息队列,你可以将邮件发送请求分发到多个邮件发送服务节点上,从而实现负载均衡,提高了系统的稳定性和可用性。
  4. 削峰填谷:在高并发情况下,邮件发送请求可能会突然增加,而消息队列可以帮助平滑处理这种突发情况,避免邮件服务器过载。
  5. 失败处理:使用消息队列可以更好地处理邮件发送失败的情况。如果邮件发送失败,你可以通过消息队列实现重试机制或者将失败的消息重新放回队列,以便稍后再次尝试发送。

使用消息队列实现邮件发送

额外引入依赖

1
2
3
4
5
6
xml复制代码<!-- spring amqp -->
<dependency>
     <groupId>cn.dev33</groupId>
     <artifactId>sa-token-spring-boot-starter</artifactId>
     <version>${saToken.version}</version>
</dependency>

这个依赖会自动地添加所需的 RabbitMQ 客户端库,并配置好Spring Boot的AMQP支持。

在配置中配置连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
yaml复制代码spring:
 # rabbitmq配置
rabbitmq:
  host: localhost
  port: 5672
  username: guest
  password: guest
  listener:
    simple:
      retry:
        enabled: true
         # 重试间隔时间
        initial-interval: 3000
         # 最大重试次数
        max-attempts: 3

创建邮件消费者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
less复制代码package com.ican.consumer;

import com.ican.model.dto.MailDTO;
import com.ican.service.EmailService;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;

import static com.ican.constant.MqConstant.*;

/**
* 邮件消费者
* @author xiayexiaolu
*/
@Component
public class EmailConsumer {

@Autowired
private EmailService emailService;

@RabbitListener(bindings = {
@QueueBinding(
value = @Queue(value = EMAIL_SIMPLE_QUEUE, durable = "true", autoDelete = "false"),
exchange = @Exchange(value = EMAIL_EXCHANGE, type = ExchangeTypes.TOPIC),
key = EMAIL_SIMPLE_KEY
)})
public void listenSendSimpleEmail(@Payload MailDTO mail) {
emailService.sendSimpleMail(mail);
}

@RabbitListener(bindings = {
@QueueBinding(
value = @Queue(value = EMAIL_HTML_QUEUE, durable = "true", autoDelete = "false"),
exchange = @Exchange(value = EMAIL_EXCHANGE, type = ExchangeTypes.TOPIC),
key = EMAIL_HTML_KEY
)})
public void listenSendHtmlEmail(@Payload MailDTO mail) {
emailService.sendHtmlMail(mail);
}
}
  1. @Component 注解表示这是一个 Spring 组件,会被 Spring 扫描并纳入到应用程序的上下文中。
  2. @Autowired 注解注入了一个 EmailService 对象,用于实际发送邮件的逻辑处理。
  3. 使用了 @RabbitListener 注解标注了两个方法,分别用于监听两个队列中的消息。这两个方法分别处理发送简单邮件和发送 HTML 邮件的逻辑。
  4. @RabbitListener 注解中,通过 @QueueBinding 注解配置了队列与交换机的绑定关系,指定了队列的属性和交换机的名称、类型、路由键等信息。
  5. 在方法参数中使用 @Payload 注解,指定了消息体的类型为 MailDTO,这样方法参数就会自动解析为消息体的内容。

具体使用

首先需要创建一个邮件对象

1
2
3
4
5
6
7
scss复制代码MailDTO mailDTO = new MailDTO();
mailDTO.setToEmail("目标邮箱");
mailDTO.setSubject("邮件主题");
mailDTO.setTemplate("邮件使用的模板"); //这里需要在之前加入了thymeleaf依赖支持
mailDTO.setContentMap(contentMap);

// 这里的contentMap是一个HashMap 也是最重要的参数,用于将值映射到模板中 具体示例如下图所示

image-20240402194651803

image-20240402194831578

然后直接使用代码:

1
2
scss复制代码// 发送HTML邮件
rabbitTemplate.convertAndSend(EMAIL_EXCHANGE, EMAIL_HTML_KEY, mailDTO);

背后的原理

  1. 邮件发送(生产者)
* 当你执行 `rabbitTemplate.convertAndSend(EMAIL_EXCHANGE, EMAIL_HTML_KEY, mailDTO);` 时,实际上是将 `mailDTO` 对象发送到了 RabbitMQ 中的 `EMAIL_EXCHANGE` 交换机,并使用 `EMAIL_HTML_KEY` 路由键。
* 这个过程是异步的,即发送操作执行后就会立即返回,而不会等待邮件真正发送完成。
  1. 邮件消费者
* 通过 `@RabbitListener` 注解,你的邮件消费者监听了名为 `EMAIL_HTML_QUEUE` 的队列。
* 当有消息到达队列时,`listenSendHtmlEmail` 方法会被调用,并传入消息体 `mailDTO`。
* 在 `listenSendHtmlEmail` 方法中,调用了 `emailService.sendHtmlMail(mail)` 方法来实际发送邮件。
  1. 消息传递
* RabbitMQ 确保了消息传递的可靠性和顺序性。当你发送一条消息到交换机时,RabbitMQ 会根据路由规则将消息路由到对应的队列中去。
* 邮件消费者监听队列,一旦有消息到达队列,就会立即触发消费者方法的执行,从而实现邮件发送的过程。

总的来说,执行 rabbitTemplate.convertAndSend(EMAIL_EXCHANGE, EMAIL_HTML_KEY, mailDTO); 之后,程序并不会自动调用消费者中的代码,而是将消息发送到 RabbitMQ 中,并触发消费者的监听。一旦有消息到达队列,消费者会立即执行对应的消费方法,完成邮件发送的过程。

小结

本文介绍了如何在Spring Boot项目中实现邮件推送功能。首先,通过引入相关依赖,包括spring-boot-starter-mailspring-boot-starter-thymeleaf,使得项目具备了发送邮件和使用Thymeleaf模板的能力。然后,配置了邮件服务的连接信息,包括邮箱的主机、端口、用户名和授权码等。接着,创建了邮件实体封装类MailDTO,定义了邮件的相关信息。通过邮件服务接口EmailService和其实现类EmailServiceImpl,实现了发送简单邮件和HTML邮件的功能。此外,还介绍了使用消息队列来异步处理邮件发送的好处,以及如何通过RabbitMQ实现邮件发送的异步处理。最后,通过具体的代码示例,展示了如何在项目中使用消息队列发送邮件,并给出了发送邮件的具体步骤。

小鹿的朋友们~大家共同加油呀
少女 è 报纸墙 4K动漫壁纸_彼岸图网

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%