Spring-boot搭建邮件服务

前言:

发送邮件,确定是每一个公司都会有的基本业务。不少公司都会选择把发送邮件做为一个基础服务,对外提供接口。直接调用就可发邮件了。可是咱们都知道发送邮件耗时都比较长。那么今天就介绍下使用Spring boot+eventbus来打造一个简单邮件服务html

规划接口列表

发送邮件的类型准备的有三种java

  1. 发送普通邮件
  2. 发送html邮件
  3. 发送图文邮件

还有一个细节,若是咱们同步的取发送邮件会有两个问题。git

  1. 接口响应时间比较长
  2. 遇到并发的状况,容易致使服务器压力过大或者邮箱服务封ip

因此咱们准备使用队列来执行发送邮件的操做。能够解决这个问题。队列我选用的是Google的eventbus。是一款很轻量的队列。直接走的内存github

准备工做

首先要在pom.xml中引入 须要使用的包spring

<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);
    }
}
复制代码

队列监听

既然封装好了方法,那么就须要调用。调用的方式,其实就是将接口传来的数据传到队列里。队列的消费者接收到了消息就将消息拿来调用发送邮件的方法 咱们首先建立一个消费类,用来接受消息,处理消息。app

@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方法。async

控制器与测试

控制器部分,没什么好说的,我就贴出图文的代码。其他代码能够在个人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替换。最后将实体类抛入队列。直接返回接口请求。队列那边就会排着队搞定全部的邮件 下面来作个测试

请求接口
请求很迅速的返回告终果 而后去邮箱中查看结果
邮件结果

好了今天对邮件服务的介绍就写到这里。知识点并不深奥,主要介绍一个思路。若有不对的地方,请大神指出。谢谢

相关文章
相关标签/搜索