SMTP协议介绍
SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,邮件通过这个协议在MUA和MTA、MTA和MTA之间传输。有了第一篇的基础,相信大家也都了解到了,整个互联网邮箱体系能够正常运行的核心就是SMTP协议,这个协议好比邮箱界的 HTTP。有了 SMTP ,大家都遵守同一套的传输规范, 它保证了你发出去的邮件对方的MTA能收到,也保证了对方MTA发过来的邮件你可以收到。要保持你的邮箱系统能够正常运作,甚至 POP3/IMAP 协议都不是必须的,如果你不需要通过客户端收邮件的话,那么你其实可以通过登录邮件服务器主机直接使用mail/mailx 或者mutt 这样的命令行工具就可以进行邮件的收发。我们现在最常用的webmail,如网易、gmail的网页邮箱其实也没有用到 POP3/IMAP协议(除非你需要配置客户端)。
SMTP 也是基于 TCP 协议的,下面是命令和应答清单:
感觉和http协议特别像有木有?甚至smtp报文中的头部和http头部也特别像,我只能说可能是同一帮人设计的。。邮件的报文格式封装:
这里要注意的是报文的信封部分是不会体现在邮件内容里面的。smtp协议是能够直接通过telnet工具执行命令的,下面我们就来实战一下,加深理解
使用smtp服务器收邮件
我们这里假设有一个邮件服务商叫做 abc.mail(仅用于演示,非真实,下同),其他邮箱基本也都差不太多。首先通过nslookup命令找到mx记录,查询 abcmail用于收件的smtp服务器地址(一般叫Mail Exchanger,MX)
bob$ nslookup -type=mx abc.mail
abc.mail MX preference = 15, mail exchanger = mx6.abc.mail
abc.mail MX preference = 10, mail exchanger = mx2.abc.mail
abc.mail MX preference = 10, mail exchanger = mx4.abc.mail
abc.mail MX preference = 10, mail exchanger = mx3.abc.mail
abc.mail MX preference = 10, mail exchanger = mx1.abc.mail
abc.mail MX preference = 15, mail exchanger = mx5.abc.mail
我们选择 mx1.abc.mail 这个服务器,直接telnet它的25端口,相关输入的命令我写在了后面的注释里,实际执行时要去掉:
bob % telnet mx1.abc.mail 25
Connected to mx1.abc.mail.
Escape character is '^]'.
220 mx.abc.mail ESMTP c16-20020a170902d49000b0019e25cff4f5si9627390plg.617 - gsmtp
helo app //通知smtp服务端开启会话,helo 后面的内容可以随便输入,还有一个增强型的命令ehlo,能够返回更多服务端的内容
250 mx.abc.mail at your service
mail from:<foobar@example.com> //发件人地址
250 2.1.0 OK c16-20020a170902d49000b0019e25cff4f5si9627390plg.617 - gsmtp
rcpt to:<foobar@abc.mail> //收件人地址
250 2.1.5 OK c16-20020a170902d49000b0019e25cff4f5si9627390plg.617 - gsmtp
data //开始邮件内容编写
354 Go ahead c16-20020a170902d49000b0019e25cff4f5si9627390plg.617 - gsmtp
from: foobar<foobar@example.com> //邮件首部
to: foobar<foobar@abc.mail> //邮件首部
subject: hello //邮件首部
this is text //邮件正文
. //邮件内容以一个半角的.结束
550-5.7.28 [156.146.145.84 1] Our system has detected an unusual rate of
550-5.7.28 unsolicited mail originating from your IP address. To protect our
550-5.7.28 users from spam, mail sent from your IP address has been blocked.
20020a170902d49000b0019e25cff4f5si9627390plg.617 - gsmtp
不出意外的,这里出了意外了😓。邮件被拒绝发送,原因是发件方MTA的ip地址未经授权。一般来说,MX服务器默认对方也是MTA,需要进行各种安全认证,我们是通过个人电脑连接上去,自然是通不过认证了。似乎出师不利,但是也符合预期,目前各大邮箱的发送方身份认证策略都设置的比较完善了,随便设置发件人邮箱肯定是行不通了。这里我们先放一放,待自己的邮件服务器搭建完毕后再进行测试。
使用smtp服务器发邮件
abc.mail 发送邮件的服务器为 smtp.abc.mail ,我们先来测试一下25端口:
bob% telnet smtp.abc.mail 25
Connected to smtp.abc.mail.
Escape character is '^]'.
220 smtp.abc.mail ESMTP d13-20020a170902b70d00b001a1d553de0fsm5958849pls.271 - gsmtp
ehlo app
250-smtp.abc.mail at your service,
250-SIZE 35882577
250-8BITMIME
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-CHUNKING
250 SMTPUTF8
250 smtp.abc.mail at your service
mail from:<foobar@abc.mail>
530 5.7.0 Must issue a STARTTLS command first. d13-20020a170902b70d00b001a1d553de0fsm5958849pls.271 - gsmtp
可以看到发件人需要进行认证,而认证必须在tls连接中进行,从而有效保护传输的信息安全。telnet是不支持tls连接的,这里我们需要使用openssl工具来进行安全连接:
openssl s_client -starttls smtp -connect smtp.abc.mail:587 -crlf -ign_eof
...
ehlo app
250-smtp.abc.mail at your service,
250-SIZE 35882577
250-8BITMIME
250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-CHUNKING
250 SMTPUTF8
auth login
334 VXNlcm5hbWU6
Zm9vYmFy //用户名base64编码,演示用非真实
334 UGFzc3dvcmQ6
Zm9vYmFy //应用专用密码base64编码,演示用非真实
235 2.7.0 Accepted
mail from:<foobar@abc.mail>
250 2.1.0 OK z14-20020a6553ce000000b00502f017657dsm5485604pgr.83 - gsmtp
rcpt to:<foobar@163.com>
250 2.1.5 OK z14-20020a6553ce000000b00502f017657dsm5485604pgr.83 - gsmtp
data
354 Go ahead z14-20020a6553ce000000b00502f017657dsm5485604pgr.83 - gsmtp
from: foobar<foobar@abc.mail>
to: foobar<foobar@163.com>
subject: helo
text
.
250 2.0.0 OK 1681052959 z14-20020a6553ce000000b00502f017657dsm5485604pgr.83 - gsmtp
587端口是smtp 的 starttls的端口(也可以使用25端口),可以看到建立tls连接后出现了auth命令。这里要注意的是,主流的各大邮箱已经禁用在非安全设备上直接使用用户名密码的登录方式,直接登录会失败。需要先在邮箱控制面板中生成应用专用密码,再进行登录。上述操作后,邮件发送成功,在163邮箱可以收到这封邮件了。
或者也可以使用下面这个命令通过465端口建立tls连接,效果是一样的:
openssl s_client -connect smtp.abc.mail:465 -crlf -ign_eof
IMAP 协议介绍
IMAP协议, Internet Mail Access Protocal (交互式邮件访问协议),是一个应用层协议(端口是143)。IMAP协议比POP3协议复杂的多,也是按照C/S的工作方式,现在较新的版本是IMAP4。
与POP3协议类似,IMAP也是提供面向用户的邮件收取服务。常用的版本是IMAP4。IMAP4改进了POP3的不足,用户可以通过浏览信件头来决定是否收取、删除和检索邮件的特定部分,还可以在服务器上创建或更改文件夹或邮箱,它除了支持POP3协议的脱机操作模式 外,还支持联机操作和断连接操作。它为用户提供了有选择的从邮件服务器接收邮件的功能、基于服务器的信息处理功能和共享信箱功能。IMAP4的脱机模式不同于POP3,它不会自动删除在邮件服务器上已取出的邮件,其联机模式和断连接模式也是将邮件服务器作为“远程文件服务器”进行访问,更加灵活方便。目前只使用POP3协议的邮箱已经很少了,主流是IMAP,故本系列文章也主要以介绍IMAP协议为主。
imap同样也是直接可以用命令行登录的,下面我们来测试一下,因为目前主流邮件服务商都已经禁用了非安全的143端口,我们直接通过 tls 端口 993 来登录,需要输入的命令行后面添加了注释:
openssl s_client -connect imap.abc.mail:993 -crlf -ign_eof
a login foobar password //输入用户名密码,每个命令前要输入一个 a 作为开始
* CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 UIDPLUS COMPRESS=DEFLATE ENABLE MOVE CONDSTORE ESEARCH UTF8=ACCEPT LIST-EXTENDED LIST-STATUS LITERAL- SPECIAL-USE APPENDLIMIT=35651584
a OK foorbar@abc.mail authenticated (Success)
a list "" * //列出所有的邮箱
* LIST (\HasNoChildren) "/" "Call log"
* LIST (\HasNoChildren) "/" "INBOX"
* LIST (\HasNoChildren) "/" "Notes"
* LIST (\HasNoChildren) "/" "SMS"
* LIST (\HasNoChildren) "/" "Sent"
a OK Success
a select inbox //选择inbox收件箱
* FLAGS (\Answered \Flagged \Draft \Deleted \Seen $Forwarded $NotPhishing $Phishing Old)
* OK [PERMANENTFLAGS (\Answered \Flagged \Draft \Deleted \Seen $Forwarded $NotPhishing $Phishing Old \*)] Flags permitted.
* OK [UIDVALIDITY 5] UIDs valid.
* 6901 EXISTS
* 0 RECENT
* OK [UIDNEXT 6934] Predicted next UID.
* OK [HIGHESTMODSEQ 463331]
a OK [READ-WRITE] inbox selected. (Success)
上述命令使用用户名+专用密码登录,列出邮箱列表,并选择了inbox邮件箱。imap 命令比较多,这里就不一一列举了,详细命令可参考附件列表里的资料。smtp和imap的telnet(openssl)命令都非常重要,需要熟练掌握,这是我们后续自建服务器进行调试的重要手段。
关于端口号
从上面的介绍大家也可以看出来,由于电子邮件存在的历史非常长,使用的端口号也经历了不少阶段,导致看起来有些混乱。最早大家都是明文传输,smtp使用25,imap使用143,还比较清楚。后来随着互联网的发展,大家意识到不能在网上裸奔了,加密很重要,于是诞生了smtps(465),imaps(993),这两个端口使用的是ssl协议。再后来ssl协议也被淘汰了,取而代之的是tls协议,配套开发了starttls协议,可以复用原来的明文端口,即可以先连接smtp的25端口,根据服务端是否支持starttls,再判断是否启用加密连接,相对更加灵活。同时,由于25端口被客户端广泛用于发送垃圾邮件,所以客户端(MUA)的starttls端口被定义成了587端口。再后来,大家又觉得其实端口不是重点,tls加密才是最重要的,所以现在的465和993都是同时支持ssl/tls的(ssl基本已不再使用),不管使用starttls还是普通tls,加密级别和安全性都是一样的。
SMTP服务器分类
- 发件服务器:这个就是我们通常意义上了解的smtp服务器,域名形式通常为 smtp.域名,如smtp.163.com,smtp.gmail.com等,普通用户接触最多的是这类服务器,邮件客户端里面配的一般也是这个地址。作用是接收邮件客户端发送过来的邮件,并转发到其他的邮件服务器中。早期使用的是25端口,近年来随着安全传输要求的不断提升,一般25端口已被禁用,以使用465(SSL/TLS)及587(STARTTLS)端口为主。为防止垃圾邮件的发送,通常都会做发件人的身份验证,认证通过后 smtp 服务器才会允许以该发件人身份向其他邮件服务器发送邮件。
- 收件服务器:一般叫 Mail Exchanger,MX服务器,地址可通过查询 dns 的mx记录获取。一般只是在邮件服务商之间传输邮件时用到,普通用户接触不多。MX服务器通常只开通25端口,上面既可以跑明文流量,也可以跑加密流量(通过starttls命令声明进行加密传输)。MX服务器一般会校验,收件人地址是本地用户,才会接收。同时,由于是MTA之间的传输,MX一般也会对发送方的MTA进行严格校验(还记得文章开头收邮件失败吗?),具体方式有SPF、DKIM、DMARC、rDNS等,后续在讲邮件身份认证时会讲到。
一般来说,出于职责权限划分及处理性能的考虑,大的邮件服务商都会把收件服务器和发件服务器分开单独部署。自建的小站,用户也没几个,合并部署问题也不大。
参考资料
1、SMTP协议介绍
https://blog.csdn.net/qq_35644234/article/details/68961603
2、测试imap服务器命令详解
https://blog.csdn.net/sinat_37213335/article/details/88291078
3、细说电子邮件的端口号
https://taoshu.in/email-ports.html