SpringBoot发送邮件

在小明经历的多个项目开发中,总会遇到消息通知的场景,比如某个广告主提交一个表单,我们要通知提醒运营人员及时查看。

消息通知的形式也有很多,比如:短信、邮件、app推送等,本文主要给大家描述一下邮件通知的形式,因为邮件相比较其他通知渠道更方便实用(免费),除了简单文本邮件(已经满足大多数情形),本文还会重点说一下集成Thymeleaf模版引擎,使用HTML的形式发送邮件,尽管HTML内容不是标准化的消息格式,但是许多邮件客户端至少支持标记语言的子集,这种方式相比较纯文本展现形式更加友好。

准备

一个普通再也普通不了的SpringBoot项目

简单文本发送

还是那句老话,在SpringBoot看来一切都是这么便捷。它已经集成邮件发送所必需的库模块,我们只需将以下依赖添加到pom.xml即可。

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-mail -->
<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布局中的图像,典型邮件附件和文本内容提供支持。

在以下部分中,我将向大家展示如何使用这些接口和类:

配置文件

下面举例163邮箱(最常用的):

spring:
  mail:
    host: smtp.163.com # 发件服务器
    username: coderxm@163.com # 账号
    password: xxxx # 密码(163需要授权第三方登录密码,请查看设置-客户端授权码密码开通)
    port: 465
    protocol: smtp
    default-encoding: utf-8
    # 下面这些配置大家不用深究,主要用于配置ssl
    properties:
      mail:
        imap:
          ssl:
            socketFactory:
              fallback: false
        smtp:
          auth: true
          ssl:
            enable: true
            socketFactory:
              class: com.fintech.modules.base.util.mail.MailSSLSocketFactory
          starttls:
            enable: true
            required: true
      test-connection: false

代码

service层

按照常见的代码结构,我们先定义一个发送邮件的接口,负责创建和发送新的邮件消息。

public interface EmailService {
    /**
     * 发送简单文本内容
     * @param to 发件人
     * @param subject 主题
     * @param text 内容
     */
    void sendSimpleMessage(String to,
                           String subject,
                           String text);
}

我们可以将一些常用的配置添加到yml配置文件当中

# 邮件配置
xiaoming:
  email:
    subject: "程序员小明"
    from: "coderxm@163.com"
    to: "xiaohong@163.com"
    # 抄送人:类型定义为数组,可以配置多个
    cc:
      - "xiaogang@163.com"

然后再通过注解注入到一个实体类中,这样很优雅,随用随取:

@Configuration
@ConfigurationProperties(prefix = "xiaoming.email")
@Data
public class EmailConfig {
    private String subject;
    private String from;
    private String to;
    private String[] cc;
}

我们再定义一个类去实现这个接口:

@Slf4j
@Service
public class EmailServiceImpl implements EmailService {
    @Autowired
    public JavaMailSender emailSender;
    @Autowired
    private EmailConfig emailConfig;

    @Override
    public void sendSimpleMessage(String to, String subject, String text) {
        try {
            SimpleMailMessage message = new SimpleMailMessage();
            message.setTo(to);
            message.setFrom("coderxm@163.com");
            message.setSubject(subject);
            message.setText(text);
            emailSender.send(message);
        } catch (MailException exception) {
            log.error(ExceptionUtil.stacktraceToString(exception));
        }
    }
}

测试

我们做一个简单的测试:简单的邮件是否能够发送成功。

@RunWith(SpringRunner.class)
@SpringBootTest
public class EmailTest {
    @Autowired
    private EmailService emailService;
    @Test
    public void testSimple(){
        emailService.sendSimpleMessage("ligang@163.com","XX篮球","你好,我想让周琦代言!");
    }
}

使用html作为模版发送邮件

正在洋洋得意(准备划水)的时候,我们的产品突然对我说,“用简单的文本发送邮件也太简陋了吧,显示不出来我们的产品档次”,然后给我了一个样式,让我以这种形式发送,好啊,什么都难不倒小明。我连忙找到我们的前端,(假装低三下四地)让她帮忙排一个页面给我(这个工作我实在不想做,一是懒,二是人家前端肯定比我专业啊),为了保密,我简化一下,大概是这样的:

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head></head>
<body>
    姓 名:<span th:text="${userName}"></span>
    性 别:<span th:text="${gender}"></span>
</body>
</html>

其实样式很好看的,但是这都不是重点,我们就以此作为模版举个例子,语法使用的都是thymeleaf,在此处就不再赘述,如果有想了解的可以去官网找。

增加Thymeleaf dependency

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

service层

创建另一个服务类,它主要通过读取html模版封装数据准备邮件内容,在我们之前的示例中,这是一个简单的文本消息。

@Service
public class MailContentBuilder {
    @Autowired
    private TemplateEngine templateEngine;

    @Autowired
    public MailContentBuilder(TemplateEngine templateEngine) {
        this.templateEngine = templateEngine;
    }

    public String build(Map<String, Object> message) {
        Context context = new Context();
        context.setVariables(message);
        return templateEngine.process("email", context);
    }
}

EmailService增加接口:

public interface EmailService {
    /**
     * 发送简单文本内容
     * @param to 发件人
     * @param subject 主题
     * @param text 内容
     */
    void sendSimpleMessage(String to,
                           String subject,
                           String text);

    /**
     * 传递多个变量,用于动态更换页面模版内容
     * @param emailInfoMap
     */
    void prepareAndSend(Map<String,Object> emailInfoMap);
}

EmailServiceImpl增加发送html形式邮件的实现方法:

@Override
public void prepareAndSend(Map<String,Object> emailInfoMap) {
    MimeMessagePreparator messagePreparator = mimeMessage -> {
        MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage);
        messageHelper.setFrom(emailConfig.getFrom());
        messageHelper.setTo(emailConfig.getTo());
        messageHelper.setCc(emailConfig.getCc());
        messageHelper.setSubject(emailConfig.getSubject());
//            messageHelper.setText(message);
        String content = mailContentBuilder.build(info);
        messageHelper.setText(content,true);
    };
    try {
        emailSender.send(messagePreparator);
    } catch (MailException e) {
        // runtime exception; compiler will not force you to handle it
    }
}

测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class EmailTest {
    @Autowired
    private EmailService emailService;
  
    @Test
    public void testHtml(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("userName","程序员小明");
        map.put("gender","男");
        emailService.prepareAndSend(map);
    }
}

整个Springboot发送邮件的场景已经复盘结束,大家如果有用到的速速体验吧!
欢迎关注微信公众号”程序员小明”,获取更多资源。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容