第5章 SMTP与POP3应用编程.docx
- 文档编号:9852491
- 上传时间:2023-02-07
- 格式:DOCX
- 页数:24
- 大小:86.25KB
第5章 SMTP与POP3应用编程.docx
《第5章 SMTP与POP3应用编程.docx》由会员分享,可在线阅读,更多相关《第5章 SMTP与POP3应用编程.docx(24页珍藏版)》请在冰豆网上搜索。
第5章SMTP与POP3应用编程
第5章SMTP与POP3应用编程
随着互联网的普及,电子邮件已经成为人们日常工作、生活中必不可少的通讯工具。
本章主要介绍如何利用SMTP与POP3协议实现邮件的发送和接收。
5.1通过应用程序发送电子邮件
不论是Windows应用程序还是Web应用程序,实现电子邮件的收发都是常用的功能,比如要求用户以邮件方式提供反馈信息;在办公系统中定时检测用户指定的邮件,并及时提醒用户查看等。
5.1.1SMTP协议
电子邮件是通过SMTP服务器进行发送的,SMTP是英文SimpleMailTransferProtocol的缩写,意为简单邮件传输协议,默认端口为25。
使用SMTP协议发送邮件时,有两种形式,一种是不使用客户端认证,即客户端可以使用匿名方式发送邮件,这种方式即是一般的SMTP协议;另一种要求客户端必须提供用户名密码,这种方式称为ESMTP协议,即ExtendedSMTP,或者叫扩展SMTP。
ESMTP与SMTP的区别除了是否需要认证以外,其他均相同。
客户端发送电子邮件过程是:
先通过客户端软件将邮件发送到SMTP邮件服务器,然后再由SMTP邮件服务器发送到目标SMTP邮件服务器。
提供客户端软件的方式有两种,一种是Windows应用程序客户端软件,例如安装Windows操作系统时自动安装的OutlookExpress;另一种是提供SMTP服务的公司提供的Web应用程序,该Web应用程序相对于邮件客户是服务器,但相对于SMTP服务器则是客户端。
例如网站提供的邮件收发服务。
对于邮件接收者来说,接收邮件时,首先通过POP3协议与SMTP邮件服务器连接,POP的意思是PostOfficeProtocol,即邮局协议,用于电子邮件的接收。
现在常用的是第三版,简称POP3。
通过POP3协议,客户机登录到服务器后,可以对指定的邮件进行删除或是下载到本地。
为了避免或者减少垃圾邮件,目前大部分SMTP邮件服务器一般均采用用户名密码认证的方式。
在SMTP协议中,电子邮件由三部分组成,信封、首部和正文。
1)信封
信封包括发信人的邮件地址和接收人的邮件地址,用两条SMTP命令指明。
①MAILFROM:
<发信人的地址>,告诉SMTP服务器发信人的地址。
②RCPTTO:
<收信人的地址>,告诉SMTP服务器收信人的地址。
2)首部
首部中常用命令:
①FROM:
<姓名><邮件地址>,表明邮件发送者是谁。
②TO:
<姓名><邮件地址>,表明邮件接收者是谁。
③SUBJECT:
<邮件标题>,表明邮件的主题。
④DATE:
<时间>,表明发邮件的时间。
⑤REPLY-TO:
<邮件地址>,表明邮件的回复地址。
⑥Content-Type:
<邮件类型>,表明邮件包含文本、HTML超文本和附件的哪些类型。
⑦X-Priority:
<邮件优先级>,表明邮件的发送优先级。
⑧MIME-Version:
<版本>,MIME的意思是MultipurposeInternetMailExtensions,即多用途Internet邮件扩展标准,它对传输内容的消息、附件及其他的内容定义了格式。
3)正文
正文是邮件的内容。
首部以一个空行结束,再下面就是正文部分。
4)结束符号
邮件以“.”结束。
5.1.2发送邮件
从SMTP协议的介绍可以看出,发送和接收邮件的内部实现过程还是比较复杂的,如果全部从底层进行编程,需要的代码就比较多。
因此在.NET框架2.0的System.Net.Mail命名空间中提供了专门对邮件进行处理的类,从而使邮件的发送变得非常简单。
对于运行在没有专用邮件服务器的大多数客户程序而言,向SMTP服务器发送邮件需要提供用户名和密码,服务器验证成功后,才能进行发送或接收。
因此在应用程序中发送邮件,需要使用下面几个类:
1)System.Net命名空间下的NetworkCredential类
该类用于提供客户端身份验证机制的凭据。
其中包括标准Internet身份验证方法(基本、简要、协商、NTLM和Kerberos身份验证)以及可以创建的自定义方法。
在邮件发送中,我们需要使用这个类提供SMTP服务器需要的用户名和密码,用法为:
NetworkCredentialmyCredentials=newNetworkCredential("发件人邮件地址","密码");
2)System.Net.Mail命名空间下的MailAddress类
该类用于提供发件人和收件人的邮件地址,常用形式为:
MailAddressfrom=newMailAddress("发件人邮件地址");
MailAddressto=newMailAddress("收件人邮件地址");
3)System.Net.Mail命名空间下的MailMessage类
该类用于提供邮件的信息,包括主题、内容、附件、信息类型等,常用形式为:
MailMessagemessage=newMailMessage(from,to);
message.Subject="主题";
message.SubjectEncoding=System.Text.Encoding.UTF8;
message.Body="邮件内容";
message.BodyEncoding=System.Text.Encoding.UTF8;
4)System.Net.Mail命名空间下的Attachment类
该类用于提供附件对象,常用形式为:
AttachmentattachFile=newAttachment("文件名");
message.Attachments.Add(attachFile);
5)SmtpClient类
该类用于发送邮件,常用形式为:
SmtpClientclient=newSmtpClient("邮件服务器地址");
client.Send(message);
下面通过具体例子说明发送邮件的方法。
【例5-1】设计一个Windows应用程序,实现发送邮件的功能。
要求利用正则表达式验证用户输入的信息,当输入信息符合要求时,才允许将邮件发送到邮件服务器。
(1)创建一个名为SendMailExample的Windows应用程序,修改Form1.cs为FormSendMail.cs,设计界面如图5-1所示。
(2)切换到代码方式,添加对应的命名空间引用、事件与方法,源代码如下:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.ComponentModel;
usingSystem.Data;
usingSystem.Drawing;
usingSystem.Text;
usingSystem.Windows.Forms;
//添加的命名空间引用
usingSystem.Text.RegularExpressions;
usingSystem.Net;
usingSystem.Net.Mail;
namespaceSendMailExample
{
publicpartialclassFormSendMail:
Form
{
publicFormSendMail()
{
InitializeComponent();
}
//用户名(发件人地址)改变时触发
privatevoidtextBoxUserName_TextChanged(objectsender,EventArgse)
{
//要求满足电子邮件格式
labelUserName.Visible=!
Regex.IsMatch(textBoxUserName.Text,
@"^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$");
}
//密码改变时触发
privatevoidtextBoxPassword_TextChanged(objectsender,EventArgse)
{
//要求满足5-20个英文字母或数字的组合
labelPassword.Visible=!
Regex.IsMatch(textBoxPassword.Text,@"^\w{5,20}$");
}
//收件人地址改变时触发
privatevoidtextBoxReceive_TextChanged(objectsender,EventArgse)
{
//要求满足电子邮件格式
labelReceive.Visible=!
Regex.IsMatch(textBoxReceive.Text,
@"^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$");
}
//主题改变时触发
privatevoidtextBoxSubject_TextChanged(objectsender,EventArgse)
{
//不能为空
labelSubject.Visible=!
Regex.IsMatch(textBoxSubject.Text,@"^.{1,}$");
}
//发送内容改变时触发
privatevoidtextBoxBody_TextChanged(objectsender,EventArgse)
{
//不能为空
labelBody.Visible=!
Regex.IsMatch(textBoxBody.Text,@"^.{1,}$");
}
//单击【发送】按钮触发的事件
privatevoidbuttonSend_Click(objectsender,EventArgse)
{
stringinvalidString="";
if(labelUserName.Visible==true)invalidString+="用户名、";
if(labelPassword.Visible==true)invalidString+="口令、";
if(labelReceive.Visible==true)invalidString+="收件人、";
if(labelSubject.Visible==true)invalidString+="主题、";
if(labelBody.Visible==true)invalidString+="邮件内容、";
if(invalidString.Length>0)
{
MessageBox.Show(invalidString.TrimEnd('、')+
"不能为空或者有不符合规定的内容");
}
else
{
//发件人和收件人地址
MailAddressfrom=newMailAddress(textBoxUserName.Text);
MailAddressto=newMailAddress(textBoxReceive.Text);
//邮件主题、内容
MailMessagemessage=newMailMessage(from,to);
message.Subject=textBoxSubject.Text;
message.SubjectEncoding=System.Text.Encoding.UTF8;
message.Body=textBoxBody.Text;
message.BodyEncoding=System.Text.Encoding.UTF8;
//添加附件
if(listBox1.Items.Count>0)
{
for(inti=0;i { AttachmentattachFile=newAttachment(listBox1.Items[i].ToString()); message.Attachments.Add(attachFile); } } try { //大部分邮件服务器均加smtp.前缀 SmtpClientclient=newSmtpClient("smtp."+from.Host); SendMail(client,from,textBoxPassword.Text,to,message); MessageBox.Show("发送成功"); } catch(SmtpExceptionerr) { //如果错误原因是没有找到服务器,则尝试不加smtp.前缀的服务器 if(err.StatusCode==SmtpStatusCode.GeneralFailure) { try { //有些邮件服务器不加smtp.前缀 SmtpClientclient=newSmtpClient(from.Host); SendMail(client,from,textBoxPassword.Text,to,message); MessageBox.Show("发送成功"); } catch(SmtpExceptionerr1) { MessageBox.Show(err1.Message,"发送失败"); } } else { MessageBox.Show(err.Message,"发送失败"); } } } } //根据指定的参数发送邮件 privatevoidSendMail(SmtpClientclient,MailAddressfrom,stringpassword, MailAddressto,MailMessagemessage) { //不使用默认凭证,注意此句必须放在client.Credentials的上面 client.UseDefaultCredentials=false; //指定用户名、密码 client.Credentials=newNetworkCredential(from.Address,password); //邮件通过网络发送到服务器 client.DeliveryMethod=SmtpDeliveryMethod.Network; try { client.Send(message); } catch { throw; } finally { //及时释放占用的资源 message.Dispose(); } } //单击【添加附件】按钮触发的事件 privatevoidbuttonAddAttachment_Click(objectsender,EventArgse) { OpenFileDialogmyOpenFileDialog=newOpenFileDialog(); myOpenFileDialog.CheckFileExists=true; //只接收有效的文件名 myOpenFileDialog.ValidateNames=true; //允许一次选择多个文件作为附件 myOpenFileDialog.Multiselect=true; myOpenFileDialog.ShowDialog(); if(myOpenFileDialog.FileNames.Length>0) { listBox1.Items.AddRange(myOpenFileDialog.FileNames); } } } } (3)按〈F5〉键编译并执行,在用户名中输入类似于myname@形式的电子邮件地址,然后输入密码、收件人地址等信息。 单击【发送】按钮后,程序首先根据发件人的电子邮件地址找到SMTP邮件服务器,并设置邮件服务器需要的验证信息,然后调用SmtpClient对象的Send方法,指定的邮件即可发送到邮件服务器中。 注意,例子中并没有对发送失败的具体原因进行处理,而只是简单的将错误信息显示出来,也没有显示附件的大小、类型等信息,但是基本功能都已经具备了。 读者可以在此基础上进一步完善,做出符合实际需要的邮件发送程序。 5.2利用同步TCP接收电子邮件 与发送电子邮件不同,接收电子邮件主要是利用POP(PostOfficeProtocol)协议,现在常用的是第三版,简称为POP3,默认端口为110。 通过POP3协议,客户机登录到服务器后,可以对自己的邮件进行删除或下载,下载后,电子邮件客户端软件就可以在本地对邮件进行处理,随Windows操作系统一块安装的OutlookExpress就是这种工作方式。 实际上,收发邮件使用了两种协议,一种是TCP协议,用于收发数据;另一种是POP3协议,用于解析传送的命令。 5.2.1POP3工作原理 凡是提供邮件服务的系统,除了有SMTP服务器外,还有POP3服务器。 这两个服务器可能是同一台计算机,也可能是两台计算机。 POP3邮件服务器通过侦听TCP端口110提供POP3服务。 客户端软件读取邮件之前,需要事先与服务器建立TCP连接。 连接成功后,POP3服务器会向该客户端发送确认消息。 然后客户端根据服务器回送的信息决定下一步的操作。 客户端每次向POP3服务器发送命令后,都要等待服务器响应,并处理接收的信息,然后再接着发送下一个命令,如此往复多次,一直持续到连接终止。 这个过程经历了三个状态: 授权(AUTHORIZATION)状态、操作(TRANSACTION)状态和更新(UPDATE)状态。 在POP3协议中,规定的命令只有十几条。 每条命令均由命令和参数两大部分组成,而且每条命令都以回车换行结束。 命令和参数之间由空格间隔。 命令部分由三到四个字母组成,参数部分可达40个字符长度。 POP3服务器回送的响应信息由一个状态码和一个可能跟有附加信息的命令组成。 所有响应也以回车换行结束。 状态码有两种: “确定”(“+OK”)和“失败”(“-ERR”)。 对于客户端发送的每一条命令,服务器都会回送状态码。 因此在客户端程序中,可以通过服务器回送的状态码对应的字符,即判断第一个字符是“+”号还是“-”号来确定服务器是否正确响应客户端发送的命令。 1.授权状态 客户端首先与POP3服务器建立TCP连接,服务器接收后发送一个单行的确认信息。 例如“+OKPOP3serverready”,此时POP3会话就进入了授权状态。 在授权状态,客户需要向服务器发送用户名和密码进行确认。 假设用C表示客户端(Client),S表示服务器端(Server),下面是客户端接收邮件前需要与服务器传输的信息。 1)发送用户名。 语法形式: USER<用户名> 功能: 将客户的用户名发送到服务器。 服务器返回: +OK正确的用户名;-ERR错误的用户名。 示例: C: USERmyname@ S: +OKwelcomeonthisserver. 上述两行代码的含义为: 客户端发送“USERmyname@”,服务器端回送信息“+OKwelcomeonthisserver.”。 2)用户名确认成功后,需要输入密码。 语法形式: PASS<密码> 功能: 将客户的密码发送给服务器。 服务器返回: +OK正确的用户名;-OK错误的用户名。 示例: C: PASS***** S: +OKmynameloggedinat19: 04 授权成功后,进入操作状态。 2.操作状态 客户端向服务器成功确认了自己的身份后,POP3会话将进入操作状态,客户就可以执行POP3命令进行相应的操作。 对于每个命令,服务器都会返回应答信息。 下面是在操作状态中使用的命令。 (1)STAT命令 语法形式: STAT 功能: 从服务器中获取邮件总数和总字节数。 服务器返回: 邮件总数和总字节数。 示例: C: STAT S: +OK2320 (2)LIST命令 语法形式: LIST 功能: 从服务中获得邮件列表和大小。 服务器返回: 列出邮件列表和大小。 示例: C: LIST S: +OK2messages(320octets) S: 1120 S: 2200 S: . (3)RETR命令 语法形式: RETR<邮件的序号> 功能: 从服务器中获得一个邮件。 服务器返回: +OK成功;-ERR错误。 示例: C: RETR1 S: +OK120octets S: <服务器发送信件1内容> S: . 注意,这里的“.”是单独发送的。 (4)DELE命令 语法形式: DELE<邮件的序号> 功能: 服务器将邮件标记为删除,当执行QUIT命令时才真正删除。 服务器返回: +OK成功;-ERR错误。 示例: C: DELE1 S: +OK1Deleted 当客户发送QUIT命令时,会话进入更新状态。 3.更新状态 当客户在操作状态下发送QUIT命令后,会话进入更新状态。 QUIT命令 语法形式: QUIT 功能: 关闭与服务器的连接。 服务器返回: +OK;-ERR。 示例: C: QUIT S: +OK 然后服务器自动断开与该客户端的TCP连接。 5.2.2邮件接收处理 从上面的介绍可以看出,POP3协议中传送的命令并不多,而具体传送数据的过程则是通过TCP协议。 下面通过一个具体例子说明邮件的接收处理过程。 在这个例子中,我们重点关心的应该是如何利用同步TCP发送和接收数据,之所以选择邮件处理作为例子,是因为在这个例子中只需要编写客户端程序,而不需要编写服务器端程序即可正常运行。 而且例子中没有采用其他线程,因此比较容易理解。 但是目前流行的大部分TCP应用程序,均使用多线程进行处理。 因此我们的目标应该是掌握多线程TCP应用程序是如何设计的,这也是学习基于C/S编程模式的一个难点。 理解了这个比较简单的邮件接收程序以后,我们再进一步介绍另外一个稍微复杂的简化的多线程网络游戏程序,到时就不会感到太困难了。 【例5-2】利用POP3协议和同步TCP编写一个简单的邮件接收客户端程序。 (1)新建一个名为ReceiveMailExample的Windows应用程序项目,修改Form1.cs为FormReceiveMail.cs,设计窗体如图5-2所示。 (2)切换到代码方式,添加对应的引用、字段声明、方法和事件,源程序如下: usingSystem; usingSystem.Collections.Generic; usingSystem.ComponentModel; usingSystem.Data;
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第5章 SMTP与POP3应用编程 SMTP POP3 应用 编程