您的位置:首页 > 编程语言 > PHP开发

1.1 smtp协议及其扩展

2016-03-29 15:59 736 查看
smtp是电子邮件核心协议,它是收发信协议(pop3和imap是“取信”协议)。该协议是文本协议——这个设计导致了它便于阅读,同时也必须对二进制数据进行文本编码(MIME)。

RFC821smtp协议诞生于1982年,简单的smtp会话过程如下所示(见图1-5):



图1-5 一次简单的smtp会话

下面我们简要介绍一下大体过程,完整的smtp命令在下节列出。

1 登录服务器后,先用HELO或EHLO(esmtp协议)命令向服务器报告自身主机名。HELO或EHLO命令的参数是自身主机名。该命令可以忽略,但是如果使用了该命令,则主机名不能忽略,但一般可以随意填写,服务器会采用其他方式得到客户机信息。服务器可能在HELO/EHLO命令处设置了ACL策略,所以提供主机名时也要考虑到是否有可能被该策略屏蔽。

使用EHLO命令可以得到服务器对该客户机的功能支持列表(postfix可以设置对不同的客户开启不同的功能支持),见图1-6:



图1-6 服务器为EHLO命令返回的特性支持列表
服务器如果接受了客户机请求,则给出250欢迎代码。在这个过程中,服务器可能会对客户机资格做验证,排查恶意(如ddos攻击等)访问。

2 MAIL FROM命令声明发件人。RFC821格式的邮件地址规定的收发件人格式应该加上尖括号,类似于<zhangsan@localhost>,但postfix可以接受RFC822格式的邮件地址,该格式不强制给邮件地址加上尖括号,所以如果在不同的资料上看到命令行上有的邮件地址加上了尖括号,有的没加,那不用纠结这个问题,具体是否严格采用RFC821格式由服务器来决定,用户基本都会用邮件客户端发信,不会碰到这个问题。

3 RCPT TO命令声明收件人。一条RCPTTO命令可以指定一个收件人,所以如果要给zhangsan和lisi发邮件,是没有rcpt to:zhangsan,lisi这样的写法的,只能分别写成

rcpt to:zhangsan

rcpt to:lisi

MAIL和RCPT命令可以有扩展参数,详情见下节。这里收发件人只写了zhangsan和lisi,没有写出完整的邮件地址,这可以吗?手工书写的地址总是有可能不完整,不论是在命令行交互还是在配置文件中。postfix考虑到了这点,其trivial-rewrite模块会将地址重写为本地完整地址。

4 DATA命令开启了邮件传输,该命令只有这一行,回车后开始输入邮件内容。smtp协议并没有规定邮件内容,也就是没有规定哪些部分是标题,哪些部分是邮件正文,哪些收件人是抄送或密送的,RFC822协议可以区分这些内容。邮件客户端软件会生成这些不同的邮件部分。邮件内容输入完成后,以一个单行的点号结束,最后输入QUIT命令结束会话。

邮件协议并不止smtp一种,还有X.400等。但smtp这个简单的协议最终获得了流行。

RFC 821 (SMTPprotocol),RFC 1869 (SMTP service extensions),RFC 2821 (SMTPprotocol),RFC 5321 (SMTP protocol):这些是smtp/esmtp协议本身。smtp协议经过1982年的RFC 821、1995年的RFC1869esmtp协议、2001年的RFC 2821,目前最新的是2008年的RFC 5321标准。esmtp为smtp提供了验证支持。

smtp协议使用标准七位ascii码,可以表示127个字符。

由于smtp是文本协议,如果要提供二进制数据(附件),需要将其转化为文本。MIME(多功能Internet邮件扩充服务)编码用来完成这个工作。MIME有着较为复杂的格式,其Content-Type首部可以指出媒体类型:Text、image、audio、video、application、multipart、message等。MUA可以根据媒体类型进行解码。

smtp协议规定邮件地址要写在尖括号内。但保存邮件信息的RFC822协议没有这个规定。postfix不强制要求参与smtp会话的客户端严格遵守RFC 821的尖括号限定。参数strict_rfc821_envelopes用于设定邮件地址是否严格遵守RFC 821限定,默认为no。

smtp协议的确是一个“简单“的协议:只定义了11条命令,必须实现其中的9条。每条命令没有多于两个的参数——但是还有各种扩展协议,这也导致了实现完整smtp协议的复杂性。smtpd.c开头的注释中所列出的postfix实现的相关扩展协议如下:

/* STANDARDS
/* RFC821 (SMTP protocol)
/* RFC1123 (Host requirements)
/* RFC1652 (8bit-MIME transport)
/* RFC1869 (SMTP service extensions)
/* RFC1870 (Message size declaration)
/* RFC1985 (ETRN command)
/* RFC2034 (SMTP enhanced status codes)
/* RFC2554 (AUTH command)
/* RFC2821 (SMTP protocol)
/* RFC2920 (SMTP pipelining)
/* RFC3207 (STARTTLS command)
/* RFC3461 (SMTP DSN extension)
/* RFC3463 (Enhanced status codes)
/* RFC3848 (ESMTP transmission types)
/* RFC4409 (Message submission)
/* RFC4954 (AUTH command)
/* RFC5321 (SMTP protocol)
/* RFC6531 (Internationalized SMTP)
/* RFC6533 (Internationalized Delivery Status Notifications)

下面我们来具体解释一下这些RFC文件的主要内容。

RFC821 (SMTP protocol)、RFC 1869 (SMTP service extensions)、RFC 2821 (SMTPprotocol),RFC 5321 (SMTP protocol):即smtp和esmtp协议。

RFC 1985 (ETRNcommand): ETRN命令支持,该命令可快速清空队列中的邮件(可参考《postfix权威指南》9.1.2节)。

RFC 2554 (AUTHcommand)、RFC 3207 (STARTTLS command)、RFC 4954 (AUTHcommand):定义了AUTH、STARTTLS扩展命令。如果服务器支持STARTTLS,则可进行加密通信。

RFC 1652(8bit-MIME transport):由于smtp协议使用标准七位ascii码,传统上MUA要负责将发送给MTA的MIME数据转化为base64格式进行发送。base64采用64个基本字符(a-z,A-Z,0-9,+,/)来进行字符编码。如果MTA支持该协议,则MUA可以不将其数据进行base64编码。该协议使得MAIL命令可以有BODY=8BITMIME或BODY=7BIT参数。

RFC 1870(Message size declaration):支持在MAIL命令中增加SIZE参数。

RFC 2034 (SMTPenhanced status codes) 、RFC 3463 (Enhanced status codes):对smtp协议的简单数字状态码的增强。RFC 3463协议定义了新的出错代码,型为X.X.X,X可为多位数字。

RFC 3461 (SMTPDSN extension):smtp协议的DSN扩展。DSN即Delivery Status Notification。当邮件从MUA发送至MTA后,我们并不知道它是否发送成功。MUA软件告诉我们的“邮件已发送成功”意味着邮件已成功发送到自己的MTA,而非收件人。许多用户没有这个概念,认为邮件已经发送给收件人了。这个扩展协议可以让MTA通知我们邮件从MUA发送到MTA之后的状态。一般用户是这样判断邮件发送到MTA后的状态的:默认发送成功,除非收到退信。这个协议定义了MTA到底该如何向MUA通知邮件投递状态。

该协议给MAIL命令和RCPT命令分别增加了两个扩展参数:

给MAIL命令增加了RET(return)和ENVID(envelopidentifier)参数。RET参数有FULL或HDRS两个选项,表示返回原信或只返回信头。RFC 3461规定ENVID参数值必须为assicc可打印字符,即asicc除去控制字符外的95个字符。该项主要由MUA使用。

给RCPT命令增加了NOTIFY和ORCPT两个命令。

NOTIFY命令用来定义何时发送回执:有SUCCESS(投递成功时发送)、FAILER(投递失败时发送)、DELAY(投递延时时发送)、NEVER(从不发送)4个选项。即便客户不指定FAILER选项,postfix也会为不可投递的邮件给客户发送退信。如果设定了delay_warning_time参数,则postfix会根据此选项为用户发送邮件延迟信息,此项默认未开启。除非用户明确设置了SUCCESS选项,否则postfix不为用户发送投递成功的通知信件。

ORCPT可以指定原始收件人。该参数由分号分隔的两部分构成:一部分是邮件协议:smtp、X.400等,另一部分是收件人地址。该参数记录了未经转换的原始收件人地址样式。

RFC 2920 (SMTPpipelining):smtp协议流水线支持如下方式的smtp协议以提高通信效率,下面是RFC文档上的例子:

不使用RFC2920支持的情况:

C: MAIL FROM:<mrose@dbc.mtview.ca.us>

S: 250 sender <mrose@dbc.mtviewca.us>OK

C: RCPT TO:<ned@innosoft.com>

S: 250 recipient <ned@innosoft.com> OK

C: RCPT TO:<dan@innosoft.com>

S: 250 recipient <dan@innosoft.com> OK

C: RCPT TO:<kvc@innosoft.com>

S: 250 recipient <kvc@innosoft.com> OK

C: DATA

S: 354 enter mail, end with line containingonly "."

使用RFC2920支持的情况:

C:MAIL FROM:<mrose@dbc.mtview.ca.us>

C: RCPT TO:<ned@innosoft.com>

C: RCPT TO:<dan@innosoft.com>

C: RCPT TO:<kvc@innosoft.com>

C: DATA

S: 250 sender <mrose@dbc.mtview.ca.us>OK

S: 250 recipient <ned@innosoft.com> OK

S: 250 recipient <dan@innosoft.com> OK

S: 250 recipient <kvc@innosoft.com> OK

S: 354 enter mail, end with line containingonly "."

可见如果服务器支持RFC2920,则MUA可以将多个收件人地址一次发送给服务器。

该文档的3.1节规定了EHLO、DATA、VRFY、 EXPN、 TURN、 QUIT、 NOOP命令只能出现在流水线尾:

The EHLO, DATA,VRFY, EXPN, TURN,QUIT, and NOOP commands can only appear as the last command ina group since their success or failure produces a change of state which theclient SMTP must accommodate

5.6.8节将对这个规定进行判断。

RFC6531 (Internationalized SMTP),RFC 6533 (Internationalized Delivery Status Notifications):支持smtp协议的SMTPUTF8格式数据。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: