才发现竟然可以用telnet来和SMTP服务器交互.MS的SMTM 服务器还提供命令行交互的界面。
而HTTP的SERVER也是一样可以用TELNET来操作的,只是没有命令行回显。
使用Telnet进行SMTP//POP3//FTP//NNTP [2]
在这个系列的文章中,我引用了Richard Stevens的内容,向伟大的Richard
Stevens致敬!
[2] SMTP
介绍SMTP之前,先要知道什么是MTA。用TCP进行的邮件交换是由报文传送代理MTA
(Message Transfer Agent)完成的。RFC 821[Postel 1982]规范了SMTP协议,指定了
在一个简单TCP连接上,两个MTA如何进行通信。RFC 822[Crocker 1982]指定了在两个
MTA之间用RFC 821发送的电子邮件报文的格式。
两个MTA之间用NVT ASCII进行通信。客户向服务器发出命令,服务器用数字应答码
和可选的人可读字符串进行响应。客户只能向服务器发送很少的命令:基本的不到12个
(相比较而言,FTP超过40个)。我们用简单的例子说明发送邮件的工作过程,并不仔
细描述每个命令。
当你需要连接一个SMTP服务器,你可以使用如下的命令行,这里使用“]”表示终
端显示,下面如没有特殊说明,都可认为如此表示:
] telnet <ip address/hostname> 25
如果系统使用知名端口列表映射,则可以使用下面的命令行:
] telnet <ip address/hostname> smtp
我们连接SMTP服务器:
] telnet smtp.microsoft.com smtp
如果连接成功,服务器会返回如下信息:
] 220 smtp.microsoft.com Microsoft ESMTP MAIL Service, Version:
5.0.2195.6713 ready at Sun, 4 Jan 2004 08:43:53 +0800
客户主动打开TCP端口25。返回时,客户等待从服务器来的问候报文(应答代码为
220)。该服务器的应答必须以服务器的完全合格的域名开始:本例中为microsoft.com
(通常,跟在数字应答后面的文字是可选的。这里需要域名。这里的服务器名仅用作示
例,实际上是无法连接的。)。
为了方便下面的介绍,我们使用一个Help命令列出当前服务器的可用命令列表,但
是请注意,Help命令不是服务器必须提供的。
] help
214-This server supports the following commands:
214 HELO EHLO STARTTLS RCPT DATA RSET MAIL QUIT HELP AUTH TURN ATRN ETRN
BDAT VRFY
可以看到,服务器返回了响应码214以及支持的SMTP命令。最小的SMTP命令集包含8
个命令:HELO,MAIL,RCPT,DATA,QUIT,RSET,VRFY,NOOP。后面我们还将看到扩展
的SMTP命令。
下一步客户用HELO命令标识自己。参数必须是完全合格的的客户主机名,这里同样
使用一个例子:haohu.jforce.net。
] helo haohu.jforce.net
250 smtp.microsoft.com Hello [10.0.0.5]
服务器返回响应码250,以及客户的IP地址。许多SMTP服务器得到客户的IP地址,
完成一个DNS指针查询并比较主机名。这样允许服务器基于IP地址注册到客户的连接,
而不是基于用户可能错误键入的名。某些服务器会用幽默的报文回答,如“你是一个骗
子”,或“为什么叫你自己..”。在这个例子中我们看到,这个Exchange Server服务
器通过指针查询只打印出我们的IP地址,当然如果你是管理员的话你可以进行修改,但
在这里我们不讨论这个问题。
MAIL命令标识出报文的发起人。
] mail from:<haohu@microsoft.com>
250 2.1.0 haohu@microsoft.com....Sender OK
服务器允许当前用户使用SMTP服务的话,会回应响应码250以及sender ok的消息,
至于SMTP发信验证,我们暂时不加讨论。
下一个命令,RCPT,标识接收方。如果有多个接收方,可以发多个RCPT命令。
] rcpt to:<haohu_cn@hotmail.com>
250 2.1.5 haohu_cn@hotmail.com
同样,服务器响应代表命令成功的响应码250。
邮件报文的内容由客户通过DATA命令发送。报文的末尾由客户自行指定,是只有一
个句点的一行。
] data
354 Start mail input; end with <CRLF>.<CRLF>
test mail
.
250 2.6.0 <SMTPYjIPj8jvovSYbn00000001@smtp.microsoft.com> Queued mail for
delivery 服务器返回响应码354表示开始接受邮件正文。我们输入测试的邮件正文
:test mail。按照服务器的提示,此处实际是以<CRLF>.<CRLF>作为邮件的结束的。可
以看到服务器在结束邮件输入后返回响应码250表示成功。同时产生一个邮件的MsgID,
并将其列入邮件发送队列。关于MsgID,可以看看NNTP中的介绍。
最后的命令QUIT,结束邮件的交换。
]quit
这将断开使用Telnet建立的连接。
RSET命令异常中止当前的邮件事务并使两端复位。丢掉所有有关发送方、接收方或
邮件的存储信息。
VRFY命令使客户能够询问发送方以验证接收方地址,而无需向接收方发送邮件。通
常是系统管理员在查找邮件交付差错时手工使用的。如果服务器支持的话,我们可以用
一个无效的名字键入VRFY命令,服务器就响应550差错。如果键入一个有效的名字,服
务器用本地主机上的用户名回答。然后我们试试EXPN命令,可以得到一个不同的回答。
EXPN命令决定到该用户的邮件是否被转发,并打印出转发的地址。许多站点禁止VRFY和
EXPN命令,有时是因为隐私,有时因为相信这是安全漏洞。
NOOP命令除了强迫服务器响应一个OK应答码(200)外,不做任何事情。
EXPN扩充邮件表,与VRFY类似,通常是由系统管理员使用的。
TURN命令使客户和服务器交换角色,无需拆除TCP连接并建立新的连接就能以相反
方向发送邮件。其他还有三个很少被实现的命令(SEND、SOML和SAML)取代MAIL命令。
这三个命令允许邮件直接发送到客户终端(如果已注册)或发送到接收方的邮箱。
电子邮件由三部分组成:
1) 信封(envelope)是MTA用来交付的。在我们的例子中信封由两个SMTP命令指明
:
] MAIL From: <haohu_cn@hotmail.com.>
] RCPT To: <mylover@anywhere.net>
RFC 821指明了信封的内容及其解释,以及在一个TCP连接上用于交换邮件的协议。
2) 首部由用户代理使用。我们看看在前面发送的邮件头部信息:
] Microsoft Mail Internet Headers Version 2.0
Received: from ([10.0.0.5]) by smtp.microsoft.com with Microsoft
SMTPSVC(5.0.2195.6713);
Sun, 4 Jan 2004 09:03:55 +0800
From: haohu@microsoft.com
Bcc:
Return-Path: haohu@microsoft.com
Message-ID: <SMTPYjIPj8jvovSYbn00000001@smtp.microsoft.com>
X-OriginalArrivalTime: 04 Jan 2004 01:04:12.0441 (UTC)
FILETIME=[AA6B1890:01C3D25E] Date: 4 Jan 2004 09:04:12 +0800
在我们的例子中可以看到6个首部字段:Received、From、Bcc、
Return-Path(Reply-To)、Message-Id、X-OriginalArrivalTime。这是没有输入邮件头
直接发送而得到的,例子基于Exchang Server 2000。根据发信时的不同方式,邮件头部
的字段是不一样的。每个首部字段都包含一个名,紧跟一个冒号,接着是字段值。RFC
822指明了首部字段的格式的解释(以X-开始的首部字段是用户定义的字段,其他是由
RFC 822定义的)。长首部字段,如例子中的Received,被折在几行中,多余行以空格
开头。此处的例子是在Sun处重新开始一行。
3) 正文(body)是发送用户发给接收用户报文的内容。RFC 822指定正文为NVT
ASCII文字行。当用DATA命令发送时,先发送首部,紧跟一个空行,然后是正文。用
DATA命令发送的各行都必须小于1000字节。用户接收我们指定为正文的部分,加上一些
首部字段,并把结果传到MTA。MTA加上一些首部字段,加上信封,并把结果发送到另一
个MTA。内容(content)通常用于描述首部和正文的结合。内容是客户用DATA命令发送
的。
由于电子邮件的用处越来越广泛,原有的命令、编码等不敷使用。于是RFC对其做
了扩充。对于支持扩充部分的MTA(比如我们用以作例子的邮件服务器),可以使用命
令EHLO来显示其扩充的命令列表。
] ehlo
250-smtp.microsoft.com Hello [10.0.0.5]
250-TURN
250-ATRN
250-SIZE
250-ETRN
250-PIPELINING
250-DSN
250-ENHANCEDSTATUSCODES
250-8bitmime
250-BINARYMIME
250-CHUNKING
250-VRFY
250-X-EXPS GSSAPI NTLM LOGIN
250-X-EXPS=LOGIN
250-AUTH GSSAPI NTLM LOGIN
250-AUTH=LOGIN
250-X-LINK2STATE
250-XEXCH50
250 OK
可以看到,对EHLO命令的250应答中列出许多扩充命令。有一些来自原来的RFC 821
规范,但它们是可选命令。ESMTP服务器说明除了新命令外,它们还支持哪些可选的RFC
821命令。这个服务器支持的SIZE关键字是在RFC 1427[Klensin, Freed和Moore 1993]
中定义的。它让客户在MAIL FROM命令行中以字节的多少指定报文的大小,这样服务器
就可以在客户开始发送该报文之前,验证它是否接收该长度的报文。增加这个命令的原
因在于,随着对非ASCII码(如图像、音频等)内容的支持,Internet邮件报文的长度
在不断增大。
关键字8BITMIME来自于RFC 1426[Klensin等,1993a]。它允许客户把关键字BODY加
到MAIL FROM命令中,指定正文中是否包含NVT ASCII字符(默认的)或8 bit数据。除
非客户收到服务器应答EHLO命令发来的8BITMIME关键字,否则禁止客户发送任何非NVT
ASCII字符(当我们在本节中谈到MIME时,我们将看到MIME不要求8 bit传送)。任何以
X开头的关键字都指的是本地SMTP扩充。
RFC 1522[Moore 1993]指明了一个在RFC 822报文首部中如何发送非ASCII字符的方
法。这样做的主要用途是为了允许在发送方名、接收方名以及主题中使用其他的字符。
首部字段中可以包含编码字(coded word)。它们具有以下格式:
=?charset?encoding?encoded-text?=
charset是字符集规范。有效值是两个字符串us-ascii和iso-8859-x,其中x是一个
单个数字,例如在iso-8859-1中的数字“1”。encoding是一个单个字符用来指定编码
方法,支持两个值。我们可以在很多的邮件看到没有解码信息里包括着这种内容。
1)Q编码意思是引号中可打印的(quoted-printable),目的是用于拉丁字符集。
大多数字符是作为NVT ASCII(当然最高位比特置0)发送的。任何要发送的字符若其第
8比特置1则被作为3个字符发送:第1个是字符是“=”,跟着两个十六进制数。例如,
字符é(它的二进制8bit值为0xe9)作为三个字符发送:=E9。空格通常作为下划线或
三个字符=20发送。这种编码的目的在于,某些文本中除了大多数ASCII字符外,还有几
个特殊字符。
2)B意思是以64为基数的编码。文本中的3个连续字节(24bit)被编码成4个6 bit
值。用于表示所有可能的6bit值的64个NVT ASCII字符如下表所示。当要编码的个数不
是3的倍数时,等号符“=”被用作填充符。下面列出Base64的码表:
_____________________________________
6Bit 0 1 2 3 4 5 6 7
ASCII A B C D E F G H
-------------------------------------
6Bit 8 9 a b c d e f
ASCII I J K L M N O P
-------------------------------------
6Bit 10 11 12 13 14 15 16 17
ASCII Q R S T U V W X
-------------------------------------
6Bit 18 19 1a 1b 1c 1d 1e 1f
ASCII Y Z a b c d e f
-------------------------------------
6Bit 20 21 22 23 24 25 26 27
ASCII g h i j k l m n
-------------------------------------
6Bit 28 28 2a 2b 2c 2d 2e 2f
ASCII o p q r s t u v
-------------------------------------
6Bit 30 31 32 33 34 35 36 37
ASCII w x y z 0 1 2 3
-------------------------------------
6Bit 38 39 3a 3b 3c 3d 3e 3f
ASCII 4 5 6 7 8 9 + /
-------------------------------------
RFC 822指定正文是NVT ASCII文本行,没有结构。RFC 1521[Borenstein和Freed
1993]把扩充定义为允许把结构置入正文。这被称为MIME,即通用Internet邮件扩充。
MIME不要求任何扩充,我们在本节前面已作了说明(扩充的SMTP或非ASCII标题)。
MIME正好加入了一些告知收件者正文结构的新标题(与RFC 822相一致)。正文仍可以
用NVT ASCII码来发送,而不考虑邮件内容。虽然我们前面所述的一些扩充可能会和
MIME合在一起产生好的效果—扩充的SMTP SIZE命令,因为MIME报文能变得很长,以及
非ASCII标题—这些扩充并不是MIME所要求的。与另一方交换MIME报文所需的一切,就
是双方都要有一个能够理解MIME的用户代理。在任何一个MTA中不需要做任何改变。
MIME定义这5个新标题字段如下:
Mime-Version:
Content-Type:
Content-Transfer-Encoding:
Content-ID:
Content-Description:
Text是MIME的7个被定义的内容类型之一。下表总结了RFC 1521中定义的16个不同
的内容类型和子类型。对具体的内容类型和子类型来说都有指定的很多参数。
内容类型 子类型 描述
text plain 无格式文本
richtext 简单格式文本,如粗体、斜体或下划线等
enriched richtext的简化和改进
multipart mixed 多个正文部分,串行处理
parallel 多个正文部分,可并行处理
digest 一个电子邮件的摘要
altenative 多个正文部分,具有相同的语义内容
message rfc822 内容是另一个RFC 822邮件报文
partial 内容是一个邮件报文的片断
external-body 内容是指向实际报文的指针
application octet-stream 任意二进制数据
postscript 一个PostScript程序
image jpeg ISO 10918格式
gif CompuServe的图形交换格式
audio basic 用8 bit ISDN μ律格式编码
video mpeg ISO 11172格式
内容类型和用于内容的传送编码是相互独立的。前者由首部字段Content-Type指
明,后者由首部字段Content-Transfer-Encoding指明。在RFC 1521中定义了5种不同的
编码格式。
1)7bit,是默认的NVT ASCII;
2)quoted-printable,我们在前面的一个例子中看到有非ASCII首部。当字符中只
有很少一部分的第8bit置1时非常有用;
3)base64,如上面的编码表所示;
4)8bit,包含字符行,其中某些为非ASCII字符且第8bit置1;
5)binary编码,无需包含多行的8bit数据。
对RFC 821 MTA,以上5种编码格式中只有前3种是有效的。因为这3种产生只包含
NVT ASCII字符的正文。使用有8BITMIME支持的扩充SMTP允许使用8bit编码。尽管内容
类型和编码是独立的,RFC 1521推荐有非ASCII数据的text使用quoted-printable,而
image、audio、video和octet-stream application 使用base 64。这样允许与符合RFC
821的MTA保持最大的互操作性。而且,multipart和message内容类型必须以7bit编码。
MIME的详细细节和例子,见RFC 1521和[Rose1993]。
DNS中的一种资源记录类型是邮件交换记录,称为MX记录。可以使用MX记录向不直
接连到Internet的主机发送邮件。RFC 974[Partridge 1986]描述了MTA对MX记录的处
理。通过DNS服务器,MTA可以发现目的主机的MX记录,在有多个MX记录的情况下,使用
具有低优先级数值的MX记录。
由于系统的多样性,MTA与DNS之间的交互随不同的实现而不同。RFC 974指定MTA必
须首先要求MX记录,如果没有,就尝试提交给目的主机(也就是说,向DNS要主机的记
录和IP地址)。MTA也必须处理DNS中的CNAME记录(规范的名)。MX记录的另一个用途
是在目的主机出故障时可提供另一个邮件接收器。这个功能同时也可以实现在使用ADSL
的动态DNS解析中。由于ADSL造成的IP地址的不确定性,我们往往需要后备的邮件服务
器。这时同样可以添加一个MX记录到提供动态域名解析的DNS服务器,使得发往此动态
域名的服务器的邮件优先尝试ADSL的连接,失败后再连接其他的邮件服务器。