SpringBoot–自定义域名发送邮件

前言

最近的一个小项目用到了邮件发送的功能,由于自己实现一套 SMTP 比较复杂,于是借助第三方如 QQ 邮箱或网易邮箱或 Gmail 等邮件系统实现此功能,在开发过程中我使用了网易邮箱,并申请了免费的网易企业邮箱实现自定义域名发送邮件。

邮件协议

SMTP

SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议是一个在互联网上传输电子邮件的标准。

POP

POP(Post Office Protocol)即邮局协议是TCP/IP协议族中的一员。此协议主要用于支持使用客户端远程管理在服务器上的电子邮件。最新版本为POP3,全名“Post Office Protocol - Version 3”,而提供了SSL加密的POP3协议被称为POP3S。

IMAP

IMAP(Internet Message Access Protocol)即因特网信息访问协议是一个应用层协议,用来从本地邮件客户端(如Microsoft Outlook、Outlook Express、Foxmail、Mozilla Thunderbird)访问远程服务器上的邮件。

那么这三个协议有什么关系呢?

简单地说,SMTP 管 , POP3/IMAP 管

举个例子,你坐在电脑边用 mail client 写完邮件,点击”发送”。这时你的 mail client 会发消息给邮件服务器上的 SMTP service。这时有两种情况:

  1. 如果邮件的收信人也是处于同一个 domain,比如从 163.com 发送给163的邮箱,SMTP service 只需要转给 local 的 POP3 Service 即可。
  2. 如果邮件收信人是另外的 domain,比如 163.com 发送给 sina.com,SMTP service 需要通过询问 DNS,找到属于 sina 的 SMTP service 的 host。

SMTP service 收到邮件后转给负责接收邮件的 POP3 service

POP3 service 和 IMAP 的区别主要是:

  • POP3 是比较老的 protocol,主要为了解决本地机器和远程邮件服务器链接的问题,每次邮件会download 到本地机器,然后从远程邮件服务器上删掉(当然特殊config除外),然后进行本地编辑。这样的问题是如果从多个终端链接服务器,只有第一个下载的能看到,现在pop4正在讨论中。
  • IMAP 是比较新的(好吧,好像也是80年代的产物)protocol,可以将邮件分文件夹整理,然后这些信息也存在远程的邮件服务器上,读取邮件后,服务器上不删除。原理上 IMAP 应该是相当于 oneline 编辑,但现在的 mail client 基本都有在本地存 copy 的功能。

摘自知乎

作者:diligentTiger
链接:https://www.zhihu.com/question/24605584/answer/29039357

Spring 中相关的类

MailSender 是邮件发送相关的接口

1
2
3
4
5
public interface MailSender {
void send(SimpleMailMessage var1) throws MailException;

void send(SimpleMailMessage... var1) throws MailException;
}

MailMessage 是消息相关的接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public interface MailMessage {
void setFrom(String var1) throws MailParseException;

void setReplyTo(String var1) throws MailParseException;

void setTo(String var1) throws MailParseException;

void setTo(String... var1) throws MailParseException;

void setCc(String var1) throws MailParseException;

void setCc(String... var1) throws MailParseException;

void setBcc(String var1) throws MailParseException;

void setBcc(String... var1) throws MailParseException;

void setSentDate(Date var1) throws MailParseException;

void setSubject(String var1) throws MailParseException;

void setText(String var1) throws MailParseException;
}

在实际的使用过程中主要使用了 JavaMailSenderImpl 类,它实现了 JavaMailSender 接口,JavaMailSender接口继承自 MailSender,其次是 MimeMessageHelper 帮助我们构建邮件消息。

实现

开启POP3/SMTP/IMAP服务

在网易邮箱,设置——POP3/SMTP/IMAP 中开启相关的服务。

image.png

开通完服务之后获得客户端授权码,在配置文件中会使用。

image.png

个人邮箱配置

在 SpringBoot 的配置文件 application.properties 中添加以下配置

1
2
3
4
5
6
7
8
9
10
11
12
# 网易个人邮箱
spring.mail.host=smtp.163.com
spring.mail.port=465
spring.mail.username=你的邮箱
# 邮箱的授权码
spring.mail.password=你自己的授权码
spring.mail.properties.mail.smtp.ssl.enable=true
spring.mail.properties.mail.imap.ssl.socketFactory.fallback=false
spring.mail.properties.mail.smtp.ssl.socketFactory.class=javax.net.ssl.SSLSocketFactory
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true

发送简单邮件

1
2
3
4
5
6
7
8
9
10
public void sendMessage() throws MessagingException {
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper helper;
helper = new MimeMessageHelper(message, true, "utf-8");
helper.setFrom("你的邮箱");
helper.setTo("邮件人@qq.com");
helper.setSubject("九点下班");
helper.setText("微信搜一搜");
javaMailSender.send(message);
}

可以看到在 QQ 邮箱中正常收到了邮件

image.png

发送 html 格式的邮件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public void sendMessage() throws MessagingException {
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper helper;
helper = new MimeMessageHelper(message, true, "utf-8");
helper.setFrom("你的邮箱");
helper.setTo("邮件人@qq.com");
helper.setSubject("九点下班");

helper.setText("<html>\n" +
"\n" +
"<body>\n" +
" <h4>你好:</h4>\n" +
" 欢迎关注九点下班\n" +
"</br>\n" +
" <img src=\"https://i.loli.net/2020/03/19/UYw3raP1NnD7Xhj.png\" width=\"20%\">\n" +
"</body>\n" +
"\n" +
"</html>", true); //注意这里要设置为true
javaMailSender.send(message);
}

收到邮件格式如下:

image.png

除以上格式外,还可以添加附件、设置抄送、设置邮件模版等等。

企业邮箱配置

申请网易企业邮箱

网易企业邮箱http://ym.163.com/ 注册账号

image.png

填完以上信息,在 MX 记录验证阶段,需要域名解析记录加一条,以下是我在阿里云域名解析的配置

image.png

完成注册并验证通过之后就可以使用了,配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 网易企业邮箱
spring.mail.host=smtp.ym.163.com
spring.mail.port=465
# 你注册的企业邮箱
spring.mail.username=service@democome.com
# 注意是企业邮箱的密码,企业邮箱没有授权码
spring.mail.password=企业邮箱的密码
spring.mail.properties.mail.smtp.ssl.enable=true
spring.mail.properties.mail.imap.ssl.socketFactory.fallback=false
spring.mail.properties.mail.smtp.ssl.socketFactory.class=javax.net.ssl.SSLSocketFactory
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true

以上配置完成后,发送消息的代码基本不变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public void sendMessage() throws MessagingException {
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper helper;
helper = new MimeMessageHelper(message, true, "utf-8");
helper.setFrom("service@democome.com");
helper.setTo("邮件人@qq.com");
helper.setSubject("九点下班");

helper.setText("<html>\n" +
"\n" +
"<body>\n" +
" <h4>你好:</h4>\n" +
" 欢迎关注九点下班\n" +
"</br>\n" +
" <img src=\"https://i.loli.net/2020/03/19/UYw3raP1NnD7Xhj.png\" width=\"20%\">\n" +
"</body>\n" +
"\n" +
"</html>", true);
javaMailSender.send(message);
}

可以看到已经是域名邮箱了

image.png

其他

如果你在 macOS 使用的过程中出现 Connection refused 异常需要开启 postfix

1
2
sudo postfix status
postfix/postfix-script: the Postfix mail system is running: PID: 19508

如果没有启动需要执行

1
sudo postfix start

参考资源

STMPhttps://zh.wikipedia.org/wiki/简单邮件传输协议

IMAPhttps://zh.wikipedia.org/wiki/因特网信息访问协议

POPhttps://zh.wikipedia.org/wiki/郵局協定

更多推荐

Android开发者如何写服务端代码

Nginx 入门实战

macOS使用iTerm2配置ssh连接

了解更多,请关注公众号:九点下班