关于spring:Spring-Boot-发送邮件端口号大有玄机

46次阅读

共计 10380 个字符,预计需要花费 26 分钟才能阅读完成。

@[toc]
Spring Boot 发送邮件,松哥之前专门写过文章,这里就不啰嗦了。还不懂 Spring Boot 如何发送邮件的小伙伴,翻到本文后半局部,有介绍。

明天想和大家聊一下 SMTP 服务器的端口问题,这个也是一个小伙伴提的问题,SMTP 服务器有泛滥端口:25、465、587 各自间有什么区别?能够随便应用吗?心愿明天这篇文章能给你答案。

1. 什么是 SMTP

SMTP 代表简略邮件传输协定,简而言之,它是通过 Internet 发送电子邮件的过程。计算机端口是集体计算机连贯到网络并实现数据传输的形式。SMTP 端口是两者的组合:设计用于通过网络向其收件人发送电子邮件的端口。

下图展现了 SMTP 协定在邮件发送过程的作用:

当然,就像有多个计算机端口一样,能够应用的 SMTP 端口也有很多。

2. SMTP Port

2.1 25

1982 年,南加州大学向 Internet 工程工作组 (IETF) 提交了一份提案,即 Request For Comments (RFC) 821,将端口 25 建设为 Internet 电子邮件的默认传输通道。40 年过来了,现在咱们仍然能够应用 25 这个端口在两个邮件服务器之间传输邮件。

不过最后的设计没有思考平安问题,在 1998 年 12 月,R. Gellens 和 J. Klensin 提交了 RFC2476,在这个标准中,RFC 提议将传统的音讯提交和音讯中继概念离开,RFC 定义音讯提交应通过端口 587 进行(即咱们通过邮件客户端等工具提交邮件的时候,应该应用 587 端口),以确保新的策略和平安要求不会烦扰音讯中继端口 25 上的传统中继流量。

这么一拆分,端口 25 就次要用于 SMTP 中继,也就是将邮件从一个电子邮件服务器传输到另一个电子邮件服务器。

在大多数状况下,SMTP 电子邮件客户端(Foxmail、Microsoft Outlook、Mail、Thunderbird 等)不应应用 25 端口,以遏制垃圾邮件的数量,所以这个 25 端口和咱们集体应用的关系就不大。

2.2 587

这是默认的邮件提交端口,当用户提交一封电子邮件到邮件服务器时,能够应用该端口,咱们本人通过 Java 代码发送邮件,也能够应用该端口。

端口 587 与 TLS 加密相结合,可确保安全提交电子邮件并遵循 IETF 制订的指导方针。

2.3 465

那按理说咱们发送邮件的时候就该应用 587 端口呀,465 又是干嘛的?

IETF 从未将端口 465 公布为官网 SMTP 传输或提交端口,然而保护大部分外围互联网基础设施的 IANA 为 SMTPS 调配了端口 465。目标是为 SMTP 建设一个端口,以便应用安全套接字层 (SSL) 进行操作,这样使得邮件发送更加平安。

所以 465 和 587 其实都是为了邮件平安,然而两者的思路不一样,465 是 SSL,587 则是 TLS,SSL 和 TLS 有啥区别呢?这个就说来话长了,简略一句话就是:TLS(传输层平安)是更为平安的升级版 SSL,TLS 是 SSL 标准化后的产物。

按理说 465 应该被撤销,大家都用 587,然而因为 465 已经被 IANA 认定为无效,因而可能存在仅可能应用此端口连贯的遗留零碎,所以该端口并没有被废除,也能够应用。

2.4 小结

好啦,这就是这几个端口的区别。一般来说,咱们用 Spring Boot 发送邮件的时候,465 和 587 都能用,然而不倡议应用 25。另外在应用 465 或者 587 的时候,有的个别邮箱如 139 邮箱须要配置如下属性:

spring.mail.properties.mail.smtp.ssl.enable=true

3. 号外

可能还有小伙伴不懂 Spring Boot 邮件发送,再来回顾下。

邮件发送其实是一个十分常见的需要,用户注册,找回明码等中央,都会用到,应用 JavaSE 代码发送邮件,步骤还是挺繁琐的,Spring Boot 中对于邮件发送,提供了相干的自动化配置类,使得邮件发送变得非常容易,接下来咱们就来一探到底!看看应用 Spring Boot 发送邮件的 5 中姿态。

3.1 邮件根底

咱们常常会听到各种各样的邮件协定,比方 SMTP、POP3、IMAP,那么这些协定有什么作用,有什么区别?咱们先来讨论一下这个问题。

SMTP 是一个基于 TCP/IP 的应用层协定,江湖位置有点相似于 HTTP,SMTP 服务器默认监听的端口号为 25。看到这里,小伙伴们可能会想到既然 SMTP 协定是基于 TCP/IP 的应用层协定,那么我是不是也能够通过 Socket 发送一封邮件呢?答复是必定的。

生存中咱们投递一封邮件要通过如下几个步骤:

  1. 深圳的小王先将邮件投递到深圳的邮局
  2. 深圳的邮局将邮件运送到上海的邮局
  3. 上海的小张来邮局取邮件

这是一个缩减版的生存中邮件发送过程。这三个步骤能够别离对应咱们的邮件发送过程,假如从 aaa@qq.com 发送邮件到 111@163.com:

  1. aaa@qq.com 先将邮件投递到腾讯的邮件服务器
  2. 腾讯的邮件服务器将咱们的邮件投递到网易的邮件服务器
  3. 111@163.com 登录网易的邮件服务器查看邮件

邮件投递大抵就是这个过程,这个过程就波及到了多个协定,咱们来别离看一下。

SMTP 协定全称为 Simple Mail Transfer Protocol,译作简略邮件传输协定,它定义了邮件客户端软件与 SMTP 服务器之间,以及 SMTP 服务器与 SMTP 服务器之间的通信规定。

也就是说 aaa@qq.com 用户先将邮件投递到腾讯的 SMTP 服务器这个过程就应用了 SMTP 协定,而后腾讯的 SMTP 服务器将邮件投递到网易的 SMTP 服务器这个过程也仍然应用了 SMTP 协定,SMTP 服务器就是用来收邮件。

而 POP3 协定全称为 Post Office Protocol,译作邮局协定,它定义了邮件客户端与 POP3 服务器之间的通信规定,那么该协定在什么场景下会用到呢?当邮件达到网易的 SMTP 服务器之后,111@163.com 用户须要登录服务器查看邮件,这个时候就该协定就用上了:邮件服务商都会为每一个用户提供专门的邮件存储空间,SMTP 服务器收到邮件之后,就将邮件保留到相应用户的邮件存储空间中,如果用户要读取邮件,就须要通过邮件服务商的 POP3 邮件服务器来实现。

最初,可能也有小伙伴们据说过 IMAP 协定,这个协定是对 POP3 协定的扩大,性能更强,作用相似,这里不再赘述。

3.2 筹备工作

目前国内大部分的邮件服务商都不容许间接应用用户名 / 明码的形式来在代码中发送邮件,都是要先申请受权码,这里以 QQ 邮箱为例,向大家演示受权码的申请流程:首先咱们须要先登录 QQ 邮箱网页版,点击上方的设置按钮:

而后点击账户选项卡:

在账户选项卡中找到开启 POP3/SMTP 选项,如下:

点击开启,开启相干性能,开启过程须要手机号码验证,依照步骤操作即可,不赘述。开启胜利之后,即可获取一个受权码,将该号码保留好,一会应用。

3.3 我的项目创立

接下来,咱们就能够创立我的项目了,Spring Boot 中,对于邮件发送提供了主动配置类,开发者只须要退出相干依赖,而后配置一下邮箱的根本信息,就能够发送邮件了。

  • 首先创立一个 Spring Boot 我的项目,引入邮件发送依赖:

创立实现后,我的项目依赖如下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
  • 配置邮箱根本信息

我的项目创立胜利后,接下来在 application.properties 中配置邮箱的根本信息:

spring.mail.host=smtp.qq.com
spring.mail.port=587
spring.mail.username=1510161612@qq.com
spring.mail.password=ubknfzhjkhrbbabe
spring.mail.default-encoding=UTF-8
spring.mail.properties.mail.smtp.socketFactoryClass=javax.net.ssl.SSLSocketFactory
spring.mail.properties.mail.debug=true

配置含意别离如下:

  • 配置 SMTP 服务器地址
  • SMTP 服务器的端口
  • 配置邮箱用户名
  • 配置明码,留神,不是真正的明码,而是刚刚申请到的受权码
  • 默认的邮件编码
  • 配饰 SSL 加密工厂
  • 示意开启 DEBUG 模式,这样,邮件发送过程的日志会在控制台打印进去,不便排查谬误

如果不晓得 smtp 服务器的端口或者地址的的话,能够参考 腾讯的邮箱文档

  • https://service.mail.qq.com/c…

做完这些之后,Spring Boot 就会主动帮咱们配置好邮件发送类,相干的配置在 org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration 类中,局部源码如下:

@Configuration
@ConditionalOnClass({MimeMessage.class, MimeType.class, MailSender.class})
@ConditionalOnMissingBean(MailSender.class)
@Conditional(MailSenderCondition.class)
@EnableConfigurationProperties(MailProperties.class)
@Import({MailSenderJndiConfiguration.class, MailSenderPropertiesConfiguration.class})
public class MailSenderAutoConfiguration {}

从这段代码中,能够看到,导入了另外一个配置 MailSenderPropertiesConfiguration 类,这个类中,提供了邮件发送相干的工具类:

@Configuration
@ConditionalOnProperty(prefix = "spring.mail", name = "host")
class MailSenderPropertiesConfiguration {
        private final MailProperties properties;
        MailSenderPropertiesConfiguration(MailProperties properties) {this.properties = properties;}
        @Bean
        @ConditionalOnMissingBean
        public JavaMailSenderImpl mailSender() {JavaMailSenderImpl sender = new JavaMailSenderImpl();
                applyProperties(sender);
                return sender;
        }
}

能够看到,这里创立了一个 JavaMailSenderImpl 的实例,JavaMailSenderImplJavaMailSender 的一个实现,咱们将应用 JavaMailSenderImpl 来实现邮件的发送工作。

做完如上两步,邮件发送的筹备工作就算是实现了,接下来就能够间接发送邮件了。

具体的发送,有 5 种不同的形式,咱们一个一个来看。

3.3.1 发送简略邮件

简略邮件就是指邮件内容是一个一般的文本文档:

@Autowired
JavaMailSender javaMailSender;
@Test
public void sendSimpleMail() {SimpleMailMessage message = new SimpleMailMessage();
    message.setSubject("这是一封测试邮件");
    message.setFrom("1510161612@qq.com");
    message.setTo("25xxxxx755@qq.com");
    message.setCc("37xxxxx37@qq.com");
    message.setBcc("14xxxxx098@qq.com");
    message.setSentDate(new Date());
    message.setText("这是测试邮件的注释");
    javaMailSender.send(message);
}

从上往下,代码含意别离如下:

  1. 构建一个邮件对象
  2. 设置邮件主题
  3. 设置邮件发送者
  4. 设置邮件接收者,能够有多个接收者
  5. 设置邮件抄送人,能够有多个抄送人
  6. 设置隐秘抄送人,能够有多个
  7. 设置邮件发送日期
  8. 设置邮件的注释
  9. 发送邮件

最初执行该办法,就能够实现邮件的发送,发送效果图如下:

3.3.2 发送带附件的邮件

邮件的附件能够是图片,也能够是一般文件,都是反对的。

@Test
public void sendAttachFileMail() throws MessagingException {MimeMessage mimeMessage = javaMailSender.createMimeMessage();
    MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);
    helper.setSubject("这是一封测试邮件");
    helper.setFrom("1510161612@qq.com");
    helper.setTo("25xxxxx755@qq.com");
    helper.setCc("37xxxxx37@qq.com");
    helper.setBcc("14xxxxx098@qq.com");
    helper.setSentDate(new Date());
    helper.setText("这是测试邮件的注释");
    helper.addAttachment("javaboy.jpg",new File("C:\\Users\\sang\\Downloads\\javaboy.png"));
    javaMailSender.send(mimeMessage);
}

留神这里在构建邮件对象上和前文有所差别,这里是通过 javaMailSender 来获取一个简单邮件对象,而后再利用 MimeMessageHelper 对邮件进行配置,MimeMessageHelper 是一个邮件配置的辅助工具类,创立时候的 true 示意构建一个 multipart message 类型的邮件,有了 MimeMessageHelper 之后,咱们针对邮件的配置都是由 MimeMessageHelper 来代劳。

最初通过 addAttachment 办法来增加一个附件。

执行该办法,邮件发送效果图如下:

3.3.3 发送带图片资源的邮件

图片资源和附件有什么区别呢?图片资源是放在邮件注释中的,即一关上邮件,就能看到图片。然而一般来说,不倡议应用这种形式,一些公司会对邮件内容的大小有限度(因为这种形式是将图片一起发送的)。

@Test
public void sendImgResMail() throws MessagingException {MimeMessage mimeMessage = javaMailSender.createMimeMessage();
    MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
    helper.setSubject("这是一封测试邮件");
    helper.setFrom("1510161612@qq.com");
    helper.setTo("25xxxxx755@qq.com");
    helper.setCc("37xxxxx37@qq.com");
    helper.setBcc("14xxxxx098@qq.com");
    helper.setSentDate(new Date());
    helper.setText("<p>hello 大家好,这是一封测试邮件,这封邮件蕴含两种图片,别离如下 </p><p> 第一张图片:</p><img src='cid:p01'/><p> 第二张图片:</p><img src='cid:p02'/>",true);
    helper.addInline("p01",new FileSystemResource(new File("C:\\Users\\sang\\Downloads\\javaboy.png")));
    helper.addInline("p02",new FileSystemResource(new File("C:\\Users\\sang\\Downloads\\javaboy2.png")));
    javaMailSender.send(mimeMessage);
}

这里的邮件 text 是一个 HTML 文本,里边波及到的图片资源先用一个占位符占着,setText 办法的第二个参数 true 示意第一个参数是一个 HTML 文本。

setText 之后,再通过 addInline 办法来增加图片资源。

最初执行该办法,发送邮件,成果如下:

在公司理论开发中,第一种和第三种都不是应用最多的邮件发送计划。因为失常来说,邮件的内容都是比拟的丰盛的,所以大部分邮件都是通过 HTML 来出现的,如果间接拼接 HTML 字符串,这样当前不好保护,为了解决这个问题,个别邮件发送,都会有相应的邮件模板。最具代表性的两个模板就是 Freemarker 模板和 Thyemeleaf 模板了。

3.3.4 应用 Freemarker 作邮件模板

首先须要引入 Freemarker 依赖:

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

而后在 resources/templates 目录下创立一个 mail.ftl 作为邮件发送模板:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p>hello 欢送退出 xxx 小家庭,您的入职信息如下:</p>
<table border="1">
    <tr>
        <td> 姓名 </td>
        <td>${username}</td>
    </tr>
    <tr>
        <td> 工号 </td>
        <td>${num}</td>
    </tr>
    <tr>
        <td> 薪水 </td>
        <td>${salary}</td>
    </tr>
</table>
<div style="color: #ff1a0e"> 一起努力创造辉煌 </div>
</body>
</html>

接下来,将邮件模板渲染成 HTML,而后发送即可。

@Test
public void sendFreemarkerMail() throws MessagingException, IOException, TemplateException {MimeMessage mimeMessage = javaMailSender.createMimeMessage();
    MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
    helper.setSubject("这是一封测试邮件");
    helper.setFrom("1510161612@qq.com");
    helper.setTo("25xxxxx755@qq.com");
    helper.setCc("37xxxxx37@qq.com");
    helper.setBcc("14xxxxx098@qq.com");
    helper.setSentDate(new Date());
    // 构建 Freemarker 的根本配置
    Configuration configuration = new Configuration(Configuration.VERSION_2_3_0);
    // 配置模板地位
    ClassLoader loader = MailApplication.class.getClassLoader();
    configuration.setClassLoaderForTemplateLoading(loader, "templates");
    // 加载模板
    Template template = configuration.getTemplate("mail.ftl");
    User user = new User();
    user.setUsername("javaboy");
    user.setNum(1);
    user.setSalary((double) 99999);
    StringWriter out = new StringWriter();
    // 模板渲染,渲染的后果将被保留到 out 中,将 out 中的 html 字符串发送即可
    template.process(user, out);
    helper.setText(out.toString(),true);
    javaMailSender.send(mimeMessage);
}

须要留神的是,尽管引入了 Freemarker 的自动化配置,然而咱们在这里是间接 new Configuration 来重新配置 Freemarker 的,所以 Freemarker 默认的配置这里不失效,因而,在填写模板地位时,值为 templates

调用该办法,发送邮件,效果图如下:

3.3.5 应用 Thymeleaf 作邮件模板

举荐在 Spring Boot 中应用 Thymeleaf 来构建邮件模板。因为 Thymeleaf 的自动化配置提供了一个 TemplateEngine,通过 TemplateEngine 能够不便的将 Thymeleaf 模板渲染为 HTML,同时,Thymeleaf 的自动化配置在这里是持续无效的。

首先,引入 Thymeleaf 依赖:

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

而后,创立 Thymeleaf 邮件模板:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p>hello 欢送退出 xxx 小家庭,您的入职信息如下:</p>
<table border="1">
    <tr>
        <td> 姓名 </td>
        <td th:text="${username}"></td>
    </tr>
    <tr>
        <td> 工号 </td>
        <td th:text="${num}"></td>
    </tr>
    <tr>
        <td> 薪水 </td>
        <td th:text="${salary}"></td>
    </tr>
</table>
<div style="color: #ff1a0e"> 一起努力创造辉煌 </div>
</body>
</html>

接下来发送邮件:

@Autowired
TemplateEngine templateEngine;

@Test
public void sendThymeleafMail() throws MessagingException {MimeMessage mimeMessage = javaMailSender.createMimeMessage();
    MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
    helper.setSubject("这是一封测试邮件");
    helper.setFrom("1510161612@qq.com");
    helper.setTo("25xxxxx755@qq.com");
    helper.setCc("37xxxxx37@qq.com");
    helper.setBcc("14xxxxx098@qq.com");
    helper.setSentDate(new Date());
    Context context = new Context();
    context.setVariable("username", "javaboy");
    context.setVariable("num","000001");
    context.setVariable("salary", "99999");
    String process = templateEngine.process("mail.html", context);
    helper.setText(process,true);
    javaMailSender.send(mimeMessage);
}

调用该办法,发送邮件,效果图如下:

好了,这就是咱们明天说的 5 种邮件发送姿态,不晓得你把握了没有呢?

本文案例曾经上传到 GitHub:https://github.com/lenve/javaboy-code-samples。

有问题欢送留言探讨。

参考资料:

  • https://www.mailgun.com/blog/…

正文完
 0