邮件发送原理

SMTP(Simple Mail Transfer Protocol)是电子邮件从客户机传输到服务器或从某一个服务器传输到另一个服务器使用的传输协议。SMTP 是请求/响应协议,命令和响应都是基于 ASCII 文本,并以 CR 和 LF 符结束。响应包括一个表示返回状态的三位数字代码。在 TCP 协议 25 端口监听连接请求。其命令如下:

SMTP命令

命令说明

HELO <domain><CRLF>

识别发送方到接收SMTP的一个HELO命令

AUTH LOGIN

登陆服务器的命令。在这条命令之后,要发送用Base64编码后的用户名与密码进行登陆

MAIL FROM:<reverse-path><CRLF>

<reverse-path>为发送者地址。此命令告诉接收方一个新邮件发送的开始,并对所有的状态和缓冲区进行初始化。此命令开始一个邮件传输处理,最终完成将邮件数据传送到一个或多个邮箱中

RCPT TO:<forward-path><CRLF>

<forward-path>标识各个邮件接收者的地址

DATA <CRLF>

接收SMTP将把其后的行为看作邮件数据去处理,以<CRLF>.<CRLF>标识数据的结尾

REST <CRLF>

退出/复位当前的邮件传输

NOOP <CRLF>

要求接收SMTP仅做OK应答。(用于测试)

QUIT <CRLF>

要求接收SMTP返回一个OK应答并关闭传输。

VRFY <string> <CRLF>

验证指定的邮箱是否存在,由于安全因素,服务器多禁止此命令。

EXPN <string> <CRLF>

验证给定的邮箱列表是否存在,扩充邮箱列表,也常禁止使用。

HELP <CRLF>

查询服务器支持什么命令


邮件交互图

A->B: 1. 建立TCP连接(host:port, 默认port为25)
B->A: 220. Anti-spam GT for Coremail System
Note over A: 
A->B: 2. 向服务器标识用户身份(HELO host\r\/n)
B->A: 250 OK
Note over A: 
A->B: 3. 登录服务器(AUTH LOGIN\r\/n)
B->A: 334. username: (这里是解密后的信息)
A->B: <my_username>(要用Base64加密)
B->A: 334. password: (这里是解密后的信息)
A->B: <my_password>(要用Base64加密)
B->A: 235. Authentication successful
Note over A: 
A->B: 4. 指定发信者(MAIL FROM: <my_sender@gmail.com>\r\/n)
B->A: 250. Mail OK
Note over A: 
A->B: 5. 指定收信者(RCPT TO: <my_receiver@gmail.com>\r\/n)
B->A: 250. Mail OK
Note over A: 
A->B: 6. 发送数据(DATA\r\/n)
B->A: 354. End data with <CR><LF>.<CR><LF>
Note over A: 
A->B: 7. to: <my_receiver@gmail.com\r\/nsubject:<my_subject>\r\/nSome Context\r\/n.\r\/n>
B->A: 250. Mail OK
Note over A: 
A->B: 8. QUIT\r\/n
B->A: 221. Bye

因markdown里不能打出"\n", 因此使用"\/n" 代替"\n"


SMTP发信操作及返回码

[crazywill@localhost crazywill]$ telnet smtp.163.com 25 #telnet登录25端口
Trying 202.108.5.81...
Connected to smtp.163.com.
Escape character is '^]'.
220 163.com Coremail SMTP(Anti Spam) System
EHLO smtp.163.com # 握手 :)
250-mail
250-PIPELINING
250-AUTH LOGIN PLAIN
250-AUTH=LOGIN PLAIN
250 8BITMIME
AUTH LOGIN # 开始认证登录
334 dXNlcm5hbWU6
crazywill
334 UGFzc3dvcmQ6
mypassword
535 Error: authentication failed # 直接用户名密码不能登录
AUTH LOGIN
334 dXNlcm5hbWU6
Y3Jhenl3aWxs
334 UGFzc3dvcmQ6
bXlwYXNzd29yZA==
235 Authentication successful # 使用Base64编码则成功登录
MAIL FROM:<test@163.com> # 邮件发送方
553 You are not authorized to send mail, authentication is required # 不可伪造发送邮件 
MAIL FROM:<crazywill@163.com> # 邮件发送方
250 Mail OK
RCPT TO:<crazywill@163.com> # 邮件的接收方,若有多个收件人,则重复这一语句多次。
250 Mail OK
DATA # 邮件体内容
354 Please start mail input.
TO: crazywill@163.com # 此处的TO,FROM,等内容,可以随便造假 :) 可以骗人但骗不了懂得查看邮件源码的。
FROM: cccc@163.com
SUBJECT: test by telnet/smtp 

test, just a test. # 邮件正文内容,与Header部分空一行开始写
. # 邮件写完,以一个句点加回车结果。
250 Mail OK queued as smtp10,wKjADQ2ApxRnnqBE0CWaEw==.38326S3 # 返回250 表示发送成功。
NOOP # 空语句,不执行任何操作,一般用来保持和服务器连接,不要掉线
250 OK
QUIT # 退出
221 Closing connection. Good bye.
Connection closed by foreign host.
[crazywill@localhost crazywill]$

参考资料: 用c++发邮件 电子邮件发送的原理以及简易实现 邮件正文及其附件的发送的C++实现 C++通过SMTP发送邮件总结 C++实现向多人发送邮件

Licensed under CC BY-NC-SA 4.0
Built with Hugo
主题 StackJimmy 设计