详解电子邮件系统系列之二:SMTP、IMAP协议介绍

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 协议的,下面是命令和应答清单:


smtp命令和应答

感觉和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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容