目录

  • 一、邮件协议

    • 关于数据传输
  • 二、SpringBoot 与邮件
    • A. 添加依赖
    • B. 配置文件
    • C. 发送文本邮件
    • D.发送附件
    • E. 发送Html邮件
  • 三、CID与图片
  • 参考文档

一、邮件协议

在谈谈代码之前,先来了解下邮件的基本协议。

电子邮件协议是基于TCP层定义的,主要有下面几个:

  • SMTP协议

SMTP 是 Simple Mail Transfer Protocol 的简称,即简单邮件传输协议,是发送协议。
它定义了一组从源地址到目的地址传输邮件的规范,并支持在传送过程中通过不同网络主机实现中转及传送。

  • POP3协议

POP3是 Post Office Protocol 3 的简称,属于接收协议,POP3是即POP(邮局协议)的第3个版本,也是因特网电子邮件的第一个离线协议。
它规定了终端如何接入远程的邮件服务器并下载电子邮件。

  • IMAP协议

IMAP的全称是 Internet Mail Access Protocol,即交互式邮件访问协议,是一种支持同步接收的协议。
该协议由斯坦福大学在1986年研发,目前是最流行的邮件收取功能协议。
开启IMAP功能之后,电子邮件客户端可同步接收服务端的邮件,无论在客户端还是服务端上的操作都会反馈到另一方,比如删除、标记等;
此外IMAP还支持只对选中的部分邮件进行收取,这在POP协议上是做不到的。

关于数据传输

大多人都知道,电子邮件的传输采用了Base64编码对邮件内容进行包装,这是一种基于64个可打印字符来表示二进制数据的方法。

如上是Base64编码的字符映射表,64个字符可对应6个bit位。
一个字节是8个bit位,那么3个字节刚好需要4个Base64的字符来表示,而3个字节(4个字符)也是Base64编码的最小单位,
在编码过程中对于不足的部分采用"="号来补齐,如下:

另外一个需要知道的协议是MIME(Multipurpose Internet Mail Extensions),即多用途互联网邮件扩展
在前面介绍SpringBoot-MiMe类型处理的文章中提到过,这是一种用来定义文档性质及格式的标准。
一段内容,是文本、图片、音频,还是二进制,都通过MIME类型来进行声明和解析。

常见的MIME

内容 后缀 MIME
普通文本 .txt text/plain
RTF文本 .rtf application/rtf
PDF文档 .pdf application/pdf
Word文件 .word application/msword
PNG图像 .png image/png
GIF图形 .gif image/gif
JPEG图形 .jpg image/jpeg

二、SpringBoot 与邮件

SpringBoot 是一个脚手架,邮件功能其实是通过 JavaMail来实现的。
JavaMail是Java实现邮件收发功能的标准组件,其提供了一组简便的API来实现邮件处理,同时也支持各类认证协议。
这里不对JavaMail 做展开介绍,由于有了SpringBoot,实现一个邮件发送功能变得非常简单。

下面将展示几个例子,包括:

  • 使用springboot 发送文本邮件;
  • 如何发送带附件的邮件;
  • 如何使用 thymeleaf 发送模板邮件,支持HTML格式。

A. 添加依赖

spring-boot-starter-mail是一个封装了邮件功能的组件,依赖如下:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId><version>${spring-boot.version}</version>
</dependency>

B. 配置文件

按下面的配置设置SMTP服务器、用户密码、及收发人信息

//smtp 服务器
spring.mail.host=smtp.qq.com
//smtp 端口
spring.mail.port=25
//发送用户名
spring.mail.username=xxx
//发送密码
spring.mail.password=xxx//收发人
spring.mail.from=xxx@qq.com
spring.mail.to=xxx@qq.com//启用鉴权
spring.mail.properties.mail.smtp.auth=true
//不使用tls
spring.mail.properties.mail.smtp.starttls.enable=false
spring.mail.properties.mail.smtp.starttls.required=false

C. 发送文本邮件

编写下面的代码,实现简单的文本发送:

@Service
public class SimpleMailSender implements CommandLineRunner {private static final Logger logger = LoggerFactory.getLogger(SimpleMailSender.class);@Autowiredprivate JavaMailSender mailSender;@Autowiredprivate Environment environment;private void sendText() {String from = environment.getProperty("spring.mail.from");String to = environment.getProperty("spring.mail.to");SimpleMailMessage msg = new SimpleMailMessage();msg.setFrom(from);msg.setTo(to);msg.setSubject("first email from yourself");msg.setText("hello world!");this.mailSender.send(msg);logger.info("send text done");}@Overridepublic void run(String... args) throws Exception {sendText();}

JavaMailSender、SimpleMailMessage 都是对JavaMail接口的封装,目的仅在于提供更简易的使用方式。
SimpleMailSender 继承了CommandLineRunner ,在SpringBoot启动时会触发sendText方法,
此时尝试启动SpringBoot应用,可以看到日志输出:

o.h.s.m.SimpleMailSender                 : send text done

此时检查收件箱,便可以看到对应的文本邮件。

D.发送附件

基于前面发送文本的例子,实现附件发送的代码如下:

private void sendAttachment() throws MessagingException {String from = environment.getProperty("spring.mail.from");String to = environment.getProperty("spring.mail.to");// 使用Mime消息体MimeMessage message = mailSender.createMimeMessage();// multipart参数为true,表示需要发送附件MimeMessageHelper helper = new MimeMessageHelper(message, true);helper.setFrom(from);helper.setTo(to);helper.setSubject("first file from yourself");helper.setText("check the file");//指定系统文件File file = new File("D:\\temp\\attachment.xlsx");FileSystemResource resource = new FileSystemResource(file);helper.addAttachment(file.getName(), resource);mailSender.send(message);logger.info("send attachment done");}

同样,启动应用并发送邮件后,在收件邮件中获得了附件:

E. 发送Html邮件

许多邮件都包含了丰富的文本样式,这是通过HTML邮件实现的。
对于此类场景的通用做法是使用模板来发送,应用程序只关注模型数据的传参即可。

SpringBoot 可利用 thymeleaf 页面引擎来实现HTML的模板,首先需要引入thymeleaf

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId><version>${spring-boot.version}</version>
</dependency>

接着新建一个模板,
/src/main/resources/templates/mail/template.html

<html>
<body><h4 th:text="|Hi, ${customer}, these're your pets|"></h4>
<hr></hr><table><tr><th>name</th><th>type</th><th>age</th></tr><tr th:each="p : ${pets}"><td th:text="${p.name}"></td><td th:text="${p.type}"></td><td th:text="${p.age}"></td></tr>
</table></body>
</html>

上面的模板中是一个宠物列表的页面(表格),宠物模型定义:

public static class Pet {private String name;private String type;private int age;public Pet(String name, String type, int age) {super();this.name = name;this.type = type;this.age = age;}
...

我们在发送邮件时,需要注入宠物列表数据
代码如下:

@Service
public class SimpleMailSender {/*** 日志工具*/private static final Logger logger = LoggerFactory.getLogger(MailService.class);@Autowiredprivate JavaMailSender mailSender;@Autowiredprivate TemplateEngine templateEngine;@Autowiredprivate Environment environment;private void sendTemplateMail() throws MessagingException {String from = environment.getProperty("spring.mail.from");String to = environment.getProperty("spring.mail.to");// 使用Mime消息体MimeMessage message = mailSender.createMimeMessage();MimeMessageHelper helper = new MimeMessageHelper(message, true);helper.setFrom(from);helper.setTo(to);helper.setSubject("first html report from yourself");// 根据模板、变量生成内容// 数据模型List<Pet> pets = new ArrayList<Pet>();pets.add(new Pet("Polly", "Bird", 2));pets.add(new Pet("Tom", "Cat", 5));pets.add(new Pet("Badboy", "Dog", 3));Context context = new Context();context.setVariable("customer", "LiLei");context.setVariable("pets", pets);String text = templateEngine.process("mail/template", context);helper.setText(text, true);mailSender.send(message);}}

启动应用,发送邮件后的效果:

三、CID与图片

使用 thymeleaf 可以快速的制作出一个Html模板,
有时候我们需要在邮件中显示一张图片,怎么办呢?

  1. 使用img标签,并指定一个在线的图片;
    此方案比较通用,应该说大多数在线平台都采用这种做法,但这么做的前提是需要有一个统一的图片存储及访问系统。

  2. 使用 Base64编码,在页面中嵌入编码后的内容:

<img width="100" height="100" src="https://img-blog.csdnimg.cn/2022010710444627788.jpg" />

该方案非通用,在实测中发现Outlook 无法展示这类标签,客户端并未支持。
下面列举了支持内嵌图片展示的一些邮件客户端:

  1. 采用CID 方案,图片作为内嵌资源

CID就是ContentID,是一种在MIME消息体中用于定义并引用内容块的机制。
RFC2392 对这个进行了定义。

一个带CID的消息体如下所示:

--boundary-example 1
Content-Type: Text/HTML; charset=US-ASCIIto the other body part, for example through a statement such as:
<IMG SRC="cid:foo4*foo1@bar.net" ALT="IETF logo">--boundary-example-1Content-ID: <foo4*foo1@bar.net>
Content-Type: IMAGE/GIF
Content-Transfer-Encoding: BASE64R0lGODlhGAGgAPEAAP/ZRaCgoAAAACH+PUNvcHlyaWdodCAoQykgMTk5
NSBJRVRGLiBVbmF1dGhvcml6ZWQgZHVwbGljYXRpb24gcHJvaGliaXRlZC4A
etc...

那么,使用CID内嵌图片的做法如下:

步骤一

在发送邮件时指定带 CID 的 Resource

        String text = templateEngine.process("mail/template", context);helper.setText(text, true);helper.addInline("soft", new FileSystemResource("D:/temp/soft.png"));mailSender.send(message);

步骤二
步骤:模板中引用对应的CID,如下:

<img src="cid:soft"></img>

最终,发送邮件可支持图片的展示,如下

码云同步代码

参考文档

spring.io-mail
springboot-mail.properties
send-a-base64-image-in-html-email

欢迎继续关注"美码师的补习系列-springboot篇" ,期待更多精彩内容^-^

作者:美码师

补习系列(12)-springboot 与邮件发送相关推荐

  1. Java技术:SpringBoot实现邮件发送功能

    邮件发送功能基本是每个完整业务系统要集成的功能之一,今天小编给大家介绍一下SpringBoot实现邮件发送功能,希望对大家能有所帮助! 今天主要给大家分享简单邮件发送.HTML邮件发送.包含附件的邮件 ...

  2. Springboot实现邮件发送(2020最新版)

    在正式讲解如何用Springboot发送邮件之前,先普及四个容易忽视的概念(好多教程直接忽略介绍): 1.邮件协议,简单理解下:小明给小红发了一封邮件,指的是小明登录邮箱客户端(比如通过浏览器登录QQ ...

  3. 补习系列(15)-springboot 分布式会话原理

    目录 一.背景 二.SpringBoot 分布式会话 三.样例程序 四.原理进阶 A. 序列化 B. 会话代理 C. 数据老化 小结 一.背景 在 补习系列(3)-springboot 几种scope ...

  4. 补习系列(14)-springboot redis 整合-数据读写

    目录 一.简介 二.SpringBoot Redis 读写 A. 引入 spring-data-redis B. 序列化 C. 读写样例 三.方法级缓存 四.连接池 小结 一.简介 在 补习系列(A3 ...

  5. 使用SpringBoot实现邮件发送

    邮件发送是一个非常常见的功能,注册时的身份认证.重要通知发送等都会用到邮件发送.Sun公司提供了JavaMail用来实现邮件发送,但是配置烦琐,Spring中提供了JavaMailSender用来简化 ...

  6. 补习系列(2)-springboot mime类型处理

    目标 了解http常见的mime类型定义: 如何使用springboot 处理json请求及响应: 如何使用springboot 处理 xml请求及响应: http参数的获取及文件上传下载: 如何获得 ...

  7. 补习系列(13)-springboot redis 与发布订阅

    目录 一.订阅发布 常见应用 二.Redis 与订阅发布 三.SpringBoot 与订阅发布 A. 消息模型 B. 序列化 C. 发布消息 D. 接收消息 小结 一.订阅发布 订阅发布是一种常见的设 ...

  8. 补习系列(10)-springboot 之配置读取

    目录 简介 一.配置样例 二.如何注入配置 1. 缺省配置文件 2. 使用注解 3. 启动参数 还有.. 三.如何读取配置 @Value 注解 Environment 接口 @Configuratio ...

  9. 补习系列(9)-springboot 定时器,你用对了吗

    目录 简介 一.应用启动任务 二.JDK 自带调度线程池 三.@Scheduled 定制 @Scheduled 线程池 四.@Async 定制 @Async 线程池 小结 简介 大多数的应用程序都离不 ...

最新文章

  1. 大连学业水平考试计算机,2016年大连市普通高中学生学业水平考试模拟题(一)
  2. 【ZOJ - 4029】Now Loading!!!(整除分块,思维,二分,前缀和)
  3. 如何运用模板之家做html,Flask框架如何使用HTML模板
  4. java内存模型(netty权威指南)
  5. SVN 更新发生冲突各选项含义
  6. iOS开发之TableView去掉单个cell的间隔线和去掉全部间隔线和去掉tableView多余的间隔线
  7. VS2010下编译mp4v2及在项目中的使用
  8. windows 本地搭建git仓库_windows局域网搭建本地git代码版本管理仓库
  9. css 全文字体大小,CSS 字体大小
  10. IMU与Gyro及其它相关
  11. 支付宝崩了登上微博热搜
  12. Ubuntu下使用OpenCV显示中文
  13. python pexels_从零开始学习python爬虫方法,从安装到语法基础(附赠资料)
  14. android用户苹果手表,Android分析苹果手表成功原因
  15. 2022-2028全球及中国先进LTE测试设备行业研究及十四五规划分析报告
  16. 在GSYVideoPlayer中实现VLC 内核
  17. C#,背包问题(Knapsack Problem)贪心算法的源代码
  18. openGauss DBMind亮相VLDB2021,展示数据库自动驾驶平台
  19. 分布式交易事务_交易基础和分布式交易
  20. 防范网络陷阱与计算机病毒教学设计,粤教版信息技术第二册上第6课防范网络陷阱与计算机病毒教学设计(1).doc...

热门文章

  1. cent os mysql图形界面_cent os 6.4安装使用mysql
  2. mysql dump 二进制_mysqldump+二进制日志备份恢复
  3. android 删除wifi文件在哪里设置,如何删除无线终端的无线配置文件
  4. java半解释半编译_编译型语言、解释型语言、半编译半解释型语言
  5. python内建函数有哪些_Python内建函数大全(一)
  6. 一般微型计算机有几十条,计算机单选题.doc
  7. 并发编程总结一,进程
  8. webstorm 设置js或者html文件自动缩进为4个空格不生效
  9. HDU5212 CODE【莫比乌斯函数】
  10. C# Wpf异步修改UI,多线程修改UI(二)