搭建邮件服务器(1) – 邮件系统简介

近期QQ邮箱逐渐关闭域名邮箱功能,不能继续给域名邮箱增加账户了。于是想着换一家邮箱服务提供商。但是转至网易邮箱吧,发现总是给我发官方的垃圾邮件(广告);转至其他邮箱服务商吧,又要收托管费,或者是免费多少封邮件。总之总觉得不靠谱。于是寻思着自己搭一个邮件服务器。

以前我也尝试着搭建过邮箱服务器。但是折腾了一通后,发现统统被当成垃圾邮件拦截了下来(甚至没进“垃圾邮件”收件箱,而是直接在发信的时候拦截了)。这次趁着假期,好好研究了一下基于Postfix的邮件服务器,也算是搞定了基本的邮件配置,这里决定写几篇文章,详细阐述一下Postfix、Dovecot等的配置。

1 邮件系统组成

首先明白几个名词:MUA、MTA、MDA。

MUA,Mail User Agent,指的是邮件客户端,是运行在用户电脑手机等终端设备的应用程序,用户通过MUA与邮件服务器联系以收取或者发送邮件。
MTA,Mail Transfer Agent,指的是发送或者转发邮件的服务器。可以把它看成一个邮件的中转站,接受到什么邮件,就会根据自己的配置发出去。(就像网络中的路由器,受到数据包后就根据路由表发往不同网口)
MDA,Mail Deliver Agent,指的是暂存或者存储邮件的服务器,也是邮件的终点站。邮件到达这个服务器后就等待MUA连接读取。

常见的MUA有Foxmail, Outlook, 手机的“电子邮件”应用程序等,MTA有Postfix, Sendmail等,MDA有Dovecot等。

一般来说,邮件系统就是使用这三种服务构成的系统。下面来看看他们是如何工作的。

2 邮件系统工作流程

2.1 发件流程

让我们从一个例子开始。若用户从QQ邮箱网页版向Gmail发送邮件,那么邮件的传递流程是这样的:

MUA(网页邮箱)->MTA(mail.qq.com)->MTA(gmail.com)->MDA

用户在MUA编辑邮件,比如说QQ邮箱网页版。用户点击“发送”后,邮件将直接被送往QQ邮箱的MTA,然后QQ邮箱的MTA根据发往的地址,便将邮件转发到如gmail.com的MTA服务器。gmail收到邮件后发现目的账户是自己,就将邮件转交给gmail的MDA,进入用户信箱。

邮件系统中也可使用多个MTA。如Outlook邮件服务可以有很多个邮箱域名(outlook.com, live.com, office.com等),于是可用多个MTA分流邮件:

MTA(分流) -> MTA For outlook.com -> MDA
          \-> MTA For live.com -> MDA
           \-> MTA For office.com -> MDA

2.2 收件流程

收件流程包括两个部分:邮件送达MDA和MUA收取邮件。

邮件送达MDA正如上面发件流程所述,发送方通过MUA编辑邮件,经过MTA传输,送达MDA。

随后需要接收方用户主动登陆邮箱收取信件。MUA登陆MDA下载信件,用户即可在MUA上阅读邮件。

MUA(网页邮箱)<-MDA(mail.qq.com)

整个邮件的工作流程也正如传统的信件投递,发件方写好信件后投至邮桶,结果一级级的转发投递,最终到达收件方的邮箱,最后收件方主动查看邮箱,获得邮件。总体流程如下:

发件者MUA->MTA->...->MTA->MDA<-MUA收件者

3 相关协议

3.1 SMTP协议

我们已经知道了邮件的收发流程,下面我们来讨论一些技术细节,这些知识在调试邮件服务器是非常有用。

SMTP,Simple Mail Transfer Protocol,是发送邮件使用的标准协议,是所有的邮件服务提供商都支持的。SMTP使用TCP25端口。发件方MTA主动连接接收方MTA的TCP25端口,使用Telnet协议在接收方MTA服务器上打开一个远程终端,进行命令和数据的交互。可以尝试连接outlook邮件服务器的MTA:

3.1.1 尝试连接一个MTA服务器

telnet apc.olc.protection.outlook.com 25

执行命令后,输出如下:

可见连接成功,系统提示退出字符为“^]”,即Ctrl+]。我们输入这个字符,即可回到telnet命令行,输入q并回车可断开连接并退出:

下面让我们学习一些发邮件的常用命令。

3.1.2 尝试使用Telnet给自己发送一封邮件

尝试输入以下命令,实现从test@localhost向xxx@xxx.com发一封邮件:

EHLO localhost
MAIL FROM: <test@localhost>
RCPT TO: <你自己的邮箱@xxx.com>
DATA
Subject: test mail
A test mail sent by myself.
.

EHLO后面跟的是你的发件服务器的域名,MAIL FROM后写发件人,RCPT TO后写收件人,DATA指令回车后便可输入数据,以一个点结束数据内容。一个信件中的数据可包含Subject标题等二级数据域。

首先可以试试Outlook邮箱:

Outlook邮箱禁止了我的IP发送信件

可以看到命令还没有完成,Outlook就终止连接了,原因是我的IP在黑名单中。事实上一般邮箱服务器都不允许家庭宽带用户直接发送邮件,否则若允许匿名且伪造身份发送邮件,会造成垃圾邮件泛滥。

再试试Gmail:

➜  ~ telnet gmail-smtp-in.l.google.com 25               
Trying 108.177.97.27...
Connected to gmail-smtp-in.l.google.com.
Escape character is '^]'.
220 mx.google.com ESMTP r18si1866308pjo.173 - gsmtp
EHLO localhost
250-mx.google.com at your service, [183.xxx.xxx.xxx]
250-SIZE 157286400
250-8BITMIME
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-CHUNKING
250 SMTPUTF8
MAIL FROM: <test@localhost>
250 2.1.0 OK r18si1866308pjo.173 - gsmtp
RCPT TO: <xxxxxxxx@gmail.com>
250 2.1.5 OK r18si1866308pjo.173 - gsmtp
DATA
354  Go ahead r18si1866308pjo.173 - gsmtp
Subject: test mail
A test mail sent by myself. It is not a spam.
.
421-4.7.0 [183.xxx.xxx.xxx      15] Our system has detected that this message is
421-4.7.0 suspicious due to the very low reputation of the sending IP address.
421-4.7.0 To protect our users from spam, mail sent from your IP address has
421-4.7.0 been temporarily rate limited. Please visit
421 4.7.0  https://support.google.com/mail/answer/188131 for more information. r18si1866308pjo.173 - gsmtp
Connection closed by foreign host.

这次是送完数据才终止连接的。Gmail说我的IP信任度不够,不能送件。

同样地,使用Postfix这类服务发件时,也可能出现这些状况,相应地,Postfix也会详细记录这些状况。比如说以下日志:

日志结果与上面Gmail的回应是一样的,在DATA命令结束后,Gmail返回了这么一段话,表示发件地址发件频率太高而被禁止。

所以通过以上比较,可以发现:家庭宽带是不能作为邮件服务器的,因为已经被列入了黑名单中;选择合适的服务提供商是非常必要的,如上面日志的机器的VPS提供商的网段都在黑名单中。

还有,一些因特网服务提供商会禁止出方向TCP25端口的连接以防止从他们的网段发送垃圾邮件。如果你在运行telnet指令时许久没有反应,可能就是因为这个原因。一些服务提供商可能也提供解封申请服务(如AWS)。对于需要提供解封申请的服务商可能往往更好,因为他们的网段信任度更高。

3.1.3 SMTPS加密

SMTP可启用两种加密方式:一种是全SSL/TLS加密,一种是STARTTLS加密。

全TLS加密使用TCP465端口,MTA直接建立加密连接,而STARTTLS使用TCP587端口,在连接时使用STARTTLS命令开始加密连接。STARTTLS方式的SMTP协议又叫Submission。Postfix中可能需要进行额外的配置才能启用Submission(后面介绍)。

3.2 POP3和IMAP收件协议

POP3和IMAP协议就不作过多介绍了,无非是用户拉取下载邮件的方式。IMAP协议更加新,且支持多种文件夹,所以一般建议使用IMAP协议。POP3和IMAP也均有加密支持。Exchange是微软的一套协议,这里不作介绍。

明文协议端口加密协议端口
POP3110POP3S995
IMAP143IMAPS993
POP3和IMAP端口表

4 MX记录

在上面一节,实验连接Telnet的时候,你是否有个疑问:为什么不是连接gmail.com, outlook.com这些邮箱域名的呢?为什么连接的是gmail-smtp-in.l.google.com这些奇怪的长长的域名?

我们一般不直接使用邮箱的域名作为邮件服务器,因为这样做太死板且不利于分流(如Outlook这种有多个域名的邮件服务提供商)。对于邮箱中域名,我们往往对其设置一个MX记录,指向这个域名的MTA服务器。

MX记录还包括一个权重值,权重值越小越优先。MTA向对方MTA发件时,先连接权重值小的服务器,若连接失败,则尝试连接下一个权重的服务器。

如上图为Gmail的MTA服务器,若要向xxx@gmail.com发送邮件,将首先尝试连接gmail-smtp-in.l.google.com服务器,如果连接失败,将依次尝试alt1, alt2, alt3, alt4.

有了MX记录后,还需要为这条MX记录的域名创建A或者AAAA记录,这样其他人才能使用SMTP协议,通过IP地址连接到邮件服务器。

总的来说,再具体一些,发件过程如下:

  1. 用户xxx@example.com通过MUA,使用SMTP协议连接到example.com的MTA(由邮箱服务商提供具体配置),收件人为xxx@gmail.com;
  2. example.com的MTA查找gmail.com的MX记录,选择优先级最低那个记录,得到gmail-smtp-in.l.google.com;
  3. example.com的MTA查找gmail-smtp-in.l.google.com的IP地址(A记录或者AAAA记录),得到64.233.188.26;
  4. example.com的MTA尝试向64.233.188.26发起连接,若连接失败,选择下一优先级的MX记录,重复2-3;
  5. 若连接成功,即使用相关命令发送邮件。

发表评论