Spring boot搭建邮件服务的完整步骤
作者:祥哥去哪里啊 发布时间:2023-07-20 06:58:34
前言:
发送邮件,肯定是每个公司都会有的基本业务。很多公司都会选择把发送邮件作为一个基础服务,对外提供接口。直接调用就可发邮件了。但是我们都知道发送邮件耗时都比较长。那么今天就介绍下使用Spring boot+eventbus来打造一个简单邮件服务
规划接口列表
发送邮件的类型准备的有三种
发送普通邮件
发送html邮件
发送图文邮件
还有一个细节,如果我们同步的取发送邮件会有两个问题。
接口响应时间比较长
遇到并发的情况,容易导致服务器压力过大或者邮箱服务封ip
所以我们准备使用队列来执行发送邮件的操作。可以解决这个问题。队列我选用的是Google的eventbus。是一款很轻量的队列。直接走的内存
准备工作
首先要在pom.xml中引入 需要使用的包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
spring-boot-starter-mail :spring-boot提供的发邮件的maven库
guava:google提供的开源库。里面包含来很多工具
lombok:可以帮你省去编写实体类的工具
引入之后,我们还需要配置发送邮件所需要的必要配置
在application.properties中配置邮箱
spring.mail.host=smtp.mail.me.com //邮箱发送服务器
spring.mail.port=587//服务器端口
spring.mail.username=xxx6666@icloud.com//发件人邮箱
spring.mail.password=password//客户端专用密码
//如果和我一样使用的icloud邮箱 还需要下列两个配置,别的有的邮箱不需要
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
做到这里其实就已经完成了,发邮件所需要的配置了。但是我们是要用队列来发送,所以还需要配置下队列
@Configuration
public class AsyncEventBusConfig {
//实例化bean,采用单例形式注入容器
@Bean
@Scope("singleton")
public AsyncEventBus asyncEventBus(){
//创建线程池对象
final ThreadPoolExecutor executor=executor();
return new AsyncEventBus(executor);
}
//创建线程池方法
private ThreadPoolExecutor executor(){
return new
ThreadPoolExecutor(2,
2,0L,
TimeUnit.MICROSECONDS,
new LinkedBlockingQueue<>());
}
}
封装EmailService
准备好了之后,就可以直接来封装发送邮件的业务了。之前有提到我们需要三个接口,同样的,我们也需要三个service方法
@Service
public class EmailService {
@Autowired
private JavaMailSender javaMailSender;
/**
* 发件人。这里发件人一般是同使用的发件邮箱一致
*/
@Value("${spring.mail.username}")
private String from;
/**
* 发送文本邮件
* @param to 收件人邮箱地址
* @param subject 主题
* @param content 内容
*/
public void sendTextMail(String to,
String subject,
String content) {
SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
simpleMailMessage.setTo(to);
simpleMailMessage.setSubject(subject);
simpleMailMessage.setText(content);
simpleMailMessage.setFrom(from);
javaMailSender.send(simpleMailMessage);
}
/**
* 发送html内容的邮件
* @param to 收件人
* @param htmlContent html内容
* @param subject 主题
* @throws MessagingException
*/
public void sendHtmlMail(String to,
String htmlContent,
String subject) throws MessagingException {
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper messageHelper = new MimeMessageHelper(message, true);
messageHelper.setTo(to);
messageHelper.setSubject(subject);
messageHelper.setFrom(from);
messageHelper.setText(htmlContent, true);
javaMailSender.send(message);
}
/**
* 发送图文邮件
* @param to 收件人
* @param imgContent 图文内容
* @param subject 主题
* @param rscId 资源id
* @param imgPath 资源路径
* @throws MessagingException
*/
public void sendImgMail(String to,
String imgContent,
String subject,
String rscId,
String imgPath) throws MessagingException {
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper messageHelper = new MimeMessageHelper(message, true);
messageHelper.setTo(to);
messageHelper.setSubject(subject);
messageHelper.setFrom(from);
messageHelper.setText(imgContent, true);
messageHelper.addInline(rscId, new File(imgPath));
javaMailSender.send(message);
}
}
队列监听
既然封装好了方法,那么就需要调用。调用的方式,其实就是将接口传来的数据传到队列里。队列的消费者接收到了消息就将消息拿来调用发送邮件的方法
我们首先创建一个消费类,用来接受消息,处理消息。
@Service
public class EventBusListener {
/**
* 引入bean
*/
@Autowired
private AsyncEventBus asyncEventBus;
@Autowired
private EmailService emailService;
/**
* 注册服务类
*/
@PostConstruct
public void init(){
asyncEventBus.register(this);
}
/**
* 线程安全,消费 文本消息
* @param textEmailDTO
*/
@AllowConcurrentEvents
@Subscribe
public void sendTextMail(TextEmailDTO textEmailDTO){
emailService.sendTextMail(
textEmailDTO.getTo(),
textEmailDTO.getSubject(),
textEmailDTO.getContent()
);
}
/**
* 线程安全 消费 html消息
* @param htmlEmailDTO
*/
@AllowConcurrentEvents
@Subscribe
public void sendHtmlMail(HtmlEmailDTO htmlEmailDTO){
try {
emailService.sendHtmlMail(
htmlEmailDTO.getTo(),
htmlEmailDTO.getHtmlContent(),
htmlEmailDTO.getSubject()
);
} catch (MessagingException e) {
// nothing to do
}
}
/**
* 线程安全 消费 图文消息
* @param imgEmailDTO
*/
@AllowConcurrentEvents
@Subscribe
public void sendImgMail(ImgEmailDTO imgEmailDTO){
try {
emailService.sendImgMail(
imgEmailDTO.getTo(),
imgEmailDTO.getImgContent(),
imgEmailDTO.getSubject(),
imgEmailDTO.getRscId(),
imgEmailDTO.getImgPath()
);
} catch (MessagingException e) {
// nothing to do
}
}
}
其实eventbus抛消息都是使用的post方法来抛消息。走到不同的方法里面是利用了类的多态,抛入不同的实体类就可以进行区分了。走进了不同的方法,就调用相应Service方法。
控制器与测试
控制器部分,没什么好说的,我就贴出图文的代码。其余代码可以在我的github上面看
先看眼实体类
@Data
public class ImgEmailDTO implements Serializable {
public ImgEmailDTO() {
}
/**
* 图片路径
*/
private String imgPath;
/**
* 资源id
*/
private String rscId;
/**
* 主题
*/
private String subject;
/**
* 图片正文(同样可以使用html)
*/
private String imgContent;
/**
* 收件人
*/
private String to;
}
/**
* 发送图文邮件
* @param request
* @return
*/
@RequestMapping(value = "/sendImgMail", method = RequestMethod.POST)
public Result<Integer> sendImgMail(@RequestBody Request<ImgEmailDTO> request) {
Result<Integer> result = Result.create();
ImgEmailDTO imgEmailDTO=request.getData();
StringBuilder sb=new StringBuilder();
sb.append(imgEmailDTO.getImgContent());
//cid:资源id。在spring中会自动绑定
sb.append("<img src=\'cid:").append(imgEmailDTO.getRscId()).append("\'></img>");
imgEmailDTO.setImgContent(sb.toString());
asyncEventBus.post(imgEmailDTO);
return result.success(1);
}
图文要稍微特殊一点,需要拼接下正文内容。然后将实体类中的content替换。最后将实体类抛入队列。直接返回接口请求。队列那边就会排着队搞定所有的邮件
下面来做个测试
请求很迅速的返回了结果
然后去邮箱中查看结果
好了今天对邮件服务的介绍就写到这里。知识点并不深奥,主要介绍一个思路。如有不对的地方,请大神指出。谢谢
来源:https://juejin.im/post/5d79af986fb9a06b1c745908


猜你喜欢
- 当时用逆向生成后,实体类中的下划线都被去掉,这时只需要在sqlmap.xml中加以下代码即可。打开mybatis驼峰法则。 <sett
- 一. 简单介绍一下Spring Boot世界惯例,在学习一个框架之前,我们需要了解一下这个框架的来历。下面我们引用一下百度百科的解释。Spr
- Ping pingSender = new Ping(); PingReply reply = pingSender.Send("
- 业务场景我们知道在使用PageHelper分页插件时,会对执行PageHelper.startPage(pageNum, pageSize)
- 默认路径在Spring Boot 2.7.2版本中,查看默认静态资源路径,在WebProperties.class中如下private st
- 定义:结点的带权路径长度为从该结点到树根之间的路径长度与结点上权的乘积。树的带权路径长度为树中所有叶子结点的带权路径长度之和。假设有n个权值
- 前言研究表明,Java堆中对象占据最大比重的就是字符串对象,所以弄清楚字符串知识很重要,本文主要重点聊聊字符串常量池。Java中的字符串常量
- 最近在工作中处理了一些内存泄露的问题,在这个过程中我尤其发现了一些基本的问题反而忽略导致内存泄露,比如静态变量,cursor关闭,线程,定时
- Java8对List<Integer>的求和想要用流对List<Integer>进行求和,但查找完资料都是对List
- Spring开启注解AOP的支持放置的位置放在springmvc的aop,需要在springmvc的配置文件中写开启aop,而不是sprin
- 文件的重命名与移动操作有时候为了对文件进行统一访问与管理,需要把文件进行重命名,并移动到新的文件夹,如何实现呢?一枚简单的java小程序即可
- 前面有写到Spring+SpringMVC+MyBatis深入学习及搭建(二)——MyBatis原始Dao开发和mapper代理开发MyBa
- 在使用ComboBox控件时,遇到了重新绑定赋值出问题的情况。正常情况下,对于数据重新赋值的或者绑定数据源的时候,为了防止数据出现问题,都会
- spring Cache注解和redis区别1.不支持TTL即不能设置过期时间 expires time,SpringCache 认为这是各
- dynamic是FrameWork4.0的新特性。dynamic的出现让C#具有了弱语言类型的特性。编译器在编译的时候不再对类型进行检查,编
- 概述最近重新回顾了一下数据结构和算法的一些基本知识,对几种排序算法有了更多的理解,也趁此机会通过博客做一个总结。1.选择排序-简单选择排序选
- JVM(Java虚拟机)是一个抽象的计算模型。就如同一台真实的机器,它有自己的指令集和执行引擎,可以在运行时操控内存区域。目的是为构建在其上
- 背景接上文《失踪人口回归,mybatis-plus 3.3.2 发布》[1] ,提供了一个非常实用的功能 「数据安全保护」 功能,不仅支持数
- 概述对于android的so文件的hook根据ELF文件特性分为:Got表hook、Sym表hook和inline hook等。全局符号表(
- 一、C#方法中参数类型有4种参数类型,有时候很难记住它们的不同特征,下图对它们做一个总结,使之更容易比较和对照。二、C#方法中的参数1、值参