SMTP协议通讯模型

  SMTP协议是TCP/IP协议族中的一员,主要对如何将电子邮件从发送方地址传送到接收方地址,也即是对传输的规则做了规定。SMTP协议的通信模型并不复杂,主要工作集中在发送SMTP和接收SMTP上:首先针对用户发出的邮件请求,由发送SMTP建立一条连接到接收SMTP的双工通讯链路,这里的接收SMTP是相对于发送SMTP而言的,实际上它既可以是最终的接收者也可以是中间传送者。发送SMTP负责向接收SMTP发送SMTP命令,而接收SMTP则负责接收并反馈应答。可大致用下面的通讯模型示意图来表示:
 
SMTP协议的命令和应答

  从前面的通讯模型可以看出SMTP协议在发送SMTP和接收SMTP之间的会话是靠发送SMTP的 SMTP命令和接收SMTP反馈的应答来完成的。在通讯链路建立后,发送SMTP发送MAIL命令指令邮件发送者,若接收SMTP此时可以接收邮件则作出OK的应答,然后发送SMTP继续发出RCPT命令以确认邮件是否收到,如果接收到就作出OK的应答,否则就发出拒绝接收应答,但这并不会对整个邮件操作造成影响。双方如此反复多次,直至邮件处理完毕。SMTP协议共包含10个SMTP命令,列表如下:

SMTP命令 命令说明
HELLO <domain> <CRLF> 识别发送方到接收SMTP的一个HELLO命令
MAIL FROM:<reverse-path><CRLF> <reverse-path>为发送者地址。此命令告诉接收方一个新邮件发送的开始,并对所有的状态和缓冲区进行初始化。此命令开始一个邮件传输处理,最终完成将邮件数据传送到一个或多个邮箱中。
RCPT TO:<forward-path><CRLF> <forward-path>标识各个邮件接收者的地址
DATA <CRLF>
接收SMTP将把其后的行为看作邮件数据去处理,以<CRLF>.<CRLF>标识数据的结尾。
REST <CRLF> 退出/复位当前的邮件传输
NOOP <CRLF> 要求接收SMTP仅做OK应答。(用于测试)
QUIT <CRLF> 要求接收SMTP返回一个OK应答并关闭传输。
VRFY <string> <CRLF> 验证指定的邮箱是否存在,由于安全因素,服务器多禁止此命令。
EXPN <string> <CRLF> 验证给定的邮箱列表是否存在,扩充邮箱列表,也常禁止使用。
HELP <CRLF> 查询服务器支持什么命令

注:<CRLF>为回车、换行,ASCII码分别为13、10(十进制)。

SMTP协议的每一个命令都会返回一个应答码,应答码的每一个数字都是有特定含义的,如第一位数字为2时表示命令成功;为5表失败;3表没有完成。一些较复杂的邮件程序利用该特点,首先检查应答码的首数字,并根据其值来决定下一步的动作。下面将SMTP的应答码列表如下:

应答码 说明
501 参数格式错误
502 命令不可实现
503 错误的命令序列
504 命令参数不可实现
211 系统状态或系统帮助响应
214 帮助信息
220 <domain>服务就绪
221 <domain>服务关闭
421 <domain>服务未就绪,关闭传输信道
250 要求的邮件操作完成
251 用户非本地,将转发向<forward-path>
450 要求的邮件操作未完成,邮箱不可用
550 要求的邮件操作未完成,邮箱不可用
451 放弃要求的操作;处理过程中出错
551 用户非本地,请尝试<forward-path>
452 系统存储不足,要求的操作未执行
552 过量的存储分配,要求的操作未执行
553 邮箱名不可用,要求的操作未执行
354 开始邮件输入,以"."结束
554 操作失败

SMTP协议的会话流程

  在进行程序设计之前有必要弄清SMTP协议的会话流程,其实前面介绍的内容已经可以大致勾勒出用SMTP发送邮件的框架了,对于一次普通的邮件发送,其过程大致为:先建立TCP连接,随后客户端发出HELLO命令以标识发件人自己的身份,并继续由客户端发送MAIL命令,如服务器应答为"OK",可继续发送RCPT命令来标识电子邮件的收件人,在这里可以有多个RCPT行,而服务器端则表示是否愿意为收件人接受该邮件。在双方协商结束后,用命令DATA将邮件发送出去,其中对表示结束的"."也一并发送出去。随后结束本次发送过程,以QUIT命令退出。下面通过一个实例,从langrui@sohu.com发送邮件到renping@sina.com来更详细直观地描述此会话流程:

R:220 sina.com Simple Mail Transfer Service Ready
S:HELLO sohu.com
R:250 sina.com
S:MAIL FROM:<langrui@sohu.com>
R:250 OK
S:RCPT TO:<renping@sina.com>
R:250 OK
S:DATA
R:354 Start mail input;end with "<CRLF>.<CRLF>"
S:……
R:250 OK
S:QUIT
R:221 sina.com Service closing transmission channel

邮件的格式化

  由于电子邮件结构上的特殊性,在传输时是不能当作简单的文本来直接处理的,而必须按照一定的格式对邮件头和邮件体进行格式化处理之后才可以被发送。需要进行格式化的部分主要有:发件人地址、收件人地址、主题和发送日期等。在RFC文档的RFC 822里对邮件的格式化有详尽的说明,有关详情请参阅该文档。下面通过VC++6.0按照RFC 822文档规定将格式化邮件的部分编写如下(部分代码):

//邮件头准备
strTemp = _T( "From: " ) + m_strFrom; file://发件人地址
add_header_line( (LPCTSTR)strTemp );
strTemp = _T( "To: " ) + m_strTo; file://收件人地址
add_header_line( (LPCTSTR)strTemp );
m_tDateTime = m_tDateTime.GetCurrentTime();//发送时间
strTemp = _T( "Data: " );
strTemp += m_tDateTime.Format( "%a, %d %b %y %H:%M:%S %Z" );
add_header_line( (LPCTSTR)strTemp );
strTemp = _T( "Subject: " ) + m_strSubject; file://主题
add_header_line( (LPCTSTR)strTemp );
file://邮件头结束
m_strHeader += _T( ""r"n" );
file://邮件体准备
if( m_strBody.Right( 2 ) != _T( ""r"n" ) ) file://确认最后以回车换行结束
m_strBody += _T( ""r"n" );

其中add_header_line(LPCTSTR szHeaderLine)函数用于把szHeaderLine指向的字串追加到m_strHeader后面。其中,格式化后的邮件头保存在m_strHeader里,格式化后的邮件体保存在m_strBody中。

由Socket套接字为SMTP提供网络通讯基础

许多网络程序都是采用Socket套接字实现的,对于一些标准的网络协议如HTTP、FTP和SMTP等协议的编程也是基于套接字程序的,只是端口号不再是随意设定而要由协议来指定,比如HTTP端口在80、FTP是21,而SMTP则是25。Socket只是提供在指定的端口上同指定的服务器从事网络上的通讯能力,至于客户和服务器之间是如何通讯的则由网络协议来规定,这对于套接字是完全透明的。因此可以使用Socket套接字为程序提供网络通讯的能力,而对于网络通讯连路建立好之后采取什么样的通讯应答则要按SMTP协议的规定去执行了。Socket套接字网络编程方面的文章资料非常丰富,限于本文篇幅,在此不再赘述,有关详情请参阅相关文档。为简便起见,没有采用编写较复杂的Windows Sockets API进行编程,而是使用经过较好封装的MFC 的CSocket类。在正式使用套接字之前,也要先用AfxSocketInit()函数对套接字进行初始化,然后用Create()创建套接字对象,并由该套接字通过Connect()建立同邮件服务器的连接。如果一切正常,再后续的工作中就是遵循SMTP协议的约定来使用Send()、Receive()函数来发送SMTP命令和接收邮件服务器发来的应答码以完成对邮件的传送。

 

POP3协议命令原始码及工作原理 
一 简介: 
1. POP适用于C/S结构的脱机模型的电子邮件协议,目前已发展到第三版,称POP3。脱机 模型即不能在线操作,不像IMAP4(netscape支持IMAP4) 
2. 当客户机与服务器连接并查询新电子邮件时,被该客户机指定的所有将被下载的邮件 都将被程序下载到客户机,下载后,电子邮件客户机就可以删除或修改任意邮件,而无需与电子邮件服务器进一步交互。 
3. POP3客户向POP3服务器发送命令并等待响应,POP3命令采用命令行形式,用ASCII码 表示。 服务器响应是由一个单独的命令行组成,或多个命令行组成,响应第一行以ASCII文本+ OK或-ERR指出相应 的操作状态是成功还是失败 
4. 在POP3协议中有三种状态,认可状态,处理状态,和更新状态。 当客户机与服务器建立联系时,一旦客户机提供了自己身份并成功确认,即由认可状态转入处理状态, 在完成相应的操作后客户机发出quit命令,则进入更新状态,更新之后最后重返认可状态。如下图 
等待连接 身份确认 quit命令 
—— |认可|————— |处理|——————|更新| 
|__________________________________| 
重返认可状态 
5. 认可状态的命令语句 
一般情况下,大多数现有的POP3客户与服务器执行采用ASCII明文发送用户名和口令,在 认可状态等 待客户连接的情况下,客户发出连接,并由命令user/pass对在网络上发送明文用户名和 口令给服务器 
进行身份确认。一旦确认成功,便转入处理状态。为了避免发送明文口令的问题,有一种新的认证方法,命令为APOP,使用APOP,口令在 传输之前被加密。 当第一次与服务器连接时,POP3服务器向客户机发送一个ASCII码问候,这个问候由一串字符组成对每个客户机是唯一的,与当时的时间有关,然后,客户机把它的纯文本口令附加到从服务器接 收到的字符串之后,然后计算出结果字符串的MD5单出函数消息摘要,客户机把用户名与MD5消息摘要作为APOP命令的参数一起发送出去。目前,大多数windows上的邮件客户软件不支持APOP命令,qpopper支持。 
6. POP3命令码如下: 
命令 参数 状态 描述 
------------------------------------------ 
USER username 认可 此命令与下面的pass命令若成功,将导致状态转换 
PASS password 认可 
APOP Name,Digest 认可 Digest是MD5消息摘要 
------------------------------------------ 
STAT None 处理 请求服务器发回关于邮箱的统计资料,如邮件总数和总字节数 
UIDL [Msg#] 处理 返回邮件的唯一标识符,POP3会话的每个标识符都将是唯一的 
LIST [Msg#] 处理 返回邮件数量和每个邮件的大小 
RETR [Msg#] 处理 返回由参数标识的邮件的全部文本 
DELE [Msg#] 处理 服务器将由参数标识的邮件标记为删除,由quit命令执行 
RSET None 处理 服务器将重置所有标记为删除的邮件,用于撤消DELE命令 
TOP [Msg#] 处理 服务器将返回由参数标识的邮件前n行内容,n必须是正整数 
NOOP None 处理 服务器返回一个肯定的响应 
------------------------------------------ 
QUIT None 更新 
a.客户机希望结束这次会话 
b.如果服务器处于‘处理’状态,那么将进入‘更新’状态以删除任何标记为删除的邮 
件 
c.导致由处理状态到更新状态,又重返认可状态的转变 
d.如果这个命令发出时服务器处于‘认可’状态,则结束会话,不进行‘更新’状态。 

7. POP3协议在TCP/110端口上等待客户连接请求。 
8. 若密码为明文,我如何监听? 
下面的命令在服务器运行后在屏幕上显示POP3连接及命令发送的过程: 
#sniffit -a -A. -p 110 -b -s 192.169.11.12 
note: 192.168.11.12是客户机IP地址 
你需要事先安装sniffit这个端口监听程序 
9. 考虑这种情况,若客户在收取邮件时,假定为15封信等待接收,但由于线路问题,收 
到第10封时断线了, 
为什么下次收时仍然从第一封开始,也即为什么前10封没有被从服务器上删除掉? 
任何邮件的删除都必须在quit命令发出后对已标记为删除的邮件执行删除操作,由于中 
途断线,仍处于 
处理状态,没有机会执行quit命令以进行状态转换。 
10. pop3 session is locked by another session, please wait 10 minutes then t 
ry again. 
由于非正常操作引起POP3程序内部机制锁住该次会话。 
11. Foxmail与OE(outlook express)的处理机制的不同。 
a. 假定服务器上有三封邮件等待客户机接收。用foxmail与OE的不同之处在于 
foxmail每收一封标记删除一封,而OE则等全部接收完后再全部标记为删除最后执行qui 
t命令。 
Foxmail OE 
------------------------------- 
retr 1 retr 1 
dele 1 retr 2 
retr 2 retr 3 
dele 2 dele 1 
retr 3 dele 2 
dele 3 dele 3 
quit quit 
b. Foxmail的远程邮件管理是非常优秀的管理工具,假定服务器上有三封信,对第一封 
,我们不想接收 
想从服务器直接删除;对第二封,想接收但不删除,对第三封,这一次不想接收,分别 
标记后 
最后foxmail发出的命令是 
dele 1 
retr 2 
quit 
c. 若没有foxmail,正好有几封很大的信堵住了,我不想接收,想直接删除它,或者想 
查看这两封是谁发的? 
直接在windows的DOS窗口下用命令行操作,如: 
# telnet my.isp.net 110 
user username 
pass password 
list

dele 3 
dele 5 
quit 
--



HTTP服务器与HTTP客户机之间的会话如下: 

1 客户机与服务器建立联系 

    与服务器建立连接,就是与SOCKET建立连接,因此要指定机器名称、资源名称和断口号,可以通过URL来提供这些信息。URL的格式为: 
          HTTP://<IP地址>/[端口号]/[路径][?<查询信息>] 
    资源的缺省值是INDEX或DEFAULT,断口号缺省为80. 

2 客户向服务器提出请求 

    请求信息包括希望返回的文件名和客户机信息.客户机信息以请求头发送给服务器,请求头包括HTTP方法和头字段. 
    HTTP方法常用的有GET、HEAD、POST,而PUT、DELETE、LINK、UNLINK方法 
许多HTTP服务器都不使用。 

    头字段包括: 

          。DATE:请求发送的日期和时间 

          。PARGMA:用于向服务器传输与实现无关的信息。这个字段还用于告诉代理服 
务器,要从实际服务器而不是从高速缓存取资源 

          。FORWARDED:可以用来追踪机器之间,而不是客户机和服务器的消息。这个字段 
可以用来追踪在代理服务器之间的传递路由。

      。MESSAGE_ID:用于唯一地标识消息 

      。ACCEPT: 通知服务器客户所能接受的数据类型和尺寸。(*/*表示可以接受 
所有类型的数据。 

      。AOTHORIZATION:向服务器提供旁路安全保护和加密机制,若服务器 
不需要这个字段,则不提供这个字段 

          。FROM:当客户应用程序希望想服务器提供有关其电子邮件地址时使用 

          。IF-MODEFIED-SINCE用于提供条件GET。如果所请求的文档自从所指定 
的日期以来没有发生变化,则服务器应不发送该对象。如果所发送的日期格式不合 
法,或晚于服务器的日期,服务器会忽略该字段 

          。BEFERRER:向服务器进行资源请求用到的对象 

          。MIME-VERTION:用于处理不同类型文件的MIME协议版本号 

          。USER-AGENT:有关发出请求的客户信息 

3 服务器对请求作出应答 

    服务器收到一个请求,就会立刻解释请求中所用到的方法,并开始处理应答。 
服务器的应答消息也包含头字段形式的报文信息。

    。报文第一行是状态行,格式为 <HTTP版本号><状态代码><解释短语> 

         状态码是个三位数字码,分为四类: 

             。以2开头,表示请求被成功处理 
                 。以3开头,表示请求被重定向 
              。以4开头,表示客户的请求有错 
             。以5开头,表示服务器不能满足请求 
         解释短语是对状态码的解释。 

    。报文还向客户返回几个头字段,如: 
         。STATUS CODE/REASON PHRASE 
             。DATE 
         。LAST-MODIFIED 
         。SERVER 
         。CONTENT _TYPE 
         。RETRY_AFTER:服务器太忙时返回这个字段 
         。WWW_AUTHENTICATE:当服务器的安全机制要求客户发送某中授权信息时使用该字段 

    。报文最后是实体信息,即客户请求得到的HTTP服务器上的资源内容。 

4 关闭客户与服务器之间的连接  

posted on 2009-10-16 10:31  x1Ao  阅读(4861)  评论(0编辑  收藏  举报