《VCSMTP协议电子邮件传送剖析.docx》由会员分享,可在线阅读,更多相关《VCSMTP协议电子邮件传送剖析.docx(7页珍藏版)》请在第一文库网上搜索。
1、VC+SMTP合同电子邮件传送剖析-11-19-信息产业部电子第二十二研究所青岛分所朗锐yesky摘要:本文简介了一种采用SMTP合同规范并通过直接使用SMTP合同命令而在程序中实现电子邮件传送的措施。并在VC+开发环境下给出了部分核心的实现代码。a前言A电子邮件服务作为Internet上应用最多和最广的J服务项目得到了非常广泛的应用,在网络应用中也起到非常重要的作用。犹如其他的网络服务,电子邮件系统也有其使用的传播合同,涉及SMTP(SimP1eMai1TransferProtoco1,简朴邮件传播合同)、POP(PoStOfficeProtoCo1,邮局合同)和IMAP(InternetM
2、essageAccessProtoca1消息访问合同)等,这些合同应用于电子邮件时发送和接受。某些邮件解决软件如OUt1ookEXPreSS和FoxMaiI等就是按照SMTP和POP3合同结合WindowsSockets套接字进行设计来收发邮件的。本文以SMTP合同为研究对象,在ViSUa1C+6.0编程环境下按照SMTP合同通过套接字发送SMTP命令,接受并解决邮件服务器的!反馈信息,从而实现对电子邮件时发送。-SMTP合同的通讯模型和会话流程ASMTP合同通讯模型ASMTP合同是TCP/1P合同族中的一员,重要对如何将电子邮件从发送方地址传送到接受方地址,也即是对传播的规则做了规定。SMT
3、P合同日勺通信模型并不复杂,重要工作集中在发送SMTP和接受SMTP上:一方面针对顾客发出的邮件祈求,由发送SMTP建立一条连接到接受SMTP的J双工通讯链路,这里的接受SMTP是相对于发送SMTP而言日勺,事实上它既可以是最后日勺接受者也可以是中间传送者。发送SMTP负责向接受SMTP发送SMTP命令,而接受SMTP则负责接受并反馈应答。可大体用下面由J通讯模型示意图来表达:SMIP通讯模型示意图4SMTP合同的命令和应答-从前面口勺通讯模型可以看出SMTP合同在发送SMTP和接受SMTP之间日勺会话是靠发送SMTP的SMTP命令和接受SMTP反馈的应答来完毕的。在通讯链路建立后,发送SMT
4、P发送MA11命令指令邮件发送者,若接受SMTP此时可以接受邮件则作出OKU勺应答,然后发送SMTP继续发出RCPT命令以确认邮件与否收到,如果接受到就作出OK的应答,否则就发出回绝接受应答,但这并不会对整个邮件操作导致影响。双方如此反复多次,直至邮件解决完毕。SMTP合同共涉及10个SMTP命令,列表如下:SMTP命令命令阐明HE11O辨认发送方到接受SMTP的一种HE11O命令MAI1FROM:reverse-path为发送者地址。此命令告诉接受方一种新邮件发送的开始,并对所有的状态和缓冲区进行初始化。此命令开始一种邮件传播解决,最后完毕将邮件数据传送到一种或多种邮箱中。RCPTT0:fo
5、rward-path标记各个邮件接受者H地址DATAA接受SMTP将把其后的行为看作邮件数据去解决,以VCR1F.VCR1F标记数据的结尾。REST退出/复位目前的邮件传播NOOP规定接受SMTP仅做OK应答。(用于测试)QIT规定接受SMTP返回一种OK应答并关闭传播。VRFY验证指定H勺邮箱与否存在,由于安全因素,服务器多严禁此命令。EXPN验证给定的邮箱列表与否存在,扩充邮箱列表,也常严禁使用。HE1P查询服务器支持什么命令A注:VCR1F为回车、换行,ASCII码分别为13、10(十进制)。SMTP合同的每一种命令都会返回一种应答码,应答码的每一种数字都是有特定含义口勺,如第一位数字为
6、2时表达命令成功;为5表失败;3表没有完毕。某些较复杂的邮件程序运用该特点,一方面检查应答码的首数字,并根据其值来决定下一步口勺动作。下面将SMTP的应答码列表如下:应答码阐明501参数格式错误502命令不可实现503错误日勺命令序列504命令参数不可实现211系统状态或系统协助响应214协助信息220服务就绪221Vdomain服务关闭421domain服务未就绪,关闭传播信道250规定的邮件操作完毕251顾客非本地,将转发向Vforward-path450规定卧J邮件操作未完毕,邮箱不可用550规定的邮件操作未完毕,邮箱不可用451放弃规定的操作;解决过程中出错551顾客非本地,请尝试Vf
7、orWardpath452系统存储局限性,规定的操作未执行552过量的存储分派,规定的操作未执行553邮箱名不可用,规定的操作未执行354开始邮件输入,以“.结束554操作失败在应用程序中使用SMTP合同ASMTP合同的会话流程A在进行程序设计之前有必要弄清SMTP合同的会话流程,其实前面简介的内容已经可以大体勾勒出用SMTP发送邮件的框架了,对于一次一般的邮件发送,其过程大体为:先建立TCP连接,随后客户端发出HE11o命令以标记发件人自己的身份,并继续由客户端发送MAI1命令,如服务器应答为“OKu,可继续发送RCPT命令来标记电子邮件的收件人,在这里可以有多种RCPT行,而服务器端则表达
8、与否乐意为收件人接受该邮件。在双方协商结束后,用命令DATA将邮件发送出去,其中对表达结束BVT也一并发送出去。随后结束本次发送过程,以QUIT命令退出。下面通过一种实例,从发送邮件到来更具体直观地描述此会话流程:R:Simp1eMai1TransferServiceReadyS:HE11Osohu.ComAR:250SS:MAI1FROMyXR:250OKS:RCPTT0iR:250OKS:DATAR:354Startmai1input;endwith.*S:R:250OKAS:QU1TAR:ServicecIosingtransmissionchanne1A邮件的格式化A由于电子邮件构造上
9、的特殊性,在传播时是不能当作简朴的文本来直接解决时,而必须按照一定的格式对邮件头和邮件体进行格式化解决之后才可以被发送。需要进行格式化的部分重要有:发件人地址、收件人地址、主题和发送日期等。在RFC文档的RFC822里对邮件的格式化有详尽的阐明,有关详情请参阅该文档。下面通过VC+6.0按照RFC822文档规定将格式化邮件的部分编写如下(部分代码):邮件头准备strTemp=_T(,From:)+m_strFrom;add_headerJine(1PCTSTR)strTemp);strTemp=_T(,To:“)+add_header_1ine(1PCTSTR)strTemp);Am_tDat
10、eTime=m_tDateTime.GetCurrentTime();发送时间strTemP=_T(,Data:);AstrTemp+=m_tDateTime.Format(%a,%d%b%y%H:%M:%S%Z);add_header_1ine(1PCTSTR)strTemp);AStrTemP=_T(Subject:)+m_strSubject;add_header_1ine(1PCTSTR)strTemp);m_strHeader+=_T(rn);if(m_strBody.Right(2)!=_T(rn)m_strBody+=_T(,rn,);其中QCIC1heQder_Iie(1PCT
11、STRSZHeOder1ine)函数用于把SZHeQCIer1ine指向的字串追力口至IJm_strH6Qder背面。其中,格式化后的邮件头保存在m,strHeader里,格式化后的邮件体保存在m_strBody中。总由SoCket套接字为SMTP提供网络通讯基郦许多网络程序都是采用SoCket套接字实现时,对于某些原则的网络合同如HTTP、FTP和SMTP等合同的编程也是基于套接字程序的,只是端标语不再是随意设定而要由合同来指定,例如HTTP端口在80、FTP是21,而SMTP则是25。SoCket只是提供在指定的端口上同指定的服务器从事网络上的通讯能力,至于客户和服务器之间是如何通讯的则由
12、网络合同来规定,这对于套接字是完全透明的。因此可以使用S。Cket套接字为程序提供网络通讯时能力,而对于网络通讯连路建立好之后采用什么样的通讯应答则要按SMTP合同的规定去执行了。S。Cket套接字网络编程方面的文章资料非常丰富,限于本文篇幅,在此不再赘述,有关详情请参阅有关文档。为简便起见,没有采用编写较复杂的WindowsSocketsAPI进行编程,而是使用通过较好封装的MFC的CSoCket类。在正式使用套接字之前,也要先用AfXSocket1nit()函数对套接字进行初始化,然后用Create()创立套接字对象,并由该套接字通过ConneCt()建立同邮件服务器的连接。如果一切正常,
13、再后续的工作中就是遵循SMTP合同时商定来使用Sed()xReceive()函数来发送SMTP命令和接受邮件服务器发来的应答码以完毕对邮件的传送aSMTP会话应答的实现A在同邮件服务器建立好链路连接后就可以按前面简介过的会话流程进行程序设计了,对于SMTP命令的发送,可按命令格式将其组帧完毕后用CSoCket类的Send()函数将其发送到服务器,并通过CSocket类的ReCeiVe()函数接受从邮件服务器发来时应答码,并根据SMTP合同的应答码表对其做出响应的解决。下面是用于接受应答码的函数get_resPonSe()的部分实现代码:BOO1CSMTP:get_response(UINTre
14、sponSe_expected)输入参数为但愿的应答码乂a/m_wsSMTPServer为CSocket的I类对象,调用Receive()将应答码接受到缓存M/response_buf中m_wsSMTPServer.Receive(response_buf,RESPONSE_BUFFER_SIZERsResponse=responSe_but;sscanf(1PCTSTR)SResponse.1eft(3),_T(,%d),&response);pResp=&responsejab1eresponse_expected;if(response!=Resp-nResponse)aa/不相等的!话
15、进行错误解决AreturnFA1SE;a)returnTRUE泠A会话时各个部分比较类似,都是命令-应答方式,并且均成对浮现,下面是本文的重点也是实现的核心部分-在程序控制下完毕对SMTP命令的格式化以及对命令的发送和对邮件服务器应答码的检查解决:/格式化并发送HE11O命令,并接受、验证服务器应答码gethostname(IOCa1jIOst,80):sHe11o.Format(_T(HE1O%srn),1oca1_host);Am_wsSMTPServer.Send(1PCTSTR)sHe11o,sHeHo.Get1ength();if(!get_response(GENERIC_SUCCESS)are