• 305.59 KB
  • 2022-04-22 11:32:15 发布

电子邮件客户端软件论文.doc

  • 51页
  • 当前文档由用户上传发布,收益归属用户
  1. 1、本文档共5页,可阅读全部内容。
  2. 2、本文档内容版权归属内容提供方,所产生的收益全部归内容提供方所有。如果您对本文有版权争议,可选择认领,认领后既往收益都归您。
  3. 3、本文档由用户上传,本站不保证质量和数量令人满意,可能有诸多瑕疵,付费之前,请仔细先通过免费阅读内容等途径辨别内容交易风险。如存在严重挂羊头卖狗肉之情形,可联系本站下载客服投诉处理。
  4. 文档侵权举报电话:19940600175。
'45电子邮件客户端软件目录第1章引言11.1电子邮件介绍11.2开发背景21.3开发环境及运行环境31.3.1开发环境31.3.2运行环境3第2章软件架构及系统用例图42.1系统架构:42.2系统总体用例:42.3程序功能框架图:52.4发送邮件类62.5附加小功能类6第3章SMTP协议的研究83.1.1介绍SMTP协议83.1.2SMTP模型83.2.1SMTP协议的命令103.2.2SMTP的应答18第4章RFC822214.1RFC822简单介绍214.2信件的头部22第5章命名控件MAILSEND295.1发送邮件的类SmtpMail29第45页共51页 455.2AddExtra类40第6章软件运行时的界面426.1新建账号426.2发送不带附件的邮件436.3发送带附件的邮件436.4验证邮件发送是否成功44第7章系统测试467.1同一SMTP服务器发送纯文本的邮件测试467.2同一SMTP服务器发送带附件的邮件测试467.3不同SMTP服务器发送邮件测试47第8章结论48致谢49参考文献50第45页共51页 45第1章引言1.1电子邮件介绍电子邮件(简称E-mai1)又称电子信箱、电子邮政,它是—种用电子手段提供信息交换的通信方式。它是全球多种网络上使用最普遍的一项服务。这种非交互式的通信,加速了信息的交流及数据传送,它是—个简易、快速的方法。通过连接全世界的Internet,实现各类信号的传送、接收、存贮等处理,将邮件送到世界的各个角落。到目前为止,可以说电子邮件是Internet资源使用最多的一种服务,E-mai1不只局限于信件的传递,还可用来传递文件、声音及图形、图像等不同类型的信息。电子邮件不是一种“终端到终端”的服务,是被称为“存贮转发式”服务。这正是电子信箱系统的核心,利用存贮转发可进行非实时通信,属异步通信方式。即信件发送者可随时随地发送邮件,不要求接收者同时在场,即使对方现在不在,仍可将邮件立刻送到对方的信箱内,且存储在对方的电子邮箱中。接收者可在他认为方便的时候读取信件,不受时空限制。在这里,“发送”邮件意味着将邮件放到收件人的信箱中,而“接收”邮件则意味着从自己的信箱中读取信件,信箱实际上是由文件管理系统支持的—个实体。因为电子邮件是通过邮件服务器(mai1server)来传递档的。通常mailserver是执行多任务操作系统UNIX的计算机,它提供24小时的电子邮件服务,用户只要向mailserver管理人员申请—个信箱账号,就可使用这项快速的邮件服务。第45页共51页 45电子邮件的工作原理:1)电子邮件系统是一种新型的信息系统,是通信技术和计算机技术结合的产物。电子邮件的传输是通过电子邮件简单传输协议(SimpleMailTransferProtocol,简称SMTP)这一系统软件来完成的,它是Internet下的一种电子邮件通信协议。2)电子邮件的基本原理,是在通信网上设立“电子信箱系统”,它实际上是一个计算机系统。系统的硬件是一个高性能、大容量的计算机。硬盘作为信箱的存储介质,在硬盘上为用户分一定的存储空间作为用户的“信箱”,每位用户都有属于自己的—个电子信箱。并确定—个用户名和用户可以自己随意修改的口令。存储空间包含存放所收信件、编辑信件以及信件存盘三部分空间,用户使用口令开启自己的信箱,并进行发信、读信、编辑、转发、存档等各种操作。系统功能主要由软件实现。3)电子邮件的通信是在信箱之间进行的。用户首先开启自己的信箱,然后通过键入命令的方式将需要发送的邮件发到对方的信箱中。邮件在信箱之间进行传递和交换,也可以与另—个邮件系统进行传递和交换。收方在取信时,使用特定账号从信箱提取。1.2开发背景当前流行的各大邮件客户端软件的除了最主要的收发信件之外,功能越来越复杂,但是人们平常真正用到的功能很少,很多功能尤其对于那些计算机知识相对缺乏的人来说,更加显得太过于华丽而不太实用。有鉴于此,在了解RFC底层协议的基础上,我们开发了这个各种功能相对简单实用的邮件客户端程序,简化了很多不必要的功能。第45页共51页 451.3开发环境及运行环境当前流行的各大邮件客户端软件的除了最主要的收发信件之外,功能越来越复杂,但是人们平常真正用到的功能很少,很多功能尤其对于那些计算机知识相对缺乏的人来说,更加显得太过于华丽而不太实用。有鉴于此,在了解RFC底层协议的基础上,我们开发了这个各种功能相对简单实用的邮件客户端程序,简化了很多不必要的功能。1.3.1开发环境Microsoft®Windows™XPProfessional、Microsoftvisualstudio2005C#、Microsoftaccess数据库。1.3.2运行环境邮件客户端运行在Windows2000或以上操作系统平台、并且安装有Microsoft.NETFramework2.0或者以上版本。第45页共51页 45第2章软件架构及系统用例图2.1系统架构:如图2.1:主要功能选择用户主界面接收邮件类发送邮件类图2.1软件架构图2.2系统总体用例:如图2.2:第45页共51页 45用户新建账号发送邮件接收邮件纯文本邮件带附件邮件图2.2系统总体用例图2.3程序功能框架图:如图2.2:第45页共51页 45客户端软件电子邮件接收系统电子邮件接收系统附加功能各种错误的提示简单邮件接收带有附件的邮件接收简单邮件发送带有附件的邮件发送电子邮件编写电子邮件的分类管理通讯簿管理图2.3程序功能图2.4发送邮件类是以“发送邮件”的核心,类名为SmtpMail,隶属于命名空间MailSend。封装了发送邮件的具体实现方法,也是具体的RFC用代码实现的过程。而用户通过具体的操作接口,接口与SmtpMail类通过交互操作来实现用户发送信件的操作。2.5附加小功能类是获取一些诸如系统时间,当前用户名,以及本机IP之类的类,类名为AddExtra第45页共51页 45,隶属于命名空间MailSend。第45页共51页 45第3章SMTP协议的研究由于要开发的是邮件客户端程序,就不得不用到SMTP协议和POP协议。而我个人负责的是邮件发送功能的实现,因此就必然会涉及到SMTP(SimpleMailTransferProtocol)协议。SMTP被用来在因特网上发送邮件,该协议规定了一些基本的命令和方法使客户端与服务器进行交互,以达到发送邮件的目的。3.1.1介绍SMTP协议简单邮件传输协议(SMTP)的目标是可靠高效地传送邮件,它独立于传送子系统而且仅要求一条可以保证传送数据单元顺序的通道。SMTP的一个重要特点是它能够在传送中接力传送邮件,传送服务提供了进程间通信环境(IPCE),此环境可以包括一个网络,几个网络或一个网络的子网。理解到传送系统(或IPCE)不是一对一的是很重要的。进程可能直接和其它进程通过已知的IPCE通信。邮件是一个应用程序或进程间通信。邮件可以通过连接在不同IPCE上的进程跨网络进行邮件传送。更特别的是,邮件可以通过不同网络上的主机接力式传送。3.1.2SMTP模型SMTP设计基于以下通信模型:针对用户的邮件请求,发送SMTP建立与接收SMTP之间建立一个双向传送通道。接收SMTP可以是最终接收者也可以是中间传送者。第45页共51页 45SMTP命令由发送SMTP发出,由接收SMTP接收,而应答则反方面传送。一旦传送通道建立,SMTP发送者发送MAIL命令指明邮件发送者。如果SMTP接收者可以接收邮件则返回OK应答。SMTP发送者再发出RCPT命令确认邮件是否接收到。如果SMTP接收者接收,则返回OK应答;如果不能接收到,则发出拒绝接收应答(但不中止整个邮件操作),双方将如此重复多次。当接收者收到全部邮件后会接收到特别的序列,如果接收者成功处理了邮件,则返回OK应答。SMTP提供传送邮件的机制,如果接收方与发送方连接在同一个传送服务下时,邮件可以直接由发送方主机传送到接收方主机;或者,当两者不在同一个传送服务下时,通过中继SMTP服务器传送。为了能够对SMTP服务器提供中继能力,它必须拥有最终目的主机地址和邮箱名称。MAIL命令参数是回复路径,它指定邮件从何处来;而RCPT命令的参数是转发路径的,它指定邮件向何处去。向前路径是源路径,而回复路径是返回路径(它用于发生错误时返回邮件)。当同一个消息要发往不同的接收者时,SMTP遇到了向不同接收者发送同一份数据的复制品的问题,邮件命令和应答有一个比较奇怪的语法,应答也有一个数字代码。在下面,例子中可以看到哪些使用实际的命令和应答。完整的命令和应答在第四节。命令与应答对大小写不敏感,也就是说,命令和应答可以是大写,小写或两者的混合,但这一点对用户邮件名称却不一定是对的,因为有的主机对用户名大小写是敏感的。这样SMTP实现中就将用户邮箱名称保留成初始时的样子,主机名称对大小写不敏感。命令与应答由ASCII字母表组成,当传送服务提供8位字节传送通道,每7第45页共51页 45位字符正确传送,而最高位被填充为0。当指定一般的命令或应答格式后,参数会由一些类似于语言的字符串表示出来,如""或"",这里尖括号表示这是一种类似于语言的变量。3.2.1SMTP协议的命令SMTP命令定义了邮件传输或由用户定义的系统功能。它的命令是由结束的字符串。而在带有参数的情况下,命令本身由和参数分开,如果未带参数可以直接和连接。邮箱的语法格式必须和接收站点的格式一致。下面讨论SMTP命令和应答。发送邮件操作涉及到不同的数据对象,它们由不同的参数相互连接。回复路径就是MAIL命令的参数,而转发路径则是RCPT命令的参数,邮件日期是DATA命令的参数。这些参数或者数据对象必须跟在命令后。这种模式也就要求有不同的缓冲区来存储这些对象,也就是说,有一个回复路径缓冲区,一个转发路径缓冲区,一个邮件内容缓冲区。特定的命令产生自己的缓冲区,或使一个或多个缓冲的内容被清除。HELLO(HELO)此命令用于向接收SMTP确认发送SMTP。参数域包括发送SMTP的主机名。接收SMTP通过连接确认命令来向发送SMTP确认接收SMTP。引命令和OK响应确认发送和接收SMTP进入了初始状态,也就是说,没有操作正在执行,所有状态表和缓冲区已经被子清除。MAIL(MAIL)第45页共51页 45此命令用于开始将邮件发送到一个多个邮箱中。参数域包括回复路径。返回路径中包括了可选的主机和发送者邮箱列表。当有主机列表时,它是一个回复路径源,它说明此邮箱是由在表中的主机一一传递发送(第一个主机是最后一个接收到此邮件的主机)过来的。此表也有作向发送者返回非传递信号的源路径。因为每个传递主机地址都被加在此表起始处,它就必须使用发送IPCE而不是接收IPCE(如果它们不是一个IPCE的话)清楚的名称。一些出错信息的回复路径可能就是空的。此命令清除回复路径缓冲区,转发路径缓冲区和邮件内容缓冲区,并且将此命令的回复路径信息插入到回复路径缓冲区中。  RECIPIENT(RCPT)此命令用于确定邮件内容的唯一接收者;多个接收者将由多个此命令指定。转发路径中包括一个可选的主机和一个必须的目的邮箱。当出现主机列表时,这就是一个源路径,它指明邮件必须向列表中的上一个主机发送。如果接收SMTP未实现邮件的传递发送,就会返回如未知本地用户(550)的信息给用户。当邮件被传递发送时,传递主机必须将自己的名称由转发路径的开始处移至回复路径的结束处。当邮件最终到达目的地时,接收SMTP将以它的主机邮件格式自己的名称插入目标邮件中。例如,由传递主机A接收的带有如下参数的邮件时,FROM:  TO:<@HOSTA.ARPA,@HOSTB.ARPA:USERC@HOSTD.ARPA>将会变成如下形式:  FROM:<@HOSTA.ARPA:USERX@HOSTY.ARPA>  TO:<@HOSTB.ARPA:USERC@HOSTD.ARPA>.第45页共51页 45此命令导致它的转发路径参数加入转发路径缓冲区中。  DATA(DATA)接收者将跟在命令后的行作为邮件内容。此命令导致此命令后的邮件内容加入邮件内容缓冲区。邮件内容可以包括所有128个ASCII码字符。邮件内容由只包括一个句号的行结束,也就是如下的字符序列:".",它指示了邮件的结束。邮件内容的结束指示要求接收者现在就处理保存的邮件内容。此过程将回复路径缓冲区,转发路径缓冲区和邮件内容缓冲区的内容全部清空。如果操作成功,接收者必须返回OK应答;如果失败也必须返回失败应答。当接收SMTP收到一条信息时,无论是用作转发还是此邮件已经到达目的地,它都必须在邮件内容的开始处加上时间戳这一行,这一行指示了接收到邮件主机和发出此邮件主机的标识,以及接收到邮件内容的时间和日期。转发的信件将有多行这样的时间戳。当接收SMTP作最后一站的传送时,它将返回路径信息行插入邮件中。此行包括了发送命令中的的信息。在这里,最后一站的传送的意思是邮件将被送到目的用户手中,但在一些情况下,邮件可能需要更进一步的加工并由另外的邮件系统传送。可能在返回路径中的邮箱与实际发送的邮件不一致,这个情况可能发生在需要传送一个特定的错误处理信箱而不是信件发送者那里。上面所述说明了,最后的邮件内容由一个返回路径行,和在其后的一个或多个时间戳行构成。这些行后面是邮件内容的头和体信息。当处理后面的邮件数据指示部分成功时就需要特定的说明。这种情况可能发生在发送SMTP第45页共51页 45发现当邮件需要传送给多个用户时,只能够成功地向其中的一部分发送信息这种情况下。在这种情况下,必须对DATA命令发送OK应答,而接收SMTP组织并发送一个"不可传递邮件"信息到信息的发送者。在此信息中或者发送一个不成功接收者的列表,或者每次发送一个不成接收者,而发送多次。所有不可传递邮件信息由MAIL命令发送。返回路径和接收时间戳例子  Return-Path:<@GHI.ARPA,@DEF.ARPA,@ABC.ARPA:JOE@ABC.ARPA>  Received:fromGHI.ARPAbyJKL.ARPA;27Oct8115:27:39PST  Received:fromDEF.ARPAbyGHI.ARPA;27Oct8115:15:13PST  Received:fromABC.ARPAbyDEF.ARPA;27Oct8115:01:59PST  Date:27Oct8115:01:01PST  From:JOE@ABC.ARPA  Subject:ImprovedMailingSystemInstalled  To:SAM@JKL.ARPA  Thisistoinformyouthat...  SEND(SEND)此命令用于开始一个发送命令,将邮件发送到一个或多个终端上。参数域包括了一个回复路径,此命令如果成功就将邮件发送到终端上了。第45页共51页 45回复路径包括一个可选的主机列表和发送者邮箱。当出现主机列表时,表示这是一个传送路径,邮件就是经过这个路径上的每个主机发送到这里的(列表上第一个主机是最后经手的主机)。此表用于返回非传递信号到发送者。因为每个传递主机地址都被加在此表起始处,它就必须使用发送IPCE而不是接收IPCE(如果它们不是一个IPCE的话)清楚的名称。一些出错信息的回复路径可能就是空的。此命令清除回复路径缓冲区,转发路径缓冲区和邮件内容缓冲区,并且将此命令的回复路径信息插入到回复路径缓冲区中。  SENDORMAIL(SOML)此命令用于开始一个邮件操作将邮件内容传送到一个或多个终端上,或者传送到邮箱中。对于每个接收者,如果接收者终端打开,邮件内容将被传送到接收者的终端上,否则就送到接收者的邮箱中。参数域包括回复路径,如果成功地将信息送到终端或邮箱中此命令成功。回复路径包括一个可选的主机列表和发送者邮箱。当出现主机列表时,表示这是一个传送路径,邮件就是经过这个路径上的每个主机发送到这里的(列表上第一个主机是最后经手的主机)。此表用于返回非传递信号到发送者。因为每个传递主机地址都被加在此表起始处,它就必须使用发送IPCE而不是接收IPCE(如果它们不是一个IPCE的话)清楚的名称。一些出错信息的回复路径可能就是空的。此命令清除回复路径缓冲区,转发路径缓冲区和邮件内容缓冲区,并且将此命令的回复路径信息插入到回复路径缓冲区中。  SENDANDMAIL(SAML)此命令用于开始一个邮件操作将邮件内容传送到一个或多个终端上,并传送到邮箱中。如果接收者终端打开,邮件内容将被传送到接收者的终端上和接收者的邮箱中。参数域包括回复路径,如果成功地将信息送到邮箱中此命令成功。第45页共51页 45回复路径包括一个可选的主机列表和发送者邮箱。当出现主机列表时,表示这是一个传送路径,邮件就是经过这个路径上的每个主机发送到这里的(列表上第一个主机是最后经手的主机)。此表用于返回非传递信号到发送者。因为每个传递主机地址都被加在此表起始处,它就必须使用发送IPCE而不是接收IPCE(如果它们不是一个IPCE的话)清楚的名称。一些出错信息的回复路径可能就是空的。此命令清除回复路径缓冲区,转发路径缓冲区和邮件内容缓冲区,并且将此命令的回复路径信息插入到回复路径缓冲区中。 RESET(RSET)此命令指示当送邮件操作将被放弃。任何保存的发送者,接收者和邮件内容应该被抛弃,所有缓冲区和状态表应该被清除,接收方必须返回OK应答。  VERIFY(VRFY)此命令要求接收者确认参数是一个用户。如果这是(已经知道的)用户名,返回用户的全名和指定的邮箱。此命令对回复路径缓冲区,转发路径缓冲区和邮件内容缓冲区没有影响。  EXPAND(EXPN)此命令要求接收者确认参数指定了一个邮件发送列表,如果是一个邮件发送列表,就返回表中的成员。如果这是(已经知道的)用户名,返回用户的全名和指定的邮箱。此命令对回复路径缓冲区,转发路径缓冲区和邮件内容缓冲区没有影响。HELP(HELP)此命令导致接收者向HELP第45页共51页 45命令的发送者发出帮助信息。此命令可以带参数,并返回特定的信息作为应答。此命令对回复路径缓冲区,转发路径缓冲区和邮件内容缓冲区没有影响。  NOOP(NOOP)此命令不影响任何参数和已经发出的命令。它只是说明没有任何操作而不是说明接收者发送了一个OK应答。此命令对回复路径缓冲区,转发路径缓冲区和邮件内容缓冲区没有影响。  QUIT(QUIT)此命令指示接收方必须发送OK应答然后关闭传送信道。接收方在接到QUIT命令并做出响应之前不应该关闭通信信道。发送方在发送QUIT命令和接收到响应之前也不应该关闭信道。即使出错,也不应该关闭信道。如果连接被提前关闭,接收方应该象接收到RSET命令一样,取消所有等待的操作,但不恢复原先已经做过的操作。而发送方应该象接收到暂时错误(4XX)一样假定命令和操作仍在支持之中。  TURN(TURN)此命令指定接收方要么发送OK应答并改变角色为发送SMTP,要么发送拒绝信息并保持自己的角色。如果程序A现在是发送SMTP,它发出TURN命令后接收到OK(250)应答,它就变成了接收SMTP。程序A就进入初始状态,好象通信信道刚打开一样,这时它发送220准备好服务信号。如果程序B现在是接收SMTP,它发出TURN命令后接收到OK(250)应答,它就变成了发送SMTP。程序A就进入初始状态,好象通信信道刚打开一样,这时它准备接收220准备好服务信号。若要拒绝改变角色,接收方可以发送502应答。第45页共51页 45对于这些命令的顺序有一定的限制。对话的第一个命令必须是HELLO命令,此命令在此后的会话中也可以使用。如果HELLO命令的参数不可接受,必须由返回一个501失败应答,同时接收到的SMTP必须保持在与刚才一致的状态下。NOOP,HELP,EXPN和VRFY命令可以在会话的任何时候使用。MAIL,SEND,SOML或SAML命令开始一个邮件操作。一旦开始了以后就要发送RCPT和DATA命令。邮件操作可以由RSET命令终止。在一个会话中可以有一个或多个操作。如果在操作开始参数不可接受,必须返回501失败应答,同时接收到的SMTP必须保持在与刚才一致的状态下。如果操作中的命令顺序出错,必须返回503失败应答,同时接收到的SMTP必须保持在与刚才一致的状态下。会话的最后一个命令必须是QUIT命令。此命令在会话的其它时间不能使用。COMMAND语法格式命令是由命令码和其后的参数域组成的。命令码是四个字母组成的,不区别大小写。因为下面的命令的作用是相同的:  MAILMailmailMaIlmAIl这对于引导任何参数值的标记也是适用的,如TO和to就是一样的。命令码和参数由一个或多个空格分开。然而在回复路径和转发路径中的参数是区别大小写的。特别是在一些主机上,"smith"和"Smith"就根本不是一个用户。参数域由不定长的字符串组成,它由结束,接收方在完全接收到此序列前不会采取任何行动。方括号代表可选的参数域。如果不选择的话,系统选择默认的设置。下面是SMTP命令:HELOMAILFROM:第45页共51页 45RCPTTO:DATARSETSENDFROM:SOMLFROM:SAMLFROM:VRFYEXPNHELP[]NOOPQUITTURN3.2.2SMTP的应答对SMTP命令的响应是多样的,它确定了在邮件传输过程中请求和处理的同步,也保证了发送SMTP知道接收SMTP的状态。每个命令必须有且只有一个响应。SMTP第45页共51页 45响应由三位数字组成,其后跟一些文本。数字帮助决定下一个应该进入的状态,而文本对人是有意义的。三位的响应已经包括了足够的信息,不用再阅读文本,文本可以直接抛弃或者传递给用户。特别的是,文本是与接收和环境相关的,所以每次接收到的文本可能不同。在附录E中可以看到全部的响应码。正规的情况下,响应由下面序列构成:三位的数字,,一行文本和一个,或者也可以是一个多行响应。只有EXPN和HELP命令可以导致多行应答,然而,对所有命令,多行响应都是允许的。REPLYCODESBYFUNCTIONGROUPS500格式错误,命令不可识别(此错误也包括命令行过长)501参数格式错误502命令不可实现503错误的命令序列504命令参数不可实现211系统状态或系统帮助响应214帮助信息220服务就绪221服务关闭传输信道421服务未就绪,关闭传输信道(当必须关闭时,此应答可以作为对任何命令的响应)250要求的邮件操作完成251用户非本地,将转发向450要求的邮件操作未完成,邮箱不可用(例如,邮箱忙)550要求的邮件操作未完成,邮箱不可用(例如,邮箱未找到,或不可访问)451放弃要求的操作;处理过程中出错551用户非本地,请尝试第45页共51页 45452系统存储不足,要求的操作未执行552过量的存储分配,要求的操作未执行553邮箱名不可用,要求的操作未执行(例如邮箱格式错误)354开始邮件输入,以.结束554操作失败第45页共51页 45第4章RFC822说道发送和接受邮件,我们就必须不得不提RFC822了。RFC822的全称是“ARPA因特网文本信件格式的标准”(StandardfortheFormatofARPAInternetTextMessages)。该标准提供了邮件内容的格式和相关语义。。4.1RFC822简单介绍RFC822规定的电子邮件内容全部由ASCII字符组成,就是通常所说的文本文件,因而标准将它称为Internet文本信件(InternetTextMessages)。从直观上看,信件非常简单,就是一系列由ASCII字符组成的文本行,每一行以回车换行符(“CRLF“,就是ASCII码的13和10)结束。从组织上看,信件内容结构分为两大部分,中间用一个空白行(只有CRLF符的行)来分隔。第一部分称为信件的头部(theheaderofthemessage),包括有关发送方、接收方、发送日期等信息。第二部分称为信件的体部(Bodyofthemessage),包括信件内容的正文文本。信头是必需的,信体是可选的,即信体可有可无。如果不存在信体,用作分隔的空白行也就不需要。在信体中,也可以有用作分隔的空白行。这样设计的信件便于进行语法分析,提取信件的基本信息。在RFC822中规定,信件体就是一系列的向收信人表达信息的文本行,比较简单,可以包含任意文本,并没有附加的结构。信件头则具有比较复杂的结构,在下一小节中详述。第45页共51页 454.2信件的头部1、信件头部的一般格式信头的结构比较复杂,信头由若干信头字段(headerfield)组成,这些字段为用户和程序提供了关于信件的信息。要了解信头的结构就要弄清楚各种信头字段。所有的信头字段都具有相同的语法结构,从逻辑上说,包括四部分,字段名(fieldname),紧跟冒号":"(colon),后跟字段体(fieldbody),最后以回车换行符(CRLF)终止。即信头字段=字段名:字段体CRLF字段名必须由除了冒号和空格以外的可打印US—ASCII字符(其值在33和126之间)组成,大多数字段的字段名称由一系列字母,数字组成,中间经常插入横线符。字段名告诉电子邮件软件如何翻译该行中剩下的内容。字段体可以包括除了CR和LF之外的任何ASCII字符。但是其中的空格,加括号的注释,引号和多行字段都比较复杂,另外,字段体的语法和语义依赖于字段名,每个类型的字段有特定的格式。RFC822为信件定义了一些标准字段,并提供了用户自行定义非标准字段的方2、结构化字段和非结构化字段每个字段所包含的信息不同,字段大体可以分为结构化字段和非结构化字段。结构化字段有特定的格式,由语法分析程序检测。Sender字段就是一个很好的例子,它的字段内容是信箱,有一个离散的结构。非结构化的字段含有任意的数据,没有固定格式。例如,Subject第45页共51页 45字段可以含有任意的文字,并且没有固定格式。非结构化的字段数量较少,只有Subject、Comments、扩展字段,非标准字段、IN—Reply和References等。所有其它字段都是结构化的。3、信头字段的元素尽管Email信件的总体结构非常简单,但一些信头字段的结构是很复杂的。下面介绍一些大多数字段共有的元素。(1)空白符像其它文本文件一样,空白符包括空格符(ASCII码32)和制表符Tab(ASCII码19)。此外,行末的回车换行符CRLF也应算是空白符。使用空白符可以对字段进行格式化,增加它的可读性。例如,每个字段间用CRLF来分离,在字段内用空格来分隔字段名和字段内容。在Subject后面的冒号和内容之间插入空格字符,会使字段结构更加清晰。在Email中,空白符的使用并没有固定的规则,但应当正确地使用,仅在需要时才使用空白符,以便接收软件进行语法分析。(2)注解注解是由括号括起来的一系列字符,例如,(这份礼物)。注解一般用在非结构化的信头字段中,没有语法语义,仅为人提供了一些附加的信息。如果在加引号的字符串中有包括在括号中的字符,那是字符串的一部分,不是注解。在解释信件的时候,会将注解忽略,可以用一个空格字符代替它们,这样就什么也不会破坏。(3)字段折叠每个信头字段从逻辑上说应当是一个由字段名、冒号、字段体和CRLF组成的单一的行,但为了书写与显示的方便,增加可读性,也为了符合1000/80第45页共51页 45的行字符数的限制,可以将超过80个字符的信头字段分为多行,即对于比较长的字段,可以分割成几行,形成折叠。在结构化和非结构化字段中都允许折叠。通过在字段中某些点插入CRLF符和至少一个或多个空白字符来实现字段的折叠,第一行后面的行称为信头字段的续行。续行都以一个空白符开始,这种方法称为折叠(folding),例如标题字段Subject:Thisisatest可以表示为:Subject:Thisisatest反之,将一个被折叠成多行的信头字段恢复到它的单行表示的过程叫做去折叠,只要简单地移除后面跟着空格的CRLF,将折叠空白符CRLF转换成空格字符,就可以完成去折叠(unfolding)。在分析被折叠的字段的语法时,要把一个多行的折叠字段展开为一行,根据它的非折叠的形式来分析它的语法与语义。(4)字段大小写字段名称是不区分大小写的,所以Subject、subject或SUBJECT都一样。不过字段名称大小写有习惯的常用形式,如主题字段的大小写形式通常为Subject。字段体的大小写稍微复杂点,要视情况而定。比如Subject后面的字段体,其中的大写可能就是缩写的专用名词,不能改动。4、标准的信头字段下面介绍RFC822中定义的常用的标准信头字段。表4.1RFC822常用的标准信头字段与发信方有关的信头字段格式:From:mailbox举例:From:wang@163.com写信人字段。说明信件的原始创建者,给出他的电子信箱地址。创建者对信件的原始内容负责。格式:Sender:mailbox第45页共51页 45举例:From:wang@163.comSender:li@sina.com发送者字段。说明实际提交发送这个信件的人,给出他的电子信箱地址。当发信人与写信人不一样时使用。比如,秘书替经理发信。发送者对发送负责。格式:Reply-TO:mailbox举例:From:wang@163.comFrom:zhao@soho.com回复字段。指定应当把回信发到哪里。如果有此字段,回信将会发给它指定的邮箱,而不会发给From字段指定的邮箱。比如,发送的是经理的信,但回信应交办公室处理。与收信方有关的信头字段格式:TO:mailboxlist举例:TO:zhang@263.com收信人字段。指定主要收信人的邮箱地址,可以是多个邮箱地址的列表,地址中间用逗号隔开。格式:Cc:mailboxlist举例:Cc:zhang@863.com抄送字段。指定此信件要同时发给哪些人,也称为抄送。也可以使用邮箱地址列表,抄送给多个人。格式:Bcc:mailboxlist密抄字段。指定此信件要同时秘密发给哪些人,也称为密件抄送。也可以使用邮箱地址列表,密抄给多个人。其它的信头字段格式:Date:date-time举例:Date:Tue,04Dec200416:18:08+800日期字段:Date字段含有电子邮件创建的日期和时间。格式:Subject:*text举例:Subject:Hello!Subject:Re:Hello!信件主题字段。描述信件的主题。当回复信件时,通常在主题前面增加“Re:”前缀,标记为该信件为回复信件:当信件被转发时,通常在主题文字前面加上“Fw:”,“Fwd:”这样的前缀。格式:Received:["from"domain];发送主机["by"domain];接收主机接受字段。是投递信件的特定邮件服务器所作的记录。处理邮件投递的每个服务器必须给它处理的每个信头的前面加一个Received第45页共51页 45["via"atom];物理路径["id"msg-id];接收者msgid字段,用以描述信件到达目的地所经过的路径以及相关信息。当跟踪各个电子邮件问题时,这个信息很有帮助。举例:Received:fromwang[195.0.0.1]byli[129.5.0.4]Tuedec200312:18:02+800格式:Comments:*text注释字段。用于把一个注解添加到信件中。格式:Resent-*举例:Resent-FromResent-SenderResent-dateResent-Reply-To重发字段。当需要把收到的信件重发给另一组收信人的时候,可以保持整个原始信件不变,并简单地产生重发信件所要求的新信头字段。为避免与以前的字段相混。新添加的信头字段都加上Resent-前缀字符串,它们的语法与未加前缀的同名字段相同。格式:Message-ID:msg-id信件标识字段。用于表示一个信件唯一标识,该字段通常有Smtp服务器生成,这个值通常是唯一的。形式根据使用的软件而定。通常左边是标识符,右边指定电脑名图27-2表中的关键字表明了电子邮件借用了办公室备忘录中的概念和术语:电子邮件的头部能够包含一行说明应当接收到该备忘录的接收方。象传统的办公室备忘录一样,电子邮件使用关键字Cc指明一个复写副本(carboncopy).电子邮件软件必须向Cc:后面的电子邮件地址表中的每个地址发送一份消息的副本。传统的办公室过程要求备忘录的发送方通知接收方副本是否传给其它人。有时发送方希望将备忘录的一个副本给别人而不显示出有一个副本被发送出去。一些电子邮件系统提供这样的选项,遵循传统的办公室术语,用盲复写副本(blindcarboncopy)来表示。创建消息的用户在关键字Bcc后给出一个电子邮件地址表,指定一个或多个盲复写副本。虽然Bcc第45页共51页 45在发送方出现,但当信息发送时,邮件系统将它从消息中除去。每个接收方必须检查头部的To和Cc行以决定信息是直接发送还是作为盲副本发送的(有些邮件系统在正文部分附加信息来告诉接收者它是一个盲副本)。其它接收者不知道有哪些用户接收到盲副本。电子邮件使用与传统的办公室备忘录相同的格式和术语:头部包括与消息有关的信息,正文包括消息文本。电子邮件头部的行说明发送方、接收方、日期、主题、应当收到副本的人的列表。(5)扩展字段如果想在信头中加入RFC822中没有规定的字段,就需要创建非标准字段。方法非常简单,只要在自定义的信头字段名的前面使用X-前缀。RFC822将这种方法称为扩展字段。事实上已经有许多扩展字段被广泛应用,但没有标准定义。例如:X-LOOP字段X-LOOP字段用来防止邮件的循环传送。过滤或邮件列表处理程序,可以给它处理的每个信件增加一个X-LOOP字段,以后就可以根据这个字段中含有的特别值,判断一个信件是否被循环传送。如果确认邮件发生了循环,过滤或邮件列表处理程序就可以用不同的方式处理该信件。◆X-Mailer字段X-Mailer字段用于指示什么样的程序产生了这个信件,它是使用最广泛的扩展字段。产生邮件的软件可以为所有发送的信件增加合适的X-Mailer第45页共51页 45字段,该字段不仅含有软件的名称,还包含软件的版本号。例如软件名为LittlefoxMailer,版本为V1.0,可以将“X-Mailer:LittlefoxMailerV1.0”加到邮件信头中去。图27-2列出了一些在因特网电子邮件中可以找到的普通关键字,以及使用它们的目的。关键字含义From发送方地址To接收方地址Cc复制副本地址Date信息创建日期Subject信息主题Reply-To回复地址X-Charset使用的字符集(通常为ASCII)X-Mailer发送信息所使用的软件X-Sender发送方地址的副本X-Face经编码的发送方面孔的图象整个系统的核心是收发信件的操作,因此为了方便维护,以后的升级,故将这两个最主要的操作写成类库(.dll)的形式,以组件的形式加载到主程序中,而且其它的功能如果需要的话,也可以通过这样的组件的形式增加到主程序中。这也体现了CSharp这一新的微软主推语言的方便和高校。而且这样做也方便了我们小组的程序的顺利结合。第45页共51页 45第5章命名控件MailSend5.1发送邮件的类SmtpMail1、主要成员变量说明1)网络连接类及实例TcpClienttc为TCP网络服务提供客户端连接类TcpClient实例对象tc。TcpClient类提供了一些简单的方法,用于在同步阻塞模式下通过网络来连接、发送和接收流数据。而实例化的过程也是连接SMTP服务器的过程。它的重载方法之一的两个参数一个为服务器名称字符串,另一个为服务器的埠。2)提供用于网络访问的基础数据流及其实例NetworkStreamns此类提供访问网络的基础数据流的方法。其中最基本也是最重要的两个方法就是Write()和Read()方法,至于参数不再次赘述。3)一维字符串数组变量FilePath此字符串数组主要用来存放用户选择的附件的绝对路径名,并在发送带附件的邮件时用到。4)发送邮件所需的基本参数比如用于ESMTP等录检验用的用户名、密码,发送邮件需要的收信人,发信人地址以及主题等等在此不再赘述。2、主要成员函数说明第45页共51页 451)重载的构造函数SmtpMail()此函数主要用于在初始化过程中,把用户选择的附件的路径以参数的形式传给FilePath。2)添加附件的函数AddAttachment传给FilePath的路径,通过这样一个函数就可以循环的动态的添加到IList接口的一个对象中了,方便以后在具体的实现的过程中的使用。3)得到上传的附件的文件流GetStream由于在网络中的操作都是以网络流的形式来实现的,因此先将上传的附件转换成文件流,然后再用Write的方法把这些附件的文件流写入到网络中,来完成发送附件的操作。具体实现代码如下所示:privatestringGetStream(stringFilePath){//建立文件流对象System.IO.FileStreamFileStr=newSystem.IO.FileStream(FilePath,System.IO.FileMode.Open);byte[]by=newbyte[System.Convert.ToInt32(FileStr.Length)];FileStr.Read(by,0,by.Length);FileStr.Close();return(System.Convert.ToBase64String(by));}4)将字符串编码为Base64字符串的函数Base64Encode第45页共51页 45由于ESMTP的LOGIN认证机制是采用Base64编码,当用户发出AUTHLOGIN的命令后,服务器返回334的应答码等待用户输入。如果身份确认后服务器返回235的应答码,否则返回失败信息。所以要将用户名和密码转换成Base64编码然后再发给服务器。此函数的作用就是把给定的字符串转换成相应的Base64编码的字符串。5)发送SMTP命令的函数SendCommand这个函数的作用是把SMTP命令的字符串转换成对应的字节型值(C#中规定的Write方法只能写入字节型的数据)然后写入网络中,如果操作成功就返回一个标志为真的布尔型变量,如果操作失败或者发生异常就返回标志为假的布尔型变量。具体代码如下所示:privateboolSendCommand(stringstr){//定义一个数组byte[]WriteBuffer;//设定一个布尔类型的变量boolstate=false;WriteBuffer=Encoding.Default.GetBytes(str);//加入防错机制,可以有效提高程序运行的效率和捕获出错信息try{//向网络中写入数据第45页共51页 45ns.Write(WriteBuffer,0,WriteBuffer.Length);state=true;}catch(Exceptionex){//返回出错信息MessageBox.Show(ex.ToString());state=false;}//返回标志位returnstate;}6)接受服务器应答的函数RecvResponse它的作用就是从网络流中读取服务器返回的字节型的信息,将其转换成字符串型的变量,然后将其返回,可以通过其返回值来判断操作是否成功。具体实现代码如下所示:privatestringRecvResponse(){intStreamSize=0;stringReturnValue="";//定义一个字节型的数组第45页共51页 45byte[]ReadBuffer=newbyte[1024];try{//从网络流中读取数据,并返回读取的个数StreamSize=ns.Read(ReadBuffer,0,ReadBuffer.Length);}catch(Exceptionex){//返回异常信息MessageBox.Show(ex.ToString());}if(StreamSize!=0){//将当前读取的信息转换成字符串型然后返回ReturnValue=Encoding.Default.GetString(ReadBuffer).Substring(0,StreamSize);}returnReturnValue;}7)重载的函数Dialog第45页共51页 45它们的作用是与服务器交互,发送命令并接收回应。不同的是参数是字符串类型的那个函数,每次发送一条命令,并接受服务器的响应,根据响应的信息来判断交互的结果是否成功。而参数是字符串数组的函数每次发送的是一组命令,用于和服务器的交互,这个函数主要是用于ESMTP服务器的验证的功能,因为验证的过程是一个等待然后又输入的过程,因此将他们放在一个数组中有利于理解和操作。而他们的实现主要是通过调用上面的发送SMTP命令函数SendCommand以及接受SMTP服务器响应的函数RecvResponse来实现的。具体的代码如下所示:privateboolDialog(stringstr,stringerrstr){boolflag=false;if(str==null||str.Trim()==""){flag=true;}if(SendCommand(str)){stringRR=RecvResponse();//从返回的数据中截取前三位stringRRCode=RR.Substring(0,3);//然后用这前三位与哈希表中正确的回应码比较第45页共51页 45if(RightCodeHT[RRCode]!=null){flag=true;}else{flag=false;}}else{flag=false;}returnflag;}发送一组命令主要用于服务器验证的重载函数为:privateboolDialog(string[]str,stringerrstr){for(inti=0;i"+enter;if(!Dialog(SendBufferstr,"发件人地址错误,或不能为空"))returnfalse;//把传过来的收件人的地址分割然后提交给服务器stringsplit=";";string[]address=Regex.Split(Recipient,split);SendBuffer=newstring[address.Length];第45页共51页 45for(inti=0;i"+enter;}if(!Dialog(SendBuffer,"收件人地址有误"))returnfalse;SendBufferstr="DATA"+enter;if(!Dialog(SendBufferstr,""))returnfalse;SendBufferstr="From:"+FromName+"<"+From+">"+enter;SendBufferstr+=enter+"."+enter;if(!Dialog(SendBufferstr,"错误信件信息"))returnfalse;SendBufferstr="QUIT"+enter;if(!Dialog(SendBufferstr,"断开连接时错误"))returnfalse;//关闭流对象ns.Close();//关闭连接tc.Close();第45页共51页 45FilePath=null;returntrue;}以上即为发送不带附件的邮件SMTP命令用代码实现的过程。为TCP网络服务提供客户端连接类TcpClient实例对象tc。TcpClient类提供了一些简单.5.2AddExtra类这个附加的小类只是提供一些返回当前系统时间,获取主机名,主机IP,有关帮助等小的功能,在此仅对帮助信息中的“关于”操作函数稍加说明。因为它说明了在CSharp中调用WindowsAPI函数所需如下几个步骤:1、导入WindowsAPI所需要的包或者类----usingSystem.Runtime.InteropServices;而调用显示关于对话框的函数ShellAbout还需要用到两个命名空间如下所示---usingSystem.Reflection;---usingSystem.Diagnostics;2、在程序中所需的API函数[DllImport("shell32.dll")]staticexternintShellAbout(IntPtrhWnd,stringszApp,stringszOtherStuff,第45页共51页 45IntPtrhIcon);1、在程序中具体的使用Assemblyass=Assembly.GetExecutingAssembly();FileVersionInfomyVersion=FileVersionInfo.GetVersionInfo(ass.Location);ShellAbout(this.Handle,"邮件收发系统#","版本"+myVersion.FileMajorPart+"."+myVersion.FileMinorPart+"."+myVersion.CompanyName,this.Icon.Handle);至此就完成了在CSharp中调用WindowsAPI函数的过程。第45页共51页 45第6章软件运行时的界面6.1新建账号用户打开软件之后,需要新建一个邮件帐号,在这个信件帐号的过程中,需要指定SMTP服务器,SMTP的端口,以及用于ESMTP验证的用户名和密码。指定这些发邮件的必须参数之后,再回到系统的主界面如下所示:图6.1图6.1新建邮件帐号界面第45页共51页 456.2发送不带附件的邮件在新建帐号的过程中已经指定了邮件地址,和帐号名称,所以默认的以这些参数来发送邮件。通过调用参数的不同程序会自动的调用相对应的代码来执行不同的操作。发送简单的邮件运行界面如下。图6.2发送纯文本邮件6.3发送带附件的邮件和简单的邮件不同之处在于多了发送附件的功能,软件模拟FoxMail第45页共51页 45里面发送邮件时,在程序的下面自动显示增添的附件的名称,以及图标等信息。并且邮件支持添加,删除,排列图标等功能。运行界面如图6.3:图6.3发送带有附件的邮件6.4验证邮件发送是否成功邮件发送出去之后,用FoxMail跟踪接收之后,证明邮件和附件都可以正常接收,具体的FoxMail的接收界面如图6.4:第45页共51页 45图6.4验证发送的邮件是否成功第45页共51页 45第7章系统测试7.1同一SMTP服务器发送纯文本的邮件测试用户登录一个服务器(测试中用的是163的SMTP服务器)来发送一封邮件的测试。而这个测试又可以分为以下方面:1、发送一封文本邮件给一个收信人测试中用163的邮箱分别往163的邮箱以及新浪的邮箱发送邮件均可以用FoxMail正常的接收到发送的普通的纯文本文件。2、发送一封文本邮件给多个收件人测试中仍然用163的邮箱同时发往不同的邮箱,通过FoxMail都可以正常的接收到。从而很好的验证了,我们的邮件发送系统支持群发的功能。7.2同一SMTP服务器发送带附件的邮件测试用户登录一个服务器(测试中用的是163的SMTP服务器)来发送一封邮件的测试。而这个测试又可以分为以下方面:1、发送一封带附件(可以是多附件)的邮件给一个收件人测试中用163的邮箱分别往163第45页共51页 45的邮箱以及新浪的邮箱发送之外,又添加了不同的邮件类型(个数分别为等于1,大于1即验证是否支持多附件的发送),用FoxMail接收之后,所有发送的纯文本信息,以及附件信息都正常无误。经过这些验证可以证明本软件支持对一个收件人发送多附件。由于带有多附件的信件,所以写入速度明显慢于纯文本邮件的速度。2、发送一封带附件(可以是多附件)的邮件给多个收件人测试中用163的邮箱分别往163的邮箱以及新浪的邮箱发送之外,又添加了不同的邮件类型(个数分别为等于1,大于1即验证是否支持多附件的发送),用FoxMail接收之后,所有发送的纯文本信息,以及附件信息都正常无误。经过这些验证可以证明本软件支持对多个收件人发送多附件。7.3不同SMTP服务器发送邮件测试这个方面的测试是指利用不同的邮箱来发送邮件,至于测试的分类雷同于利用同一服务器发送邮件的测试,所以不再此赘述。总之,通过以上的各方面的测试,使我改正了代码中的许多不合理以及错误之处,最终也证明了,我们的软件系统是支持多种服务器,支持多附件发送的群发软件。第45页共51页 45第8章结论这次编写的邮件客户端系统,我负责的是邮件的发送的功能。在熟悉了专门用于发送邮件的SMTP协议以及RFC规定的邮件的格式的基础上,运用了微软新推出的CSharp这一新型的面向对象语言的便利性和灵活性,从SMTP协议规定的底层命令做起,一步步的与服务器进行交互操作,最终实现发送多附件多接收人的功能。其中,具体的和服务器的交互操作,都封装了在SmtpMail.dll这个动态链接库里面了。而为了方便最终的调用和整合,所有的有关后台操作发送邮件的类以及其他的附加功能的类,全部都归属于MailSend这个命名空间了。在力求达到FoxMail功能的同时,又加了一点个人的思想并把它体现到了这一软件上。最主要的体现就是新建帐号的提前检测这一特色上,这一功能类似于很多Web页面的“检测新帐号”的功能,这样就免去了用户一直到确定注册完成时,才因为帐户因为已经被使用而注册失败的麻烦。总之,通过这次的编程,使我对网络编程有了一个很好的认识和锻炼,也使我对CSharp这一语言的掌握程度又上了一个新台阶,虽然编出来的软件不能和功能强大的FoxMail相提并论,但是相信它简单,易操作性,和FoxMail的很多强大但却“鸡肋”似的功能比较起来,更多了几分实用性。以后的日子,随着我技术的提高和思想的成熟,我一定会把它做的更好,更趋近于完美。第45页共51页 45致谢感谢我的父母和亲人,没有您们的包容和支持,就不会有我的今天。感谢我的导师叶树华老师,为我们提供丰富的材料,指导我们完成毕业设计。感谢我的班主任李玲老师,无论在学习上还是生活上,都给予我莫大鼓励和帮助。感谢张建华老师,给我讲解了许多CSharp的知识,使我获益匪浅。感谢MSDN中文网站的全体员工们,使我可以免费获取更多的知识。感谢CSDN技术论坛的人们,帮我解决了很多技术性的难题。感谢412的全体室友们,我们一起走过的日子,我感觉充实又快乐。感谢南京神州数码公司,虽然面试我没有通过,但是你们使我明白现实世界并不是如我想象的那么美好,使我看到自己的不足,也使我积累到了经验。感谢篮球场上和我一起挥汗如雨的哥们们,无论我身在何方,我都会记得曾经一起并肩作战的你们。感谢NBA中一样为了生存和梦想而奋斗者的球员们,为我带来精彩的比赛,激励着我追寻自己的梦想。感谢我在中北大学的四年里,所经历的一切,无论我走到哪里,我都会记得这是我生命中不可或缺的记忆。第45页共51页'