[TOC]html
在谈谈代码以前,先来了解下邮件的基本协议。java
电子邮件协议是基于TCP层定义的,主要有下面几个:git
SMTP 是 Simple Mail Transfer Protocol 的简称,即简单邮件传输协议,是发送协议。 它定义了一组从源地址到目的地址传输邮件的规范,并支持在传送过程当中经过不一样网络主机实现中转及传送。github
POP3是 Post Office Protocol 3 的简称,属于接收协议,POP3是即POP(邮局协议)的第3个版本,也是因特网电子邮件的第一个离线协议。 它规定了终端如何接入远程的邮件服务器并下载电子邮件。spring
IMAP的全称是 Internet Mail Access Protocol,即交互式邮件访问协议,是一种支持同步接收的协议。 该协议由斯坦福大学在1986年研发,目前是最流行的邮件收取功能协议。 开启IMAP功能以后,电子邮件客户端可同步接收服务端的邮件,不管在客户端仍是服务端上的操做都会反馈到另外一方,好比删除、标记等; 此外IMAP还支持只对选中的部分邮件进行收取,这在POP协议上是作不到的。springboot
大多人都知道,电子邮件的传输采用了Base64编码对邮件内容进行包装,这是一种基于64个可打印字符来表示二进制数据的方法。服务器
如上是Base64编码的字符映射表,64个字符可对应6个bit位。 一个字节是8个bit位,那么3个字节恰好须要4个Base64的字符来表示,而3个字节(4个字符)也是Base64编码的最小单位, 在编码过程当中对于不足的部分采用"="号来补齐,以下:网络
另一个须要知道的协议是MIME(Multipurpose Internet Mail Extensions),即多用途互联网邮件扩展 在前面介绍SpringBoot-MiMe类型处理的文章中提到过,这是一种用来定义文档性质及格式的标准。 一段内容,是文本、图片、音频,仍是二进制,都经过MIME类型来进行声明和解析。并发
常见的MIMEapp
内容 | 后缀 | MIME |
---|---|---|
普通文本 | .txt | text/plain |
RTF文本 | .rtf | application/rtf |
PDF文档 | application/pdf | |
Word文件 | .word | application/msword |
PNG图像 | .png | image/png |
GIF图形 | .gif | image/gif |
JPEG图形 | .jpg | image/jpeg |
SpringBoot 是一个脚手架,邮件功能实际上是经过 JavaMail来实现的。 JavaMail是Java实现邮件收发功能的标准组件,其提供了一组简便的API来实现邮件处理,同时也支持各种认证协议。 这里不对JavaMail 作展开介绍,因为有了SpringBoot,实现一个邮件发送功能变得很是简单。
下面将展现几个例子,包括:
spring-boot-starter-mail是一个封装了邮件功能的组件,依赖以下:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> <version>${spring-boot.version}</version> </dependency>
按下面的配置设置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
编写下面的代码,实现简单的文本发送:
@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
此时检查收件箱,即可以看到对应的文本邮件。
基于前面发送文本的例子,实现附件发送的代码以下:
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"); }
一样,启动应用并发送邮件后,在收件邮件中得到了附件:
许多邮件都包含了丰富的文本样式,这是经过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", 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); } }
启动应用,发送邮件后的效果:
使用 thymeleaf 能够快速的制做出一个Html模板, 有时候咱们须要在邮件中显示一张图片,怎么办呢?
使用img标签,并指定一个在线的图片; 此方案比较通用,应该说大多数在线平台都采用这种作法,但这么作的前提是须要有一个统一的图片存储及访问系统。
使用 Base64编码,在页面中嵌入编码后的内容:
<img width="100" height="100" src="data:image/jpg;base64,/9dxxFEF8fEkqAAgAAAAL===" />
该方案非通用,在实测中发现Outlook 没法展现这类标签,客户端并未支持。 下面列举了支持内嵌图片展现的一些邮件客户端:
CID就是ContentID,是一种在MIME消息体中用于定义并引用内容块的机制。 RFC2392 对这个进行了定义。
一个带CID的消息体以下所示:
--boundary-example 1 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-1 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篇" ,期待更多精彩内容^-^