一起来学SpringBoot(十二)发送邮件

发送邮件应该是网站的必备功能之一,什么注册验证,忘记密码或者是给用户发送营销信息。最早期的时候我们会使用JavaMail相关api来写发送邮件的相关代码,后来spring退出了JavaMailSender更加简化了邮件发送的过程,在之后springboot对此进行了封装就有了现在的spring-boot-starter-mail,本章文章的介绍主要来自于此包。

首先呢肯定是要加入依赖

   <!-- springboot集成的email -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-mail</artifactId>
    </dependency>

然后呢配置下yml

spring:
  mail:
    host: smtp.163.com
    username: [email protected]
    password: nibuzhidaomima
    properties:
      mail:
          smtp:
              auth: true
              timeout: 25000

写个最简单的服务

package com.mail;

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

@Component
public class MailService {

    @Autowired
    JavaMailSender jms;

    public void send() {
        //建立邮件消息
        SimpleMailMessage mainMessage = new SimpleMailMessage();
        //发送者
        mainMessage.setFrom("[email protected]");
        //接收者
        mainMessage.setTo("[email protected]");
        //发送的标题
        mainMessage.setSubject("嗨喽");
        //发送的内容
        mainMessage.setText("hello world");
        jms.send(mainMessage);
    }
}

这样就实现了发送邮件,其实发模版html的也能实现,但是总感觉不那么大气代码量也死多死多,干脆封装下吧。


首先呢,创建一个实体

package com.maoxs.email.entity;

import lombok.Data;

import java.io.Serializable;
import java.util.Map;

/**
 * @Description: 邮件实体
 *
 * @author fulin
 * @Project
 */
@Data
public class Mail implements Serializable {

    private static final long serialVersionUID = 1L;

    /** 邮件标题 */
    private String title;
    /** 邮件内容 */
    private String content;
    /** 内容格式(默认html) */
    private String contentType;
    /** 接收邮件地址 */
    private String to;

    /*************模板发送****************/
    /** 模板名称 */
    private String templateName;
    /** 模板变量替换 */
    private Map<String, Object> maps;
}

创建类型枚举类

package com.maoxs.email.enums;

/**
 * @Description: 邮件内容的类型
 *
 * @author fulin
 * @Project
 */
public enum MailContentTypeEnum {

    //text格式
    TEXT("text"),
    //html格式
    HTML("html"),
    //模板
    TEMPLATE("template")
    ;

    private String value;

    MailContentTypeEnum(String value) {
        this.value = value;
    }

    public String value() {
        return value;
    }
}

创建一个基于spring的工厂类

package com.maoxs.email.factory;

import com.maoxs.email.enums.MailContentTypeEnum;

import java.util.HashMap;
import java.util.Map;

/**
 * @Description: 邮件发送bean工厂类
 *
 * @author fulin
 * @Project
 */
public class MailFactory {

    private MailFactory() {}

    private static final class InnerMailFactory {
        private static final MailFactory MAIL_FACTORY = new MailFactory();
    }

    private static Map<String, String> maps = new HashMap<>();

    static {
        maps.put(MailContentTypeEnum.TEXT.value(), getStrategyClassName("simple"));
        maps.put(MailContentTypeEnum.HTML.value(), getStrategyClassName("html"));
        maps.put(MailContentTypeEnum.TEMPLATE.value(), getStrategyClassName("template"));
    }

    public static final MailFactory getInstance() {
        return InnerMailFactory.MAIL_FACTORY;
    }

    public String get(String type) {
        return maps.get(type);
    }

    /**
     * 获取策略类名
     *
     * @param classNamePrefix:类名前缀
     * @return
     */
    private static String getStrategyClassName(String classNamePrefix) {
        return classNamePrefix + "MailStrategy";
    }

}

创建 邮件发送策略类的接口

package com.maoxs.email.strategy;

import com.maoxs.email.entity.Mail;

/**
 * @Description: 发送邮件策略接口
 *
 * @author fulin
 * @Project
 */
public interface MailStrategy {

    /**
     * 发送邮件
     *
     * @param from:谁发送
     * @param mail:邮件信息
     */
    void sendMail(String from, Mail mail);

}

然后是三个基础实现类

package com.maoxs.email.strategy.impl;

import com.maoxs.email.entity.Mail;
import com.maoxs.email.strategy.MailStrategy;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;

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

/**
 * @Description: HTML格式发送邮件
 *
 * @author fulin
 * @Project
 */
@Component
public class HtmlMailStrategy implements MailStrategy {
    private static final Logger LOG = LogManager.getLogger("bizLog");

    @Autowired
    private JavaMailSender javaMailSender;

    @Override
    public void sendMail(String from, Mail mail) {
        MimeMessage message = javaMailSender.createMimeMessage();
        try {
            //true表示需要创建一个multipart message
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setFrom(from);
            helper.setTo(mail.getTo());
            helper.setSubject(mail.getTitle());
            helper.setText(mail.getContent(), true);
            javaMailSender.send(message);
            LOG.info("html邮件已经发送{}。", mail.getTo());
        } catch (MessagingException e) {
            LOG.error("发送html邮件时发生异常!", e);
        }
    }
}
package com.maoxs.email.strategy.impl;

import com.maoxs.email.entity.Mail;
import com.maoxs.email.strategy.MailStrategy;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Component;

/**
 * @Description: 简单文本发送邮件
 *
 * @author fulin
 * @Project
 */
@Component
public class SimpleMailStrategy implements MailStrategy {
    private static final Logger LOG = LogManager.getLogger("bizLog");

    @Autowired
    private JavaMailSender javaMailSender;

    @Override
    public void sendMail(String from, Mail mail) {
        SimpleMailMessage message = new SimpleMailMessage();
        try {
            message.setFrom(from);
            message.setTo(mail.getTo());
            message.setSubject(mail.getTitle());
            message.setText(mail.getContent());
            javaMailSender.send(message);
            LOG.info("纯文本的邮件已经发送给【{}】。", mail.getTo());
        } catch (Exception e) {
            LOG.error("纯文本邮件发送时发生异常!", e);
        }
    }

}

package com.maoxs.email.strategy.impl;

import com.maoxs.email.entity.Mail;
import com.maoxs.email.strategy.MailStrategy;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.util.Locale;
import java.util.Map;

/**
 * @Description: 自定义模板格式发送邮件
 *
 * @author fulin
 * @Project
 */
@Component
public class TemplateMailStrategy implements MailStrategy {
    private static final Logger LOG = LogManager.getLogger("bizLog");

    @Autowired
    private JavaMailSender javaMailSender;
    @Autowired
    private TemplateEngine templateEngine;

    @Override
    public void sendMail(String from, Mail mail) {
        final Context ctx = new Context(new Locale(""));
        if (null != mail.getMaps() && mail.getMaps().size() != 0) {
            for (Map.Entry<String, Object> entry : mail.getMaps().entrySet()) {
                ctx.setVariable(entry.getKey(), entry.getValue());
            }
        }
        final String htmlContent = templateEngine.process(mail.getTemplateName(), ctx);
        final MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        final MimeMessageHelper message = new MimeMessageHelper(mimeMessage, "UTF-8");
        try {
            message.setFrom(from);
            message.setTo(mail.getTo());
            message.setSubject(mail.getTitle());
            message.setText(htmlContent, true);
            javaMailSender.send(mimeMessage);
            LOG.info("模板邮件已经发送{}。", mail.getTo());
        } catch (MessagingException e) {
            e.printStackTrace();
            LOG.error("发送模板邮件【{}】时发生异常!", mail.getTemplateName());
        }
    }
}

然后就是邮件的发送类

package com.maoxs.email.biz;

import com.maoxs.email.entity.Mail;
import com.maoxs.email.enums.MailContentTypeEnum;
import com.maoxs.email.factory.MailFactory;
import com.maoxs.email.strategy.MailStrategy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * @Description: 邮件发送类
 *
 * @author fulin
 * @Project
 **/
@Component
public class MailBiz {
    @Autowired
    private Map<String, MailStrategy> mailStrategy;

    @Value("${spring.mail.username}")
    private String from;

    /** 邮件实体 */
    private Mail mail = new Mail();

    /**
     * 设置邮件标题
     *
     * @param title:邮件标题
     * @return
     */
    public MailBiz title(String title) {
        mail.setTitle(title);
        return this;
    }

    /**
     * 设置邮件内容
     *
     * @param content:内容
     * @return
     */
    public MailBiz content(String content) {
        mail.setContent(content);
        return this;
    }

    /**
     * 设置邮件格式
     *
     * @param typeEnum:邮件格式
     * @return
     */
    public MailBiz contentType(MailContentTypeEnum typeEnum) {
        mail.setContentType(typeEnum.value());
        return this;
    }

    /**
     * 设置请求目标邮件地址
     *
     * @param to:请求目标邮件地址
     * @return
     */
    public MailBiz to(String to) {
        mail.setTo(to);
        return this;
    }

    /**
     * 设置模板名称
     *
     * @param templateName
     * @return
     */
    public MailBiz templateName(String templateName) {
        mail.setTemplateName(templateName);
        return this;
    }

    /**
     * 模板发送的变量
     *
     * @param maps:maps
     * @return
     */
    public MailBiz maps(Map<String, Object> maps) {
        mail.setMaps(maps);
        return this;
    }

    /**
     * 执行发送邮件
     */
    public void send() {
        String key = MailFactory.getInstance().get(mail.getContentType());
        this.mailStrategy.get(key).sendMail(from, mail);
    }
}

然后呢就封装完毕了 在发送类里使用了对象级联的方式,使其调用更方便如果使用的是freemarker

这边我也提供了发送方式,建议大家自己扩展。

package com.maoxs.email.strategy.impl;

import com.maoxs.email.entity.Mail;
import com.maoxs.email.strategy.MailStrategy;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.IOException;

@Component
public class FreemarkerMailStrategy implements MailStrategy {
    private static final Logger LOG = LogManager.getLogger("bizLog");

    @Autowired
    private Configuration configuration;
    @Autowired
    private JavaMailSender javaMailSender;

    @Override
    public void sendMail(String from, Mail mail) {
        try {
            final Template t = configuration.getTemplate(mail.getTemplateName());
            final String htmlContent = FreeMarkerTemplateUtils.processTemplateIntoString(t, mail.getMaps());
            final MimeMessage mimeMessage = javaMailSender.createMimeMessage();
            final MimeMessageHelper message = new MimeMessageHelper(mimeMessage, "UTF-8");
            message.setFrom(from);
            message.setTo(mail.getTo());
            message.setSubject(mail.getTitle());
            message.setText(htmlContent, true);
            javaMailSender.send(mimeMessage);
            LOG.info("FreeMarker模板邮件已经发送{}。", mail.getTo());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException e) {
            e.printStackTrace();
        } catch (MessagingException e) {
            e.printStackTrace();
            LOG.error("FreeMarker发送模板邮件【{}】时发生异常!", mail.getTemplateName());
        }
    }
}

具体怎么使用呢 来看下测试类

package com;

import com.maoxs.email.biz.MailBiz;
import com.maoxs.email.enums.MailContentTypeEnum;
import com.mail.MailService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@RunWith(SpringRunner.class)
@SpringBootTest
public class TestApplicationTests {
    @Autowired
    private MailBiz mailBiz;

    @Test
    public void sendMail() {
        mailBiz
        .contentType(MailContentTypeEnum.HTML)
        .title("测试")
        .to("[email protected]")
        .content("<h1>测试content</h1>")
        .send();
    }


    @Test
    public void sendMail2() {
        Map<String, Object> params = new HashMap<>();
        params.put("username", "昴先生");
        params.put("methodName", "???");
        params.put("errorMessage", "出错了唉");
        params.put("occurredTime", new Date());
        mailBiz
                .contentType(MailContentTypeEnum.TEMPLATE)
                .title("测试")
                .to("[email protected]")
                .content("测试content")
                .templateName("Test")
                .maps(params)
                .send();
    }
}

然后呢这是邮件 thy的 由于上面提供了freemarker的发送方式,建议大家自己扩展

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <title>Hello World</title>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css"
          th:href="@{https://cdn.bootcss.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css}"/>
</head>
<style type="text/css">
    .full-screen {
        height: fit-content;
        width: fit-content;
    }

    .fixed-page {
        overflow-x: scroll;
        overflow-y: scroll;
    }

    .container {
        width: 100%;
        padding-right: 15px;
        padding-left: 15px;
        margin-right: auto;
        margin-left: auto
    }

    .jumbotron {
        padding: 2rem 1rem;
        margin-bottom: 2rem;
        background-color: #e9ecef;
        border-radius: .3rem
    }

    .jumbotron-fluid {
        padding-right: 0;
        padding-left: 0;
        border-radius: 0
    }

</style>
<body class="fixed-page">
<table width="100%" border="0" align="center" cellpadding="0" cellspacing="0" bgcolor="#ffffff"
       style="font-family:'Microsoft YaHei';">
    <div class="jumbotron jumbotron-fluid full-screen">
        <div class="container  full-screen">
            <img class="c-img c-img6" src="https://ss1.baidu.com/6ONXsjip0QIZ8tyhnq/it/u=2222976400,3502441702&amp;fm=58&amp;bpow=440&amp;bpoh=440">
            <img class="currentImg" id="currentImg" onload="alog &amp;&amp; alog('speed.set', 'c_firstPageComplete', +new Date); alog.fire &amp;&amp; alog.fire('mark');" src="https://timgsa.baidu.com/timg?image&amp;quality=80&amp;size=b9999_10000&amp;sec=1532597177454&amp;di=aec784f189c38b207ee88ea296f2457f&amp;imgtype=0&amp;src=http%3A%2F%2Fimg5.duitang.com%2Fuploads%2Fblog%2F201308%2F13%2F20130813185613_T4nxf.thumb.700_0.jpeg" data-ispreload="0" width="485.91370558376" height="547" style="top: 0px; left: 382px; width: 318.02px; height: 358px; cursor: pointer;" log-rightclick="p=5.102" title="点击查看源网页">
            <img class="currentImg" id="currentImg" onload="alog &amp;&amp; alog('speed.set', 'c_firstPageComplete', +new Date); alog.fire &amp;&amp; alog.fire('mark');" src="https://timgsa.baidu.com/timg?image&amp;quality=80&amp;size=b9999_10000&amp;sec=1532597216973&amp;di=5a1b48da42304a2dd63ec9697084bb11&amp;imgtype=0&amp;src=http%3A%2F%2Fi2.hdslb.com%2Fbfs%2Farchive%2Fb55830fe8fb1d3221b3494442b0b5c1902c6ef3a.jpg" width="288.71287128713" height="162" style="top: 48px; left: 397px; width: 288.713px; height: 162px; cursor: pointer;" log-rightclick="p=5.102" title="点击查看源网页">
            <img class="currentImg" id="currentImg" onload="alog &amp;&amp; alog('speed.set', 'c_firstPageComplete', +new Date); alog.fire &amp;&amp; alog.fire('mark');" src="https://timgsa.baidu.com/timg?image&amp;quality=80&amp;size=b9999_10000&amp;sec=1532597216973&amp;di=5d72892a3193c4462b45d87f6a5370b2&amp;imgtype=0&amp;src=http%3A%2F%2Fi2.hdslb.com%2Fbfs%2Fface%2Faff582421bd0e8331255cb92622328d19616e2c0.jpg" width="288.71287128713" height="162" style="top: 29px; left: 392px; width: 300px; height: 300px; cursor: pointer; display: block;" log-rightclick="p=5.102" title="点击查看源网页">
            <h3>Hi,
                <span th:text="${username}">Developer</span>
            </h3>
            <p>There is an exception occurred in method
                <code style="color: #d57e13;"><span th:text="${methodName}">methodName</span></code>,
                the error message is :
            </p>
            <div>
            <pre>
                <code style="font-family: 'Source Code Pro';">
                    <span th:text="${errorMessage}">Error Message</span>
                </code>
            </pre>
            </div>
            <span th:text="${occurredTime}">occurredTime</span>
        </div>

    </div>
</table>
</body>
</html>

然后呢我们跑去邮箱里去看看

在这里插入图片描述

okokok,完事,这边还有一个多邮件轮训发送没有扩展,有时间在扩展

本博文是基于springboot2.x 如果有什么不对的请在下方留言。

相关连接:

个人博客地址 : www.fulinlin.com

csdn博客地址:https://blog.csdn.net/qq_32867467

集合源码地址 : https://gitee.com/Maoxs/springboot-test

注:如果不对联系本宝宝及时改正~~

猜你喜欢

转载自blog.csdn.net/qq_32867467/article/details/82944543