收发电子邮件实例程序参考.docx
- 文档编号:11615483
- 上传时间:2023-03-28
- 格式:DOCX
- 页数:54
- 大小:51.95KB
收发电子邮件实例程序参考.docx
《收发电子邮件实例程序参考.docx》由会员分享,可在线阅读,更多相关《收发电子邮件实例程序参考.docx(54页珍藏版)》请在冰豆网上搜索。
收发电子邮件实例程序参考
7.6接收电子邮件的程序实例
7.6.1实例程序的目的和实现的技术要点
通过这个实例,读者可以进一步了解POP3的有关原理和内容。
程序的用户界面如图7.6所示:
图7.6pop3电子邮件接收程序的用户界面
这个实例不太复杂,用户可以利用某个网站的pop3电子邮件接收服务器来接收你在该网站的电子邮箱里的信件。
首先填入pop3服务器地址、邮箱用户名和口令,并决定是否要删除邮箱里的邮件;然后点击“连接”按钮,程序会与服务器建立TCP连接,然后发送用户名和口令,经过验证,进入POP3会话。
通过命令交互,将邮箱中的所有邮件取回。
在此过程中,左下方的多文本列表框(RichTextBox)会显示全部的会话信息。
信件全部下载完毕后,左上方的组合列表框中就有了所有信件的标题字段。
用户可以从中选择一封信件,查看或者存储。
然后可以断开连接。
实例只介绍了接收邮件,提取信头标题字段的有关内容,能正确显示符合Rfc822规范的邮件。
由于目前邮件结构非常复杂,限于篇幅,程序没有对收到的信件作进一步的分析,也没有对编码的信息进行译码,读者看到的是收信的原始信息,有兴趣的读者可以进一步扩展程序的功能,例如,对信件进行MIME格式分析,将附件提取出来。
程序实现的技术要点是:
1.运用Windows的消息驱动机制
除了由MFC创建的应用程序类和对话框类以外,程序从CAsyncSocket类派生了自己的套接字类,并为它添加了OnConnect()、OnClose()和OnReceive()三个事件处理函数。
程序的会话过程几乎完全是由FD_READ消息驱动的。
建立连接后,服务器会返回信息,接到命令后,服务器也会返回信息。
当信息到达客户端套接字的接收缓冲区时,会触发FD_READ消息,并自动执行OnReceive()函数。
该函数接收服务器发来的信息,进行分析处理,然后再发送相应的命令。
这命令又会引来服务器的响应,又会触发客户端的FD_READ消息。
如此周而复始,完成POP会话的全过程。
2.通过状态转换来控制会话命令的发布顺序
程序定义了一个枚举类型STATE,并为套接字类定义了一个STATE类型的变量state,用来表示POP会话的实际状态。
容易看出,枚举的成员符号是客户端向POP3服务器发送的命令。
typedefenum
{FIRST=0,USER,PASS,STAT,LIST,RETR,ENDRETR,DELE,GOON}STATE;
STATEstate;
当用户点击“连接”按钮与服务器建立TCP连接时,将state置为初值FIRST;然后,每当收到服务器的信息,一方面根据会话的当前状态作响应的分析处理,决定应当继续发送哪条命令,另一方面发出下一个命令以后,改变state的值,将它置为该命令的状态对应的值,这就实现了会话过程中的状态转换,并保证会话按照既定的顺序进行。
读者可仔细分析mySock:
:
AnalyzeMsg()函数。
3.用结构向量来缓存信件信息
首先程序定义了一个结构类型,用来缓存一封信件信息。
typedefstruct
{
CStringtext;//存储信件的文本
intmsgSize;//信件的大小
intretrSize;//信件实际下载的大小,在下载过程中动态变化
}MESSAGEPROP;
然后为套接字类定义了一个向量型的成员变量,相当于一个数组,其成员是上述的结构。
vector
在pop会话中,一次性地将信箱中所有信件的信息转入这个向量,然后可以查阅,存储到文件中,或者进行其他处理。
7.6.2创建应用程序的过程
1.使用MFCAppWizard创建应用程序框架
工程名是pop3,应用程序的类型是基于对话框的,对话框的标题是“接收电子邮件客户端程序”,需要WindowsSockets的支持,其它部分接受系统的默认设置就可以。
向导自动为应用程序创建了两个类:
应用程序类:
CPop3App,基类是CWinApp,对应的文件是pop3.h和pop3.cpp。
对话框类:
CPop3Dlg,基类是CDialog,对应的文件是pop3Dlg.h和pop3Dlg.cpp。
2.为对话框添加控件
在程序的主对话框界面中按照图7.6添加相应的可视控件对象,并按照表7.6修改控件的属性。
表7.6对话框中的控件属性
控件类型
控件ID
Caption
静态文本statictext
IDC_STATIC
pop3服务器地址
静态文本statictext
IDC_STATIC
用户名
静态文本statictext
IDC_STATIC
口令
编辑框editbox
IDC_EDIT_SERVER
编辑框editbox
IDC_EDIT_USER
编辑框editbox
IDC_EDIT_PASS
复选框CheckBox
IDC_CHECK_DEL
删除邮箱中的邮件
多文本框RichEditBox
IDC_RICH_INFO
组合选择框ComboBox
IDC_COMB_LIST
(DropList型)
命令按钮button
IDC_BTN_CONN
连接
命令按钮button
IDC_BTN_DISC
断开
命令按钮button
IDCANCAL
取消
命令按钮button
IDC_BTN_VIEW
查看邮件
命令按钮button
IDC_BTN_SAVE
存储
3.定义控件的成员变量
按照表7.7,用类向导(ClassWizard)为对话框中的控件对象定义相应的成员变量。
表7.7控件对象的成员变量
控件ID
ControlIDs
变量名称
MemberVariableName
变量类别
Category
变量类型
VariableType
IDC_EDIT_SERVER
m_strServer
Value
CString
IDC_EDIT_USER
m_strUser
Value
CString
IDC_EDIT_PASS
m_strPass
Value
CString
IDC_CHECK_DEL
m_bolDel
Value
BOOL
IDC_COMB_LIST
m_ctrList
Control
CComboBox
IDC_RICH_INFO
m_Info
Value
CString
m_ctrlnfo
Control
CRichEditCtrl
4.为对话框中的控件对象添加事件响应函数
按照表7.8,用类向导(ClassWizard)为对话框中的控件对象添加事件响应函数。
表7.8对话框控件的事件响应函数
控件类型
对象标识ObjectID
消息Message
函数Memberfunctions
命令按钮
IDC_BTN_CONN
BN_CLICKED
OnBtnConn
命令按钮
IDC_BTN_DISC
BN_CLICKED
OnBtnDisc
命令按钮
IDC_BTN_VIEW
BN_CLICKED
OnBtnView
命令按钮
IDC_BTN_SAVE
BN_CLICKED
OnBtnSave
5.为Cpop3Dlg类添加其它的成员
voidDisp(LONGflag);//在不同的会话阶段显示不同的信息
mySockpop3Socket;//套接字类对象实例
6.创建从CAsyncSocket类继承的派生类
为了能够捕获并响应socket事件,应创建用户自己的套接字类,可利用类向导添加。
ClassType选择MFCClass,类名为mySock,基类是CAsyncSocket类,创建后对应的文件是mysock.h和mysock.cpp。
在利用类向导为mysock类添加OnConnect,OnClose和OnReceive三个事件处理函数,并为它添加一般的成员函数和变量。
可参看下一小节的程序代码。
7.手工添加包含语句以及事件函数和成员函数的代码
8.分阶段编译执行,进行测试
7.6.3程序清单
1.CPop3App应用程序类对应的文件
pop3.h不动,在pop3.cpp的InitInstance()函数中添加一句初始化多文本框控件的函数。
BOOLCPop3App:
:
InitInstance()
{
if(!
AfxSocketInit())
{
AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
returnFALSE;
}
AfxEnableControlContainer();//MFC自动创建的代码
AfxInitRichEdit();//用户添加的
...............
}
2.CPop3Dlg对话框类对应的文件
(1)pop3Dlg.h包含文件
.........
#include"mySock.h"//添加套接字类的包含文件
.........
classCPop3Dlg:
publicCDialog
{
//Construction
public:
voidDisp(LONGflag);//在不同的会话阶段显示不同的信息
mySockpop3Socket;//套接字类对象实例
CPop3Dlg(CWnd*pParent=NULL);//standardconstructor
...........
(2)pop3Dlg.cpp实现文件
#include"stdafx.h"
#include"pop3.h"
#include"pop3Dlg.h"
#include"mySock.h"//手工添加的包含语句
...................
BOOLCPop3Dlg:
:
OnInitDialog()
{
.............
//TODO:
Addextrainitializationhere
//用户在这里添加控件成员变量的初始化代码
m_strServer=_T("");//POP3服务器地址
m_strUser=_T("example");//邮箱的用户名
m_strPass=_T("123456");//口令
m_bolDel=FALSE;//下载邮件后不删除
m_Info=_T("");//多文本框清空
returnTRUE;//returnTRUEunlessyousetthefocustoacontrol
}
.................
//以下是事件处理函数和其他成员函数的代码
//当用户点击"连接"按钮时,执行此函数
voidCPop3Dlg:
:
OnBtnConn()
{
//设定pop3类的对话框指针变量,使之指向本对话框,以便传递信息
pop3Socket.SetParent(this);
UpdateData(TRUE);//取来用户在对话框中输入的数据
pop3Socket.Create();//创建套接字对象的底层套接字
pop3Socket.Connect((LPCSTR)m_strServer,110);//连接pop3服务器
m_Info="";//多文本列表框清空
UpdateData(FALSE);//更新用户界面
}
//当用户点击"断开"按钮时,执行此函数
voidCPop3Dlg:
:
OnBtnDisc()
{
pop3Socket.Close();
}
//当用户点击"查看邮件"按钮时,执行此函数
voidCPop3Dlg:
:
OnBtnView()
{
inti;
i=m_ctrList.GetCurSel();//获得用户在组合框中的选择
//获得并显示指定信件的基本属性及信件内容
m_Info+=pop3Socket.GetMsgStuff(i);
m_Info+=pop3Socket.GetMsgBody(i);
}
//在不同的情况下,向用户显示不同的信息
voidCPop3Dlg:
:
Disp(LONGflag)
{
CStrings;
switch(flag)
{
caseS_CONNECT:
//已连接到服务器,显示信息
s="已连接到"+m_strServer+"...\r\n";
m_Info+=s;
//禁用连接按钮
GetDlgItem(IDC_BTN_CONN)->EnableWindow(FALSE);
//启用断开按钮
GetDlgItem(IDC_BTN_DISC)->EnableWindow(TRUE);
//禁用查看邮件按钮
GetDlgItem(IDC_BTN_VIEW)->EnableWindow(FALSE);
break;
caseS_RECEIVE:
//收到服务器发来的响应,显示它的内容
m_Info+=pop3Socket.lastMsg;
break;
caseS_CLOSE:
//显示关闭连接的信息
m_Info+=pop3Socket.error;
s="连接已经关闭\r\n";
m_Info+=s;
//启用连接按钮
GetDlgItem(IDC_BTN_CONN)->EnableWindow(TRUE);
//禁用断开按钮
GetDlgItem(IDC_BTN_DISC)->EnableWindow(FALSE);
break;
caseS_GETNUM:
//已经知道了邮箱中信件的总数
s.Format("邮箱中共有%d封信\r\n",pop3Socket.numMsg);
m_Info+=s;
break;
caseS_GETSIZE:
//显示信件的大小
s.Format("信箱中信件大小为:
%d字节\r\n",pop3Socket.sizeMsg);
m_Info+=s;
break;
caseS_ENDRETR:
//所有信件已下载完毕,显示信息
s.Format("共下载了%d封信件\r\n",pop3Socket.msgs.size());
m_Info+=s;
//如果有信件下载,启用查看邮件按钮
if((pop3Socket.msgs.size())>0)
GetDlgItem(IDC_BTN_VIEW)->EnableWindow(TRUE);
break;
}
UpdateData(FALSE);//更新用户界面
}
//当点击“存储”按钮时,执行此函数。
voidCPop3Dlg:
:
OnBtnSave()
{
inti;
CStrings;
i=m_ctrList.GetCurSel();
//获得指定信件的基本属性及信件内容
s=pop3Socket.GetMsgStuff(i);
s+=pop3Socket.GetMsgBody(i);
CFileDialogdlg(FALSE);
if(dlg.DoModal()==IDOK)
{
CFilefile(dlg.GetPathName(),
CFile:
:
modeCreate|CFile:
:
modeWrite|CFile:
:
typeBinary);
file.Write((LPCSTR)s,s.GetLength());
file.Close();
}
}
3.mySock套接字类对应的文件
(1)mysock.h包含文件
............
#include
#include
#include
usingnamespacestd;
classCPop3Dlg;
//显示不同信息的标志
#defineS_CLOSE1//当关闭连接时,显示关闭信息
#defineS_CONNECT2//当连接成功时,显示连接信息
#defineS_RECEIVE3//当收到服务器发来的信息时,显示该信息
#defineS_GETNUM4//当所有信件下载完毕后,显示信箱中的信件总数
#defineS_GETSIZE5//当所有信件下载完毕后,显示信箱中的信件总大小
#defineS_ENDRETR6//当所有信件下载完毕后,显示相关信息
//描述pop3会话状态的枚举类型
typedefenum
{FIRST=0,USER,PASS,STAT,LIST,RETR,ENDRETR,DELE,GOON}STATE;
//用来缓存一封信件信息的结构
typedefstruct
{
CStringtext;//存储信件的文本
intmsgSize;//信件的大小
intretrSize;//信件实际下载的大小,在下载过程中动态变化
}MESSAGEPROP;
//自己的套接字类
classmySock:
publicCAsyncSocket
{
//Attributes
public:
CStringlastMsg;
CStringerror;
intnumMsg,sizeMsg,retrMsg;
vector
//Operations
public:
//获得基本的邮件信头字段:
From,To,Date,Subject,Body
CStringGetMsgStuff(inti);
CStringGetMsgBody(inti);//获得信件体
CStringGetMsgSubject(inti);//获得信件标题
CStringGetMsg(inti);//获得整封信的内容
voidClose();//退出服务器
voidSetParent(CPop3Dlg*pDlg);
mySock();
virtual~mySock();
//Overrides
public:
//ClassWizardgeneratedvirtualfunctionoverrides
//{{AFX_VIRTUAL(mySock)
public:
virtualvoidOnConnect(intnErrorCode);
virtualvoidOnClose(intnErrorCode);
virtualvoidOnReceive(intnErrorCode);
//}}AFX_VIRTUAL
//Generatedmessagemapfunctions
//{{AFX_MSG(mySock)
//NOTE-theClassWizardwilladdandremovememberfunctionshere.
//}}AFX_MSG
//Implementation
protected:
private:
voidReadLn(intindex,CStringsrc,CString&dst);
voidAnalyzeMsg();
CPop3Dlg*m_pDlg;
STATEstate;
intdelMsg;
};
..............
(2)mysock.cpp实现文件
#include"stdafx.h"
#include"pop3.h"
#include"mySock.h"
#include"pop3Dlg.h"//自己添加的包含语句
................
#defineMAX_BUFF20000
//构造函数,对某些成员变量初始化
mySock:
:
mySock()
{
m_pDlg=NULL;
state=FIRST;
error="Notconnectedtoserver\r\n";
}
mySock:
:
~mySock()
{
m_pDlg=NULL;
}
...................
//如果连接成功,执行此函数。
//接到此消息仅仅显示了一句话,开关了一些按钮连接成功后,服务器发来响应,因此
//又立即收到了OnReceive消息,后来的会话过程中,一来一往,程序总是收到
//OnReceive消息,所以真正的事情在那里作。
voidmySock:
:
OnConnect(intnErrorCode)
{
if(nErrorCode==0)m_pDlg->Disp(S_CONNECT);
}
//服务器端关闭连接,才会收到此消息。
voidmySock:
:
OnClose(intnErrorCode)
{
if(nErrorCode==0)m_pDlg->Disp(S_CLOSE);
}
//套接字收到服务器发来的数据时,执行此函数
voidmySock:
:
OnReceive(intnErrorCode)
{
if(nErrorCode==0)
{
charbuff[MAX_BUFF];//接收缓冲区
intrec=Receive(buff,MAX_BUFF);//接收服务器发来的数据
buff[rec]=NULL;//结尾置为NULL。
lastMsg=buff;
AnalyzeMsg();//分析收到的数据,作不同的处理
}else{
error="在接收数据时发送了错误!
\r\n";
m_pDlg->Disp(S_CLOSE);//显示信息
}
}
//设置套接字类的对话框指针变量
voidmySock:
:
SetParent(CPop3Dlg*pDlg)
{
m_pDlg=pDlg;
}
//获得第i封信件的标题信息
CStringmySock:
:
GetMsgStuff(inti)
{
CStringret;
intwhere=msgs[i].text.Find("From:
");
ReadLn(where,msgs[i].text,ret);
ret+="\r\n";
where=msgs[i].text.Find("To:
");
if(where!
=-1)
{
ReadLn(where,msgs[i].text,ret);
ret+="\r\n";
}
where=msgs[i].text.Find("Date:
");
if(where!
=-1)
{
ReadLn(where,msgs[i].text,ret);
ret+="\r\n";
}
ret+=GetMsgSubject(i);
ret+="\r\n";
returnret;
}
//获得第i封信件的信件体
CStringmySock:
:
GetMsgBody(inti)
{
CStringret;
intwhere=msgs[i].text.Find("\r\n\r\n");
if(where!
=-1)where+=4;
else
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 收发 电子邮件 实例 程序 参考