




已阅读5页,还剩8页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
SMTP邮件发送剖析封装之后的类如下:/ MySmtp.cpp: implementation of the MySmtp class./#include stdafx.h#include MailExam.h#include MySmtp.h#include ZBase64.h#ifdef _DEBUG#undef THIS_FILEstatic char THIS_FILE=_FILE_;#define new DEBUG_NEW#endif#define COPYRIGHT Smtp Client/ 版权信息#define BOUNDARY / 边界字符串/ Construction/Destruction/MySmtp:MySmtp()MySmtp:MySmtp()bool MySmtp:CreateSocket()/创建一个Socketif(WSAStartup(0x0101, &m_WSADATA) != 0)/至此socket版本是2.2,第一个参数也可以是MAKEWORD( 2, 2 )ReleaseSocket();return false;/创建失败if( (m_SOCKET= socket(AF_INET,SOCK_STREAM, 0) = INVALID_SOCKET)ReleaseSocket();return false;return true;/通过和比较码比较来发现是否响应成功bool MySmtp:CheckResponse(const char* RecvCode)/将收到的和对应的码字比较,判断是否发生错误char buf1024 = 0;if(recv(m_SOCKET,buf,1024,0) = SOCKET_ERROR)return false;else return buf0 = RecvCode0 & buf1 = RecvCode1&buf2 = RecvCode2 ? true : false;bool MySmtp:Connect(const string SmtpAddr,const int Port)if(!CreateSocket()return false;/得到主机(要发送给的SMTP地址如)地址,并将相应的信息写入m_HOSTENT,/就是在那个字符串中查找到相应信息并且构造一个结构体HOSTENT(这个记录了很多信息,不仅仅是地址)if(m_HOSTENT = gethostbyname(SmtpAddr.c_str() = NULL) /将传入的主机参数给m_HOSTENTreturn false;/ AfxMessageBox(m_HOSTENT-h_name);/调试用的,找到HOSTENT的结构内容/ AfxMessageBox(*m_HOSTENT-h_aliases);if(m_HOSTENT-h_addr_list0 = NULL)/地址列表为空ReleaseSocket();return false;/ AfxMessageBox(m_HOSTENT-h_addr_list0);/ AfxMessageBox(m_HOSTENT-h_addr_list1);memset(&m_SOCKADDR_IN,0,sizeof(m_SOCKADDR_IN);/将这个SOCKET和主机地址联系起来,其实WinSoket中,m_HOSTENT和m_SOCKADDR_IN都是表示的主机地址,也就是目的地的地址/m_SOCKADDR_IN.sin_family = AF_INET;m_SOCKADDR_IN.sin_addr.S_un.S_addr = *(ULONG *) m_HOSTENT-h_addr_list0;m_SOCKADDR_IN.sin_port = htons(Port);/ u_long tmp = *(ULONG *) m_HOSTENT-h_addr_list0;/ char newstring30;/ sprintf(newstring,%d,tmp);/ AfxMessageBox(newstring);/进行连接if(connect(m_SOCKET,(sockaddr *)&m_SOCKADDR_IN,sizeof(m_SOCKADDR_IN) = SOCKET_ERROR)ReleaseSocket();return false;if(!CheckResponse(220) return false;/服务准备就绪/向服务器发送HELO +服务器名string strTmp=HELO +SmtpAddr+rn;if(send(m_SOCKET,strTmp.c_str(),strTmp.length(),0) = SOCKET_ERROR)ReleaseSocket();return false;if(!CheckResponse(250) return false;/请求操作就绪return true;void MySmtp:ReleaseSocket()shutdown(m_SOCKET,SD_BOTH);closesocket(m_SOCKET);WSACleanup();bool MySmtp:SendData(const string SendFrom, const string SendToList, const string SenderName, const string ReceiverName, const string Subject, const string Content )if(SendFrom.empty()return false;/源地址是空的if(SendToList.empty() return false; /目的地址为空string strTmp;ZBase64 base64;/发送MAIL FROM:strTmp=MAIL FROM:rn;if(send(m_SOCKET,strTmp.c_str(),strTmp.length(),0) = SOCKET_ERROR)ReleaseSocket();return false;if(!CheckResponse(250) return false;/发送RCPT To:strTmp=RCPT To:rn;if(send(m_SOCKET,strTmp.c_str(),strTmp.length(),0) = SOCKET_ERROR)ReleaseSocket();return false;if(!CheckResponse(250) return false;/发送DATArnif(send(m_SOCKET,DATArn,strlen(DATArn),0) = SOCKET_ERROR)ReleaseSocket();return false;if(!CheckResponse(354) return false;/Mail From:SenderNamernstrTmp=From:+SenderName+rn;/Subject: 邮件主题rnstrTmp+=Subject:+Subject+rn;/MIME_Version:1.0rnstrTmp+=MIME_Version:1.0rn;/X-Mailer:Smtp Client By xxx/版权信息strTmp+=X-Mailer:; strTmp+=COPYRIGHT; strTmp+=rn;/MIME_Version:1.0rnstrTmp+=MIME_Version:1.0rn;/Content-type:multipart/mixed;Boundary=xxxrnrn;strTmp+=Content-type:multipart/mixed;Boundary=;strTmp+=BOUNDARY;strTmp+=rnrn;/先将HEADER部分发送过去if(send(m_SOCKET,strTmp.c_str(),strTmp.length(),0) = SOCKET_ERROR)ReleaseSocket();return false;/邮件主体strTmp=-;strTmp+=BOUNDARY;strTmp+=rn;strTmp+= Content-type:text/plain;Charset=gb2312rn;strTmp+=Content-Transfer-Encoding:8bitrnrn;/邮件内容strTmp+=Content+rnrn;/将邮件内容发送出去if(send(m_SOCKET,strTmp.c_str(),strTmp.length(),0) = SOCKET_ERROR)ReleaseSocket();return false;strTmp=-;strTmp+=BOUNDARY;strTmp+=-rn.rn;if(send(m_SOCKET,strTmp.c_str(),strTmp.length(),0) = SOCKET_ERROR)ReleaseSocket();return false;if(!CheckResponse(250) return false;/退出if(send(m_SOCKET,QUITrn,strlen(QUITrn),0) = SOCKET_ERROR)ReleaseSocket();return false;if(!CheckResponse(221) return false;ReleaseSocket();return true;bool MySmtp:Validate(const string Username,const string Password)ZBase64 base64;/发送AUTH LOGINif(send(m_SOCKET,AUTH LOGINrn,strlen(AUTH LOGINrn),0) = SOCKET_ERROR)ReleaseSocket();return false;if(!CheckResponse(334) return false;/发送经base64编码的用户名string strUserName=base64.Encode(unsigned char *)Username.c_str(),Username.length()+rn;if(send(m_SOCKET,strUserName.c_str(),strUserName.length(),0) = SOCKET_ERROR)ReleaseSocket();return false;if(!CheckResponse(334) return false;/发送经base64编码的密码string strPassword=base64.Encode(unsigned char *)Password.c_str(),Password.length()+rn;if(send(m_SOCKET,strPassword.c_str(),strPassword.length(),0) = SOCKET_ERROR)ReleaseSocket();return false;if(!CheckResponse(235) return false;return true;具体如何调用的是用这个实现:void CMailExamDlg:OnOK() / TODO: Add extra validation hereMySmtp smtp;CString strSmtpAddr,strAccount,strPasswrod;GetDlgItemText(IDC_EDIT1,strSmtpAddr);GetDlgItemText(IDC_EDIT2,strAccount);GetDlgItemText(IDC_EDIT3,strPasswrod);if(!smtp.Connect(LPSTR)(LPCTSTR)strSmtpAddr,25)AfxMessageBox(连接服务器失败!); return ;/验证用户名密码if(!smtp.Validate(LPSTR)(LPCTSTR)strAccount,(LPSTR)(LPCTSTR)strPasswrod)AfxMessageBox(用户名或密码失败!); return ;CString SendFrom,SendToList,SenderName,RecevierName,Subject,Content;GetDlgItemText(IDC_EDIT4,SendFrom);GetDlgItemText(IDC_EDIT5,SendToList);GetDlgItemText(IDC_EDIT6,Content);GetDlgItemText(IDC_EDIT7,SenderName);GetDlgItemText(IDC_EDIT8,RecevierName);GetDlgItemText(IDC_EDIT9,Subject);/发送if(!smtp.SendData(LPSTR)(LPCTSTR)SendFrom,(LPSTR)(LPCTSTR)SendToList,(LPSTR)(LPCTSTR)SenderName,(LPSTR)(LPCTSTR)RecevierName,(LPSTR)(LPCTSTR)Subject,(LPSTR)(LPCTSTR)Content)AfxMessageBox(邮件发送失败!); return ;AfxMessageBox(邮件发送成功!);/CDialog:OnOK();实际上本质就是,1,连接Connect,2,验证账户密码Validate,3,发送数据最核心的部分:如何实现MySmtp?首先看看类视图,看看这个封装的类到底实现了哪些功能: 在这个部分,关键的是:connect,Validate,checkResponse,SendData,CreateSocket这些函数,分别来说明:CreateSocket: 创建Socket,利用Socket来编写邮件客户端,就是需要利用到Socket来作为一个门户啊,关于socket的解释,这里不再多说,由于是用的Windows下面的平台,所以需要用到的WinSock来编写,对应的就需要一定的规则。具体来说就是需要WSAStartup来这个函数是应用程序应该第一个调用的Winsock API 函数,以完成一系列初始化的工作。必不可少!其次,就是需要完成真正的创建,所以调用Socket函数来实现,创建后的返回值就是一个SOCKET对象,需要保存它,因此专门定义一个类成员m_SOCKET来保存这个变量,使得以后不管是发送还是接受,都可以用这个变量来实现(前面已经说了,socket对象就是一个门户,需要通过它来发送和接收)checkResponse :需要通过这个函数来实时的检查状态,比如发送是否成功,并且可以得到相应的错误信息,也便于调试。验证从服务器返回的前三位代码和传递进来的参数是否一样 备注: 211 帮助返回系统状态 214 帮助信息 220 服务准备就绪 221 关闭连接 235 用户验证成功 250 请求操作就绪 251 用户不在本地,转寄到其他路径 334 等待用户输入验证信息 354 开始邮件输入 421 服务不可用 450 操作未执行,邮箱忙 451 操作中止,本地错误 452 操作未执行,存储空间不足 500 命令不可识别或语言错误 501 参数语法错误 502 命令不支技 503 命令顺序错误 504 命令参数不支持 550 操作未执行,邮箱不可用 551 非本地用户 552 中止存储空间不足 553 操作未执行,邮箱名不正确 554 传输失败为此,需要从socket接收数据,然后和标准的这些码字,比如554来进行比较,通过比较的结果来决定是否响应正确,确定后面是否传输!具体的函数实际上就是一个recv来实现。而接收的结果,需要存放下来,然后手动比较,就有了return buf0 = RecvCode0 & buf1 = RecvCode1&buf2 = RecvCode2 ? true : false;The recv function receives data from a connected or bound socket.Connect:连接部分其实也是一个很简单的功能,就是要发送一个HELO + 服务器名,但是注意这个之前,需要完成一些操作。首先,就是要建立连接,让它知道我要连接它,用connect函数。向对方主动提出连接请求。其次就是如何发送?当然是通过socket发送,调用send函数来实现了(都是底层的API),但是,由于是第一次发送,所以需要创建socket,所以调用了前面的CreateSocket来创建,(注意,代码中多出用到了判断语句,因为网络中很容易就出现错误,所以需要实时的进行if判断,及时定位错误,否则后面的编码就容易出错而不知道如何编写),然后就是要根据send函数的参数来调用了。对于connect函数,根据API原型,需要SOCKADDR_IN类型的参数,也就是记录了远程主机(服务器)的地址信息的东西。我们可以知道的就只用(这里以新浪邮箱为例),所以需要的操作就是,首先获取主机名,得到一个HOSTENT的结构体,调用gethostbyname,这个函数的作用就是传入一个主机名,如上面的,它会自动的创建一个HOSTENT结构体,并用相应的主机信息来填充它。当然,这个还不够,需要对于SOCKADDR_IN的其它部分赋值,所以需要其它的操作,对于类变量m_SOCKADDR_IN进行初始化,完成之后,就可以调用connect函数了,如果建立成功否则一般的SOCKADDR_IN初始化是:m_SOCKADDR_IN.sin_family = AF_INET;m_SOCKADDR_IN.sin_addr.S_un.S_addr = *(ULONG *) m_HOSTENT-h_addr_list0;m_SOCKADDR_IN.sin_port = htons(Port);完成上面的一步之后,剩下来的就是发送第一个数据报文HELO来“打个招呼”了,这个很简单,因为是有具体的规定,所以不难得到:/向服务器发送HELO +服务器名send(m_SOCKET,strTmp.c_str(),strTmp.length(),0)注意完成之后可以及时的调用CheckResponse来检测结果!Validate:验证密码的正确性是一个很重要的步骤。首先发送一个报文请求服务器响应,根据得到的信息
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 多边气候变化可持续发展议程的构建-洞察及研究
- 传统医学传承创新-洞察及研究
- 省略号处理框架-洞察及研究
- 感知数据融合处理-洞察及研究
- 专家网络构建策略-洞察及研究
- 船舶货物储存细则
- 物业管理中的员工培训与素质提升
- 北京市妙峰山林场可燃物含水率:多因子解析与精准预测模型构建
- 利率市场化浪潮下房地产行业投融资的变革与创新之路
- LTE-A波束赋形算法的深度剖析与FPGA硬件实现探究
- 2025年年公租房租赁合同范本
- 脊柱骨科课件教学
- 物业服务培训课件大纲
- 2025至2030中国原果浆行业项目调研及市场前景预测评估报告
- 家庭教育指导行业2025年市场规模与增长趋势报告
- 商场装修合同
- 急性腹泻病教学课件
- 2025年版住宅房屋租赁合同范本下载
- 2-5跨学科实践制作隔音房间模型八年级物理学案人教版
- 房屋学位租赁合同协议书
- 2025年高速公路标杆企业组织效能报告
评论
0/150
提交评论