首页 专题 文章 代码 归档
SpringBoot发送邮件
2020.03.15 20:33 2020.07.02 09:55

1. 概述

SpringBoot父项目已经为我们整合好了具体的Mail了,我们只需要加入starter依赖即可!

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

Spring框架中用于Java邮件支持的接口和类组织如下:

  1. MailSender interface:发送简单基础电子邮件的顶级接口;
  2. JavaMailSender interface:是MailSender的子接口。它支持MIME消息,并且主要与MimeMessageHelper类一起用于创建MimeMessage。建议在此接口实现类JavaMailSenderImpl中使用MimeMessagePreparator机制;
  3. JavaMailSenderImpl class:实现了JavaMailSender 的接口,它支持MimeMessageSimpleMailMessage
  4. SimpleMailMessage class:用于创建简单的邮件消息,包括from,to,cc,subject和text字段;
  5. MimeMessagePreparator interface:提供一个回调接口,用于编写MIME消息;
  6. MimeMessageHelper class:用于创建MIME消息的帮助类。它为HTML布局中的图像,典型邮件附件和文本内容提供支持。

我们要用到的,也就上面的这些东西了!

2. 简单邮件发送

简单邮件,也即纯文本方式发送邮件!

1、application.yml配置

spring:
  mail:
    host: smtp.qq.com
    password: password
    username: admin@qq.com
    port: 25

2、定义一个接口

package com.misiai.test01.service;

public interface EmailService {
    void sendSimpleMessage(String to,
                           String subject,
                           String text);
}

实现类:

package com.misiai.test01.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.stereotype.Service;

@Service
public class EmailServiceImpl implements EmailService {

    @Autowired
    private JavaMailSenderImpl javaMailSender;

    @Override
    public void sendSimpleMessage(String to, String subject, String text) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setTo(to);
        message.setSubject(subject);
        message.setFrom("admin@qq.com");
        message.setText(text);
        javaMailSender.send(message);

    }
}

测试:

@SpringBootTest
class EmailServiceImplTest {

    @Autowired
    EmailService emailService;

    @Test
    void sendSimpleMessage() {
        // System.out.println("hello");
        emailService.sendSimpleMessage("xxx@qq.com", "你好,这是Java email", "迷思爱学习乐园");
    }
}

没有问题,成功发送!!

3. HTML模板邮件

光是纯文本,邮件过于“难看”,所以使用HTML是大多是真实场景的选择;

增加Thymeleaf 依赖:

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

然后和之前步骤一样,只不过多了处理HTML步骤:

@Override
public void sendHtmlMail(String to, String subject, String templatePath) {
    MimeMessage message = javaMailSender.createMimeMessage();
    try {
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setFrom("admin@qq.com");
        helper.setTo(to);
        helper.setSubject(subject);

        // 携带参数
        Map<String, Object> model = new HashMap<>();
        model.put("username", "迷思爱");
        // 给模板的参数的上下文
        Context ctx = new Context();
        ctx.setVariable("emailParam", model);
        String html = templateEngine.process(templatePath, ctx);// 处理模板文件,返回的是处理好了的字符串
        helper.setText(html, true);
        javaMailSender.send(message);
        System.out.println("html格式邮件发送成功");
    } catch (MessagingException e) {
        System.out.println("html格式邮件发送失败");
    }
}

这里接口代码就没贴上来,一样的!

然后,下面就是HTML模板代码(位于:templates/email/Email.html):

<!DOCTYPE html>
<html lang="zh_CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>发送邮件</title>
</head>
<body>
<span th:text="${emailParam.username}" style="color: red;"></span>
<span style="color: aqua">hello world</span>
</body>
</html>

我们在调用的时候,将模板代码传入进去即可:

@Test
void sendHtmlMail() {
    emailService.sendHtmlMail("admin@qq.com", "你好,这是Java email 【HTML】", "email/Email");
}

上面参数的email/Email是HTML模板的位置,去掉.html

4. 发送附件

其实也很简单,发送调用一个方法即可:

MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.addAttachment("filename", new File("D:\\hello"));

5. 异步发送问题

异步其实很简单,加上个配置类:

AsyncConfig.java

@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        // 线程池维护线程的最少数量
        taskExecutor.setCorePoolSize(10);
        // 线程池维护线程的最大数量
        taskExecutor.setMaxPoolSize(50);
        // 缓存队列
        taskExecutor.setQueueCapacity(99999);
        // 对拒绝task的处理策略
        //(1) 默认的ThreadPoolExecutor.AbortPolicy   处理程序遭到拒绝将抛出运行时RejectedExecutionException;
        //(2) ThreadPoolExecutor.CallerRunsPolicy 线程调用运行该任务的 execute 本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度
        //(3) ThreadPoolExecutor.DiscardPolicy  不能执行的任务将被删除;
        //(4) ThreadPoolExecutor.DiscardOldestPolicy  如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 线程名前缀,方便排查问题
        taskExecutor.setThreadNamePrefix("order-send-thread-");
        // 注意一定要初始化
        taskExecutor.initialize();

        return taskExecutor;
    }

}

然后再需要异步的方法上加个@Async注解即可

需要注意的是,加上该注解的方法,只能返回void


踩坑

异步方法(被@Async注解的方法),只能通过代理调用

什么意思?

比如在EmailService类,这是个service层的类,交由spring管理,此类中有两个方法(check和send)

check就是做一些校验,校验成功后调用send发送邮箱验证码

但是如果要异步发送,你就只能通过在controller层通过emailService.send()调用,而不能在check方法内部调用send方法,不然就不会走异步,还是会以同步的方式发送邮件。

本节阅读完毕! (分享
二维码图片 扫描关注我们哟