SMTP协议解读以及如何使用SMTP协议发送电子邮件

2023-11-17

电子邮件协议中POP3协议用于接收邮件,SMTP协议用于发送邮件。SMTP的全称为Simple Mail Transfer Protocol,也就是简单邮件传输协议,字如其名。
 
相较于POP3而言,SMTP确实比较简单。这里的简单并不是指SMTP的命令比POP3少,而是指SMTP的命令是有序的,而POP3的命令是无序的,理解这一点很重要。也就是说SMTP的命令是要组合在一起才能完成一次邮件发送任务,单独调用每个命令的意义不大。POP3命令则不同,LIST、STAT、UIDL、TOP、RETR、DELE等命令都可以独立使用,比如用LIST命令查看邮件清单,然后用RETR命令接收邮件。
 
简单的另一层含义是:就socket编程而言实现发送数据要比实现接收数据简单点。
比如接收数据时要判断数据是否接收完毕。如果一条数据以回车换行结束,就需要判断是否接收到了"\r\n",从而确保读取到一条完整的消息体。而发送数据则不需要考虑上述问题,你可以按照自己的节奏发送数据,可以一次将整个消息体发送出去,也可以不用考虑服务器的死活一个字节一个字节发送数据,直至将整条消息发送完毕。
换句话说,接收数据要以流的方式进行,而不是简单的开辟一个缓冲区,进行一次recv操作。 虽然大部分情况下这种方式也没有问题,比如写个Demo程序,但如果要让你的网络程序非常健壮的话,最好以流的方式进行读取。因为并不是每次对方都会按照你期望的方式发送数据给你,比如,你开辟了1024字节缓冲区用于接收网络数据,但对方可能一次只给你发送一个字节,或者发出了1025个字节。
 
SMTP和HTTP协议一样都属于请求应答式协议,也就是一问一答,客户端发送命令后,服务器返回响应内容。 SMTP的响应格式和HTTP协议的基本一样,都是响应码+响应描述。响应码用三位数字表示,空格后则是响应信息的描述,只是HTTP协议会多一个版本信息。

这种一问一答式协议,在HTTP协议上体现的并不是很明显,只有HTTP连接设置为Keep-Alive时,你才有机会使用GET或POST命令反复与服务器进行交互,否则只有一次问答的机会。

但在SMTP协议下这种一问一答的交互方式就非常明显了。 主要原因是完成一次邮件的发送任务涉及到的步骤比较多,我把电子邮件的发送分为如下五个步骤:

1、建立会话;
2、身份认证;
3、发送邮件信封(发件人和收件人);
4、发送邮件内容(邮件正文和附件);
5、关闭会话

在这里插入图片描述
SMTP的命令主要就分布在这五个步骤中。下面以网易的yeah邮箱(smtp.yeah.net服务器)为例,具体说明这五个步骤的实现。C代表客户端,S代表服务端
 

一、建立会话

SMTP命令:HELO
该阶段用于建立客户端与SMTP服务器的连接,在此基础上,双方进行友好的问候。SMTP服务器的默认端口号是25,如果是支持SSL协议,则默认端口号是465。如果采用的是STARTTLS协议,则默认端口是587,所谓的STARTSSL其实就是SSL协议,只是开始会话前双方客套一下,问一下对方你还支持SSL啊?

连接建立后,服务器会发送一条欢迎语。接着你就需要问候一下服务器,并带上你的机器的名称。如下:

S: 220 yeah.net Anti-spam GT for Coremail System (yeah[20141016])
C: HELO your-computer-name
S: 250 OK

 

二、身份认证

SMTP命令:AUTH LOGIN
该命令用于进行身份验证,虽然这一步在SMTP协议中不是强制的要求,但目前几乎所有的SMTP服务器都需要进行身份认证。增加这一步可以大大减少垃圾邮件的存在,以及避免有人伪造其它发件人进行邮件的发送操作。
这一步中账号和密码需要进行base64编码,包括服务器发来的提示信息也是base64编码。
首先发送AUTH LOGIN命令,服务器会返回“334 XNlcm5hbWU6”,“dXNlcm5hbWU6”解码后为“username:”
UGFzc3dvcmQ6解码为"Password:"
也就是提示用户输入用户名和密码。认证成功后返回235注意返回的不是二百五(250)哦。 接着根据服务器返回的提示,发送账号(发件人的邮箱账号)和密码。

C: AUTH LOGIN
S: 334 dXNlcm5hbWU6
C: base64编码后的账号(发件人的邮箱账号)
S: 334 UGFzc3dvcmQ6
C: base64编码后的密码
S: 235 Authentication successful

至于为何是base64编码,可能是SMTP协议设计时考虑到用户名和密码的重要性,所采用的最简单的“加密”手段。虽然base64只是编码方式,不是加密方式,但在早期控制台输入命令的情况下,别人还是一下无法像记住明文一样记住这些无规律的base64编码。不过随着SSL的应用,这些都已不重要了。
 

三、发送邮件信封

SMTP命令:MAIL FROM、RCPT TO
该阶段是告诉服务器发件人和收件人的邮箱地址,可以把这个阶段想象为你在写纸质信件的信封。MAIL FROM用于指定发件人邮箱,该邮箱地址其实就是上述身份认证中的账号,如:
MAIL FROM: <lig4961@yeah.net>
RCPT TO用于指定收件人邮箱,一次只能指定一个收件人地址,如果收件人有多个的话,可以多次发送RCPT TO命令。

C: MAIL FROM: <lig4961@yeah.net>
S: 250 Mail OK
C: RCPT TO: <syfzxm@163.com>
S: 250 Mail OK
C: RCPT TO: <lig4961@yeah.net>
S: 250 Mail OK

注意,邮件地址要用放入<>中,此外,每条命令发送完毕后,一定要判断服务器返回码是否是250。 如果返回的不是二百五,说明你发送的地址可能是二百五,也就是不正确的地址,比如邮件地址中没有@,或者在同一个邮箱系统中,SMTP服务器发现收件人的地址并不存在,也就是没有注册过。

看到这里可能有人会有疑问:我们通过邮件客户端或网页写邮件时,不是有三种身份的收件人么?即:主送人(to)、抄送人(cc)、密送人(bcc)。是否存在RCPT CC和RCPT BCC命令,用于发送抄送人和密送人的邮箱地址呢?很遗憾,没有这两个命令。也就是说抄送人(cc)和密送人(bcc),也是通过RCPT TO命令进行发送。
 
既然发送时不区分,那么我们在收到的邮件中怎么还能看到主送人和抄送人呢?或者说如何做到让密送人在收到的邮件中看不见的。答案在下面邮件内容中。
 

四、发送邮件内容

SMTP命令:DATA

这一步是发送数据最多也是最复杂的一步,但操作命令却只有一个,就是DATA,也就是数据(邮件内容),邮件内容主要包括三个部分(可能会有内嵌资源文件,也可以理解为狭义上的附件):

1、邮件头;
2、邮件正文;
3、邮件附件;

DATA命令发送后,服务器会返回354响应码,并告诉客户端,数据结束要以"\r\n.\r\n"来标识。接下来客户端就可以发送整个邮件内容了。

DATA
354 End data with <CR><LF>.<CR><LF>
SUBJECT: =?UTF-8?B?5p2l6IeqU29mdGxlZe+8jOi/meaYr+S4gOWwgea1i+ivlemCruS7tg==?=
FROM: <lig4961@yeah.net>
TO: 'softlee1' <syfzxm@163.com>, 'softlee2' <lig4961@yeah.net>
MIME-Version: 1.0
Content-Type: multipart/mixed;
        boundary="=NextPart_SOFTLEE_Mail_E0B1A829CB1D4f55A037AE04B6A72078"

--=NextPart_SOFTLEE_Mail_E0B1A829CB1D4f55A037AE04B6A72078
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: base64

PCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBYSFRNTCAxLjAgVHJhbnNpdGlvbmFs
Ly9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSL3hodG1sMS9EVEQveGh0bWwxLXRyYW5zaXRpb25h
bC5kdGQiPg0KPGh0bWwgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwiPg0KDQo8
aGVhZD4NCiAgICA8bWV0YSBodHRwLWVxdWl2PSJDb250ZW50LVR5cGUiIGNvbnRlbnQ9InRleHQv

邮件内容的格式目前基本都采用MIME格式,MIME格式比较简单,可参见文章:《如何解析EML(邮件)格式的文件以及一款小巧的EML邮件阅读工具》。
 
这里我们不具体介绍如何编码邮件正文和附件。主要介绍邮件头中的信息,主题(Subject)、发件人(From)、收件人(To)、抄送(Cc)。我们看查看邮件时,读到的主题、收件人和抄送人就来自于上述字段。这里收件人和抄送人仅作为邮件头的一部分进行展现,服务器并不会关心这些地址是否真实存在,或者说服务器并不关心这些地址是否跟使用RCPT TO命令发送的地址保持一致。回到第三阶段中最后的几个问题,我们可以通过邮件头来展现该邮件的抄送人是谁,并且将密送人隐藏掉。当然你也可以篡改上述信息,比如隐瞒某些收件人,或者将密送人也一并展现。
 
邮件正文和附件的编码可参照MIME格式的文章。最后所有数据发送完毕后,一定要发送"\r\n.\r\n",从而告诉SMTP服务器所有数据发送完毕。
 

五、会话结束

SMTP命令:QUIT
这一步非常简单,就是发送一条QUIT命令,QUIT命令发送完毕后,还是要判断服务器的返回码是否为250。如果返回的不是,则表明发送失败,SMTP服务器可能不会将邮件转发到收件人所在的邮箱中,这一点很重要。

至此,整个SMTP协议介绍完毕。SMTP协议比较简单,但具体的实现细节可能还有很多,需要在实践中去体验,有的服务器返回消息体是多行的,比如outlook邮箱的服务器,下面是outlook邮箱使用STARTTLS协议截图:
 
在这里插入图片描述
 

附一: SMTP邮件发送工具
该工具特点:
1、基于命令行方式且只有一个独立文件;
2、支持SSL、STARTSSL协议;
3、具有丰富的命令行参数;

附二: 电子邮件相关文章和工具
POP3协议(电子邮件邮局协议)中UIDL和TOP命令在实际使用中的作用
POP3:基于命令行的电子邮件(EMail)在线查看和批量下载工具
EmlParse:一款超轻量级的批量解析EML格式电子邮件的工具

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SMTP协议解读以及如何使用SMTP协议发送电子邮件 的相关文章

  • Web 应用程序的 Spring Boot 和 Comodo https 配置

    我是 https 配置的新手 并尝试配置 spring boot 和 Comodo SSL 经过几次电话和尝试后 我已经弄清楚如何为您的 spring boot 网站正确配置 https 下面的答案是详细步骤 希望它可以帮助人们生成更安全的
  • 用于保护网站安全(使用 SSL)时,数字证书如何工作?

    请帮助我了解整个过程是如何进行的 据我了解 Web 浏览器包含 verisign Entrust Comodo 等证书颁发机构 CA 的根证书 但是当用户访问安全页面时到底会发生什么 Web 浏览器是否向 CA 服务器发送请求来验证证书 还
  • 使用 SSL 的 Xamarin.Forms Image.Source

    我正在使用一个在线商店来存储通过我们的应用程序上传的用户图像 并受 SSL 保护 上传工作一切顺利 因为我使用的是带有附加证书的 WebClient 但是当我尝试使用 Xamarin Forms Image 组件时 例如将源设置为 http
  • Asp.Net Core 中的 SSL 不起作用

    我从 Visual Studio 创建了一个简单的 Web 应用程序Web Application Net Core 具有个人用户帐户授权的模板 然后 我启用了 SSLProject gt MyProject Properties 将带有
  • 将 HttpApi 与 I/O 完成端口结合使用

    我刚刚偶然发现了微软的HTTP 服务器 API http msdn microsoft com en us library aa364510 28v vs 85 29 aspx 简介中写道 HTTP 服务器 API 使应用程序能够通过 HT
  • 使用普通用户和 https 的 gitea

    我正在尝试设置 gitea 以使用 https 和我从 LetsEncrypt 获得的证书 运行该服务作为普通用户 我已经让它与普通用户在端口 80 上使用 http 一起工作git并使用 iptables 将端口 80 重定向到端口 30
  • 如何增加asp classic的请求接受限制

    我从java小程序向asp classic发送post请求 我在此请求中发送非常大的数据 即 csv 数据 当此请求中的字符数增加并超过 138000 时 asp 不接受该请求 java 小程序给出 500 错误 所以有人可以告诉我如何才能
  • 使用特定 HTTP 方法链接到页面 (DELETE)

    如何像 Rails 那样链接到页面并让浏览器使用 DELETE 方法调用它 我试过 a href DELETE ME a 但不起作用 我使用 Node js 所以我可以用它来处理 DELETE 方法 你不能 链接只会触发 GET 请求 您可
  • 在 iOS 中,http 204 响应返回空白页面,有办法阻止这种情况吗?

    以前可能有人问过这个问题 但我似乎找不到解决方案 所以如果是这种情况 我深表歉意 我正在开发一个使用express的简单节点应用程序 其中一个帖子路由返回 http 204 并发送它 下面是我的代码 router post id funct
  • .net core 2.0代理请求总是导致http 407(需要代理身份验证)

    我正在尝试通过 net core 2 0 Web 应用程序中的 WebProxy 发出 HTTP 请求 我得到的代码在 net框架中运行良好 所以我知道 相信 这不是环境问题 我也尝试使用两者来发出请求HttpWebRequest and
  • AWS EC2 应用程序负载均衡器 + 双向 SSL?

    是否可以使用 AWS Application Load Balancer 并使用双向 ssl 客户端证书 我当前的设置使用经典的 ELB 通过 tcp 转发到 Web 服务器端点来支持此操作 我现在需要使用 URL 路由流量 并希望在可能的
  • RestSharp RestClient的默认超时值是多少?

    任何人都知道默认超时值休息锐利 https github com restsharp 休息客户端 RestSharp 在底层使用 HttpWebRequest 它有一个默认超时 https msdn microsoft com en us
  • HttpWebRequest vs Webclient(特殊场景)

    我知道这个问题之前已经回答过thread https stackoverflow com questions 1694388 webclient vs httpwebrequest httpwebresponse 但我似乎找不到详细信息 在
  • OpenSSL DH 密钥太小错误

    我正在尝试使用简单的 PERL 脚本连接到封闭的服务器 空调 usr bin perl use 5 10 1 use warnings use strict use IO Socket SSL use IO Socket SSL qw de
  • 服务器响应中的“连接:保持活动状态”

    我正在尝试建立从 Silverlight 应用程序到 Apache 服务器托管的 PHP 页面的 HTTP 持久连接 即无需为每个 HTTP 请求创建新的 TCP 连接 为此 我需要网络服务器发送其 HTTP 响应 并将 Connectio
  • 如何使用 python 的 http.client 准确读取一个响应块?

    Using http client在 Python 3 3 或任何其他内置 python HTTP 客户端库 中 如何一次读取一个分块 HTTP 响应一个 HTTP 块 我正在扩展现有的测试装置 使用 python 编写 http clie
  • 让我们加密证书颁发

    我正在尝试获取 Let s Encrypt 颁发的证书 已经过去了 3 个半小时 我不小心最初将我的 SecretName 设置为 echo tls 然后将其切换到我想使用的正确的 pandaist tls 我目前有这个 kubectl g
  • 从手机访问本地主机[关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我正在使用
  • 最适合“正在进行的作业”的 HTTP 状态代码

    向客户端提供的最合适的 HTTP 状态代码是什么 表示 您的请求很好 但仍在进行中 请稍后在完全相同的位置回来查看 例如 假设客户端提交初始请求以启动繁重的查询 服务器立即返回一个 URL 客户端可以定期轮询该 URL 以获取结果 如果客户
  • Angular 2 - Http - 正确忽略空结果

    我有很多处理请求并简单返回 200 的 REST 端点 我注意到将结果映射为错误json 如果我尝试不进行任何类型的映射 我会看到浏览器警告它无法解析 XML 由于不返回任何内容是很常见的 我很好奇我应该如何处理响应 这是一个基本的代码示例

随机推荐

  • 算法工程师福利:超实用技术路线图

    对于不同级别的算法工程师技能要求 我们大致可以分成以下几个层级 初级 可以在一些指导和协助下独立完成开发任务 具体到算法方面 需要你对于工具框架 建模技术 业务特性等方面有一定的了解 可以独立实现一些算法项目上的需求 中级 可以基本独立完成
  • USB+HOST+FATFS

    转载https blog csdn net zcshoucsdn article details 78944536
  • Mysql 5.6 双主配置 自动同步脚本

    最近有项目应用到了 mysql 双主结构 现在贴出来共享 mysql 版本 5 6 11 操作系统版本 rhel 6 2 Master 的 my cnf 配置 只贴M M 结构部分 log bin fabian server id 1 bi
  • 【Deep Learning】Hinton. Reducing the Dimensionality of Data with Neural Networks Reading Note

    2006年 机器学习泰斗 多伦多大学计算机系教授Geoffery Hinton在Science发表文章 提出基于深度信念网络 Deep Belief Networks DBN 可使用非监督的逐层贪心训练算法 为训练深度神经网络带来了希望 如
  • Houdini中全景摄像机shader立体左右眼成像方法

    熟悉Houdini Shader部分的同学应该多多少少也了解camera自身也可以设定自己的shader 其中polar panoramic shader 能够非常方便的为艺术家渲染360全景视角的cg画面 但是这样渲染出来的画面只是单眼所
  • md5加密

    crypto模块 crypto模块 封装了一系列密码学相关的功能 下载该模块 npm install save crypto 使用 crypto createHash md5 update 加密数据 digest hex 示例
  • 线程的状态与切换

    Java中的线程的生命周期大体可分为5种状态 1 新建 初始化 NEW 新创建了一个线程对象 2 可运行 RUNNABLE 线程对象创建后 其他线程 比如main线程 调用了该对象的start 方法 该状态的线程位于可运行线程池中 等待被线
  • react入门,适合新手小白!

    1 1官方网站 中文官网 React 官方中文文档 用于构建用户界面的 JavaScript 库 2 react简介 1 2 1 React是什么 主要是帮助咱们操作界面 也就是操作视图呈现页面 1 2 2 为什么要学React 易于学习
  • Hive(完整版)

    Hive 1 基本概念 Hive本质上是基于 Hadoop 的一个数据仓库工具 可以将结构化的数据文件映射为一张表 并 提供类 SQL 查询功能 通俗一点就是Hive相当于一个hadoop的客户端 利用hdfs存储数据 利用mapreduc
  • 【CV】第 10 章:使用 R-CNN、SSD 和 R-FCN 进行目标检测

    大家好 我是Sonhhxg 柒 希望你看完之后 能对你有所帮助 不足请指正 共同学习交流 个人主页 Sonhhxg 柒的博客 CSDN博客 欢迎各位 点赞 收藏 留言 系列专栏 机器学习 ML 自然语言处理 NLP 深度学习 DL fore
  • JAVA计算摘要,例如MD5和SHA-256

    摘要有什么用 1 保证数据的完整性 例如你发送一个100M的文件给你的B 但是你不知道B收到的是否是完整的文件 此时你首先使用摘要算法 如MD5 计算了一个固定长度的摘要 将这个摘要和文件一起发送给B B接收完文件之后 同样使用MD5计算摘
  • Android 使用SwipeRefreshLayout实现RecyclerVeiw的下拉刷新和上拉加载

    博主前些天发现了一个巨牛的人工智能学习网站 通俗易懂 风趣幽默 忍不住也分享一下给大家 点击跳转到网站 实现下拉刷新和上拉加载的完整代码如下 一 布局文件代码如下 主界面main xml代码
  • PLSQL性能优化方法

    转载自http www itfarmer com cn 1 选择最有效率的表名顺序 只在基于规则的优化器中有效 ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名 FROM子句中写在最后的表 基础表driving table 将
  • stm32f407+cjson的避坑

    1 添加cjson库文件后 编译工程文件 报错 提示 CJSON test c 461 error 268 declaration may not appear after executable statement in block 如下图
  • python 使用socket建立小型聊天室

    一个聊天室 由两个部分组成 服务端和客户端 服务端接收客户端发来的消息 并将接收到的消息发送给其他客户端 客户端负责发送消息到服务端 并接收来自服务端发送的来自其他客户端的消息 示例图 服务端和客户端 这是属于一个群聊的聊天室 服务端会把每
  • 淦、我的服务器又被攻击了

    作者简介 CSDN top100 阿里云博客专家 华为云享专家 网络安全领域优质创作者 推荐专栏 对网络安全感兴趣的小伙伴可以关注专栏 网络安全入门到精通 最近老是有粉丝问我 被黑客攻击了 一定要拔网线吗 还有没有别的方法 按理说 如果条件
  • Python使用os.path.join只保留最后一个变量的原因

    在使用Python的os path join a path bbb ccc 来合并路径时 合并的结果如果只保留了最后的 ccc 是因为最后的一个变量名包含了斜杠 函数会将其识别成绝对路径 因此就会忽略前面所以的其他路径
  • File类的知识

    File 文章目录 File 概述 构造方法 抽象路径 成员方法 创建 删除 判断和获取和遍历 判断 获取 遍历 概述 java编写的一个专门用于描述计算机中的文件和文件夹的类 1 是文件和目录路径名的抽象表示 2 文件和目录是可以通过Fi
  • System has not been booted with systemd as init system (PID 1). Can‘t operate

    system has not been booted with systemd as init system pid 1 can t operate Error 报错 System has not been booted with syst
  • SMTP协议解读以及如何使用SMTP协议发送电子邮件

    电子邮件协议中POP3协议用于接收邮件 SMTP协议用于发送邮件 SMTP的全称为Simple Mail Transfer Protocol 也就是简单邮件传输协议 字如其名 相较于POP3而言 SMTP确实比较简单 这里的简单并不是指SM