目录

一、邮件协议

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

电子邮件协议是基于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=
//发送用户名
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); @Autowired
private JavaMailSender mailSender; @Autowired
private 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");
} @Override
public 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); @Autowired
private JavaMailSender mailSender; @Autowired
private TemplateEngine templateEngine; @Autowired
private 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", ));
pets.add(new Pet("Tom", "Cat", ));
pets.add(new Pet("Badboy", "Dog", )); 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="" height="" src="data:image/jpg;base64,/9dxxFEF8fEkqAAgAAAAL===" />

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

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

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

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

 --boundary-example
Content-Type: Text/HTML; charset=US-ASCII to the other body part, for example through a statement such as:
<IMG SRC="cid:foo4*foo1@bar.net" ALT="IETF logo"> --boundary-example- Content-ID: <foo4*foo1@bar.net>
Content-Type: IMAGE/GIF
Content-Transfer-Encoding: BASE64 R0lGODlhGAGgAPEAAP/////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篇" ,期待更多精彩内容^-^

作者:美码师

HDC.Cloud 华为开发者大会2020 即将于2020年2月11日-12日在深圳举办,是一线开发者学习实践鲲鹏通用计算、昇腾AI计算、数据库、区块链、云原生、5G等ICT开放能力的最佳舞台。

欢迎报名参会

补习系列(12)-springboot 与邮件发送【华为云技术分享】的更多相关文章

  1. 补习系列(12)-springboot 与邮件发送

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

  2. 带着canvas去流浪系列之九 粒子动画【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

  3. 补习系列(17)-springboot mongodb 内嵌数据库【华为云技术分享】

    目录 简介 一.使用 flapdoodle.embed.mongo A. 引入依赖 B. 准备测试类 C. 完善配置 D. 启动测试 细节 二.使用Fongo A. 引入框架 B. 准备测试类 C.业 ...

  4. 【华为云技术分享】MongoDB经典故障系列五:sharding集群执行sh.stopBalancer()命令被卡住怎么办?

    [摘要] MongoDB sharding集群执行sh.stopBalancer()命令时被卡住怎么办?别慌,华为云数据库来给您支招,收下这份方案指南,让您分分钟远离被自建MongoDB数据库支配的恐 ...

  5. 华为云&#183;寻找黑马程序员#【代码重构之路】如何“消除”if/else【华为云技术分享】

    1. 背景 if/else是高级编程语言中最基础的功能,虽然 if/else 是必须的,但滥用 if/else,特别是各种大量的if/else嵌套,会对代码的可读性.可维护性造成很大伤害,对于阅读代码 ...

  6. Spring Boot 最流行的 16 条实践解读!【华为云技术分享】

    置顶:华为云618大促火热进行中,全场1折起,免费抽主机,消费满额送P30 Pro,点此抢购. Spring Boot是最流行的用于开发微服务的Java框架.在本文中,将与大家分享自2016年以来笔者 ...

  7. 不服跑个分:ARM鲲鹏云服务器实战评测——华为云鲲鹏KC1实例 vs. 阿里云G5实例【华为云技术分享】

    原文链接:https://m.ithome.com/html/444828.htm 今年一月份,华为正式发布了鲲鹏920数据中心高性能处理器,该处理器兼容ARM架构,采用7纳米制造,最高支持64核,主 ...

  8. 成为高手前必懂的TCP干货【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

  9. 【我的物联网成长记6】由浅入深了解NB-IoT【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

随机推荐

  1. SAP S4HANA 账户组的配置里'Int.Std.Grping'选项没勾选导致ABAP程序报错

    SAP S4HANA 账户组的配置里'Int.Std.Grping'选项没勾选导致ABAP程序报错 BP,试图创建一个新的vendor code, 角色是ZGM001, Grouping是G001, ...

  2. TP5 Request 请求对象【转】

    app\index\controller\Index.php <?php namespace app\index\controller; use think\Request; class Ind ...

  3. JSP 与Javabean 的交互技术

    JSP 与Javabean 的交互技术 JavaBean的属性可以是任意类型,并且一个JavaBean可以有多个属性.每个属性通常都需要具有相应的setter. getter方法,setter方法称为 ...

  4. tornado 文件上传

    服务端 def post(self, *args, **kwargs): # content_type # filename # body file_data=self.request.files i ...

  5. 其他综合-CentOS7 安装 Jumpserver 跳板机

    CentOS7 安装 Jumpserver 跳板机 1.实验描述 搭建 jumpserver 平台,实现有效的运维安全审计.完美做到事先防范,事中控制和事后溯源 2.实验环境 物理机系统:Window ...

  6. Java命令行传参

    目的: 在运行一个程序时候再传递给它消息,这就需要传递命令参数给main()函数实现:即main()方法可以传递数据 例: public class demo{ public static void ...

  7. devops 下测试组织管理面临的挑战及应对

    导读 先从引发的5个问题讲起,再简单回顾一下devops 简介和兴起背景 ,再从itest 测试管理团队的视角提出应对办法 DevOps后,测试面临的挑战        敏捷开发必然是迭代开发管理模式 ...

  8. google v8

    https://github.com/tongbai168/v8 https://iwebing.lofter.com/tag/chromium  编译动态库 gyp mylib.gyp --dept ...

  9. 201871010118-唐敬博《面向对象程序设计(java)》第十三周学习总结

    博文正文开头格式:(2分) 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.co ...

  10. djang项目中的疑问及解决办法(ValueError: Invalid model reference 'apps.user.User'. String model references must be of the form 'app_label.ModelName'.)

    这个问题其实就是apps.user.User这种用法是不对的,就在下面的模型中,我本来是绑定apps.user.User,但是试了一下,由于order和user是在同一个apps中,所以直接用user ...