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格式数据。
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格式数据。
相关文章推荐
- 利用 Composer 一步一步构建自己的 PHP 框架(四)——使用 ORM
- thinkphp框架3.2的cookie删除问题记录
- 利用 Composer 完善自己的 PHP 框架(二)——发送邮件
- PHP 二维数组根据某个字段排序
- phpcms 调用全站最新发布数据
- 利用 Composer 完善自己的 PHP 框架(一)——视图装载
- php正则表达式匹配img中任意属性的方法
- PHP的Yii框架中Model模型的学习教程
- php ajax异步读取rss文档数据
- 详解PHP的Yii框架中的Controller控制器
- YII2.0使用ActiveForm表单
- php高级变量
- 3.2 Zend_Db_Select
- 详解PHP匿名函数与注意事项
- php 读正在写的文件
- php ajax实现文件上传进度条
- php $_SESSION会员登录实例分享
- 独立主机配置FTP,解析域名经历
- PHP中CURL方法curl_setopt()函数的一些参数
- TinkPHP+WAMP