2.4 发送邮件类
是发送邮件的核心,类名为SmtpMail,隶属于命名空间MailSend。封装了发送邮件的具体实现方法,也是具体的RFC用代码实现的过程。而用户通过具体的操作接口,接口与SmtpMail类通过交互操作来实现用户发送信件的操作。
2.5 附加小功能类
是获取一些诸如系统时间,当前用户名,以及本机IP之类的类,类名为AddExtra,隶属于命名空间MailSend。
3 SMTP协议的研究
由于要开发的是邮件客户端程序,就不得不用到SMTP协议和POP协议。而我个人负责的是邮件发送功能的实现,因此就必然会涉及到SMTP(Simple Mail Transfer Protocol)协议。SMTP被用来在因特网上发送邮件,该协议规定了一些基本的命令和方法使客户端与服务器进行交互,以达到发送邮件的目的。
3.1 SMTP协议简介及工作原理
3.1.1 介绍
简单邮件传输协议(SMTP)的目标是可靠高效地传送邮件,它独立于传送子系统而且仅要求一条可以保证传送数据单元顺序的通道。
SMTP的一个重要特点是它能够在传送中接力传送邮件,传送服务提供了进程间通信环境(IPCE),此环境可以包括一个网络,几个网络或一个网络的子网。理解到传送系统(或IPCE)不是一对一的是很重要的。进程可能直接和其它进程通过已知的IPCE通信。邮件是一个应用程序或进程间通信。邮件可以通过连接在不同IPCE上的进程跨网络进行邮件传送。更特别的是,邮件可以通过不同网络上的主机接力式传送。
3.1.2 SMTP模型
SMTP设计基于以下通信模型:针对用户的邮件请求,发送SMTP建立与接收SMTP之间建立一个双向传送通道。接收SMTP可以是最终接收者也可以是中间传送者。SMTP命令由发送SMTP发出,由接收SMTP接收,而应答则反方面传送。
一旦传送通道建立,SMTP发送者发送MAIL命令指明邮件发送者。如果SMTP接收者可以接收邮件则返回OK应答。SMTP发送者再发出RCPT命令确认邮件是否接收到。如果SMTP接收者接收,则返回OK应答;如果不能接收到,则发出拒绝接收应答(但不中止整个邮件操作),双方将如此重复多次。当接收者收到全部邮件后会接收到特别的序列,如果接收者成功处理了邮件,则返回OK应答。
SMTP提供传送邮件的机制,如果接收方与发送方连接在同一个传送服务下时,邮件可以直接由发送方主机传送到接收方主机;或者,当两者不在同一个传送服务下时,通过中继SMTP服务器传送。为了能够对SMTP服务器提供中继能力,它必须拥有最终目的主机地址和邮箱名称。
MAIL命令参数是回复路径,它指定邮件从何处来;而RCPT命令的参数是转发路径的,它指定邮件向何处去。向前路径是源路径,而回复路径是返回路径(它用于发生错误时返回邮件)。
当同一个消息要发往不同的接收者时,SMTP遇到了向不同接收者发送同一份数据的复制品的问题,邮件命令和应答有一个比较奇怪的语法,应答也有一个数字代码。在下面,例子中可以看到哪些使用实际的命令和应答。完整的命令和应答在第四节。
命令与应答对大小写不敏感,也就是说,命令和应答可以是大写,小写或两者的混合,但这一点对用户邮件名称却不一定是对的,因为有的主机对用户名大小写是敏感的。这样SMTP实现中就将用户邮箱名称保留成初始时的样子,主机名称对大小写不敏感。
命令与应答由ASCII字母表组成,当传送服务提供8位字节传送通道,每7位字符正确传送,而最高位被填充为0。当指定一般的命令或应答格式后,参数会由一些类似于语言的字符串表示出来,如"<string>"或"<reverse-path>",这里尖括号表示这是一种类似于语言的变量。
3.2 SMTP协议的命令和应答
3.2.1 SMTP协议的命令
SMTP命令定义了邮件传输或由用户定义的系统功能。它的命令是由<CRLF>结束的字符串。而在带有参数的情况下,命令本身由<SP>和参数分开,如果未带参数可以直接和<CRLF>连接。邮箱的语法格式必须和接收站点的格式一致。下面讨论SMTP命令和应答。
发送邮件操作涉及到不同的数据对象,它们由不同的参数相互连接。回复路径就是MAIL命令的参数,而转发路径则是RCPT命令的参数,邮件日期是DATA命令的参数。这些参数或者数据对象必须跟在命令后。这种模式也就要求有不同的缓冲区来存储这些对象,也就是说,有一个回复路径缓冲区,一个转发路径缓冲区,一个邮件内容缓冲区。特定的命令产生自己的缓冲区,或使一个或多个缓冲的内容被清除。
HELLO (HELO)
此命令用于向接收SMTP确认发送SMTP。参数域包括发送SMTP的主机名。接收SMTP通过连接确认命令来向发送SMTP确认接收SMTP。引命令和OK响应确认发送和接收SMTP进入了初始状态,也就是说,没有操作正在执行,所有状态表和缓冲区已经被子清除。
MAIL (MAIL)
此命令用于开始将邮件发送到一个多个邮箱中。参数域包括回复路径。返回路径中包括了可选的主机和发送者邮箱列表。当有主机列表时,它是一个回复路径源,它说明此邮箱是由在表中的主机一一传递发送(第一个主机是最后一个接收到此邮件的主机)过来的。此表也有作向发送者返回非传递信号的源路径。因为每个传递主机地址都被加在此表起始处,它就必须使用发送IPCE而不是接收IPCE(如果它们不是一个IPCE的话)清楚的名称。一些出错信息的回复路径可能就是空的。
此命令清除回复路径缓冲区,转发路径缓冲区和邮件内容缓冲区,并且将此命令的回复路径信息插入到回复路径缓冲区中。
此命令指定接收方要么发送OK应答并改变角色为发送SMTP,要么发送拒绝信息并保持自己的角色。如果程序A现在是发送SMTP,它发出TURN命令后接收到OK(250)应答,它就变成了接收SMTP。程序A就进入初始状态,好象通信信道刚打开一样,这时它发送220准备好服务信号。如果程序B现在是接收SMTP,它发出TURN命令后接收到OK(250)应答,它就变成了发送SMTP。程序A就进入初始状态,好象通信信道刚打开一样,这时它准备接收220准备好服务信号。
若要拒绝改变角色,接收方可以发送502应答。
对于这些命令的顺序有一定的限制。对话的第一个命令必须是HELLO命令,此命令在此后的会话中也可以使用。如果HELLO命令的参数不可接受,必须由返回一个501失败应答,同时接收到的SMTP必须保持在与刚才一致的状态下。 NOOP,HELP,EXPN和VRFY命令可以在会话的任何时候使用。MAIL,SEND,SOML或SAML命令开始一个邮件操作。一旦开始了以后就要发送RCPT和DATA命令。邮件操作可以由RSET命令终止。在一个会话中可以有一个或多个操作。
如果在操作开始参数不可接受,必须返回501失败应答,同时接收到的SMTP必须保持在与刚才一致的状态下。如果操作中的命令顺序出错,必须返回503失败应答,同时接收到的SMTP必须保持在与刚才一致的状态下。
会话的最后一个命令必须是QUIT命令。此命令在会话的其它时间不能使用。
COMMAND语法格式
命令是由命令码和其后的参数域组成的。命令码是四个字母组成的,不区别大小写。因为下面的命令的作用是相同的:
MAIL Mail mail MaIl mAIl
这对于引导任何参数值的标记也是适用的,如TO和to就是一样的。命令码和参数由一个或多个空格分开。然而在回复路径和转发路径中的参数是区别大小写的。特别是在一些主机上,"smith"和"Smith"就根本不是一个用户。
参数域由不定长的字符串组成,它由<CRLF>结束,接收方在完全接收到此序列前不会采取任何行动。方括号代表可选的参数域。如果不选择的话,系统选择默认的设置。
下面是SMTP命令: HELO <SP> <domain> <CRLF> MAIL <SP> FROM:<reverse-path> <CRLF>
RCPT <SP> TO:<forward-path> <CRLF>
DATA <CRLF>
RSET <CRLF>
SEND <SP> FROM:<reverse-path> <CRLF>
SOML <SP> FROM:<reverse-path> <CRLF>
SAML <SP> FROM:<reverse-path> <CRLF>
VRFY <SP> <string> <CRLF>
EXPN <SP> <string> <CRLF>
HELP [<SP> <string>] <CRLF>
NOOP <CRLF>