首页 > 代码库 > c++封装的发邮件类CSendMail

c++封装的发邮件类CSendMail

项目需要做发邮件的功能,在网上找了一下代码,比较出名的SMailer编译不过(把那个Base64的encode拉到MailSender中实现就能过,但我搞不懂原来出错的原因,就不想用),另外找到了一个CSendMail的实现类,可以用,但代码的风格不好,使用起来也不方便,所以我就参考(chao)这两个类,实现了一个比较简单的发邮件类。CSendMail类支持多个收件人,支持附件(多个)。

[原]:http://www.cnblogs.com/sixbeauty/p/3983525.html

上代码,头文件:

/***CSendMail头文件**实现邮件的发送功能,支持多个用户接收,支持附件**program by six_beauty*/#pragma once#include <string>#include <list>#include <map>#include "LogInfo.h"#include <winsock2.h>//类型定义const int MAX_BUFFER_SIZE = 255;                            //send和recv的缓存buffer的sizeconst int SERVICE_PORT=25;                                    //端口typedef std::map<std::string, std::string> RECEIVERS;//CSendMail类class CSendMail{public:    CSendMail();    ~CSendMail();//////////////////////////////////////设置邮件信息/////////////////////////////////////////////////////////////////////////////////    /////////////////////////connent///////////////////////////////////    void setServerName(const std::string server_name);        //smtp服务器地址        void setUserName(const std::string user_name);            //邮箱用户名    void setUserPwd(const std::string user_pwd);            //邮箱用户密码    /////////////////////////SendMail//////////////////////////////////    void setSenderName(const std::string sender_name);        //发送者的名字    void setSenderAddress(const std::string sender_addr);    //发送者的邮箱(mail form:)    //邮件接收者    void setReceiver(const std::string name, const std::string address);            //先clear再add    void addReceiver(const std::string name, const std::string address);            //增加邮件接收者,name是收件人名字,mail是地址    void clearReceiver();                                                            //情况邮件接收者    //添加附件    void AddFilePath(std::string szFilePath);                                        //添加附件路径到附件列表中,一般的smtp服务器处理附件不超过50MB     void DeleteFilePath(std::string szFilePath);                                    //删除附件路径,如果有的话      void DeleteAllPath();                                                            //删除全部附件的路径  /////////////////////////////////////发送邮件//////////////////////////////////////////////////////////////////////////////////////    //连接    bool Connent();    //邮件发送    bool SendMail(const std::string mail_title,const std::string send_content);        //发送邮件的函数private:    //功能函数    inline std::string& replace_all(string& str,const string& old_value,const string& new_value);       //其实就是CString的Replace    std::string GetFileName(std::string&szFilePath);        //从附件的路径中获取文件名称    std::string GetFileData(std::string szFilePath);        //以字符形式读入附件内容    std::string Base64Encode(std::string in_str);            //把char类型转换成Base64类型      //获取时间    std::string prepareDate();    //通信recv和send的封装    int     sendRequest(const std::string content,bool bout=false);                //返回发送了多少字节    bool rcvResponse(const std::string expected_response);    //返回接收的结果和expected_response是否相同    //工作函数    bool CReateSocket();                                    //建立socket连接      bool Logon();                                            //登录邮箱,主要进行发邮件前的准备工作      bool SendHead();                                        //发送邮件头      bool SendTextBody();                                    //发送邮件文本正文      bool SendFileBody();                                    //发送邮件附件      bool SendEnd();                                            //发送邮件结尾     SOCKET _socket;    LogInfo m_logInfo;    /////////////////////////邮件信息///////////////////////////////////    /////////////////////////connent///////////////////////////////////    std::string                    m_ServerName;        //smtp服务器地址    std::string                    m_UserName;            //邮箱用户    std::string                    m_UserPwd;            //邮箱用户密    /////////////////////////SendMail//////////////////////////////////    std::string                    m_SenderName;        //发送者的名        std::string                    m_SenderAddr;        //发送者的邮箱(mail form:)    std::string                    m_MailTitle;        //邮件标题(subject)    std::string                    m_TextBody;            //邮件正文    RECEIVERS                    m_Receivers;        //邮件接收者(name,email_address)    std::list<std::string>        m_FilePathList;        //附件路径_list    /////////////////////////邮件信息///////////////////////////////////};

源文件:

/***CSendMail源文件**实现邮件的发送功能,支持多个用户接收,支持附件**program by six_beauty*///#include <afx.h>#include "CSendMail.h"#include "time.h"#include <sstream>#include <fstream>#pragma comment(lib,"WSOCK32")  #pragma comment(lib, "ws2_32")const std::string _AppOctStrmContent_encode_chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";//类的实现CSendMail::CSendMail(void)  {  }  CSendMail::~CSendMail(void)  {      clearReceiver();    DeleteAllPath();}  //连接bool CSendMail::Connent(){    //邮件信息设置判断    if(m_ServerName.empty() || m_UserName.empty() || m_UserPwd.empty())    {        m_logInfo.logInfo("Connect 失败,请先设置邮件登陆信息!");        return false;    }    if(!CReateSocket())//建立连接      {          m_logInfo.logInfo("建立连接失败!");        return false;      }    if(!Logon())//建立连接      {          m_logInfo.logInfo("登陆失败!");        return false;      }    return true;}//发送邮件的函数送bool CSendMail::SendMail(const std::string mail_title,const std::string send_content)                                        {    //参数赋值    m_MailTitle=mail_title;    m_TextBody=send_content;    if(m_SenderName.empty() || m_SenderAddr.empty() || m_Receivers.empty())    {        m_logInfo.logInfo("[SendMail]邮件参数设置错误,请检查邮件发送设置信息是否完整!");        return false;    }    if(!SendHead())//发送邮件头      {          m_logInfo.logInfo("发送邮件头失败!");        return false;      }      if(!SendTextBody())//发送邮件文本部分      {          return false;      }      if(!SendFileBody())//发送附件      {          return false;      }      if(!SendEnd())//结束邮件,并关闭sock      {          return false;      }      return true;}////////////////////////////////////////////设置邮件信息/////////////////////////////////////////////////////////////////////void CSendMail::setServerName(const std::string server_name)        //smtp服务器地址    {    m_ServerName=server_name;}void CSendMail::setUserName(const std::string user_name)            //邮箱用户名{    m_UserName=user_name;}void CSendMail::setUserPwd(const std::string user_pwd)                //邮箱用户密码{    m_UserPwd=user_pwd;}void CSendMail::setSenderName(const std::string sender_name)        //发送者的名字{    m_SenderName=sender_name;}void CSendMail::setSenderAddress(const std::string sender_addr)    //发送者的邮箱(mail form:){    m_SenderAddr=sender_addr;}void CSendMail::addReceiver(const std::string name, const std::string address){    m_Receivers.insert(RECEIVERS::value_type(name, address));}void CSendMail::setReceiver(const std::string name, const std::string address){    m_Receivers.clear();    m_Receivers.insert(RECEIVERS::value_type(name, address));}void CSendMail::clearReceiver(){    m_Receivers.clear();}void CSendMail::AddFilePath(std::string szFilePath)//添加附件路径  {      for(std::list<std::string>::iterator itrList=m_FilePathList.begin();itrList!=m_FilePathList.end();++itrList)    {        if( itrList->compare(szFilePath) == 0 )        {            //已经存在            return ;        }    }    //还未加入    m_FilePathList.push_back(szFilePath);}  void CSendMail::DeleteFilePath(std::string szFilePath)//删除附件路径  {      for(std::list<std::string>::iterator itrList=m_FilePathList.begin();itrList!=m_FilePathList.end();)    {        if( itrList->compare(szFilePath) == 0 )        {            itrList = m_FilePathList.erase(itrList);        }else        {            itrList++;        }    }}  void CSendMail::DeleteAllPath(void)  {      m_FilePathList.clear();  }  ////////////////////////////////////////////功能函数/////////////////////////////////////////////////////////////////////实现CString的Replacestring& CSendMail::replace_all(string& str,const string& old_value,const string& new_value){       while(true)    {           string::size_type pos(0);           if( (pos=str.find(old_value))!=string::npos )               str.replace(pos,old_value.length(),new_value);           else            break;       }       return str;   }//从附件的路径中获取文件名称std::string CSendMail::GetFileName(std::string &szFilePath){    replace_all(szFilePath,"/","\\");    string szFileName=szFilePath.substr(szFilePath.rfind("\\")+1,szFilePath.length());    return szFileName;}//以字符形式读入附件内容std::string CSendMail::GetFileData(std::string szFilePath){    std::string szBuffer;    if(szFilePath.empty())      {        m_logInfo.logInfo("[SendFileBody]Error:附件路径为空!");        return szBuffer;      }      ifstream ifFile(szFilePath.c_str(),ios::binary|ios::in);    if(!ifFile)      {          m_logInfo.logInfo("[SendFileBody]Error:打开附件路径错误!");        return szBuffer;      }      ifFile.seekg(0,ios::beg);    std::ostringstream tmp;     tmp << ifFile.rdbuf();     szBuffer = tmp.str();        ifFile.close();    return szBuffer;  }//把char类型转换成Base64类型 std::string CSendMail::Base64Encode(std::string in_str)        {    std::string out_str;    unsigned char c1, c2, c3;    int i = 0;    int len = in_str.length();    while ( i<len )    {        // read the first byte        c1 = in_str[i++];        if ( i==len )       // pad with "="        {            out_str += _AppOctStrmContent_encode_chars[ c1>>2 ];            out_str += _AppOctStrmContent_encode_chars[ (c1&0x3)<<4 ];            out_str += "==";            break;        }        // read the second byte        c2 = in_str[i++];        if ( i==len )       // pad with "="        {            out_str += _AppOctStrmContent_encode_chars[ c1>>2 ];            out_str += _AppOctStrmContent_encode_chars[ ((c1&0x3)<<4) | ((c2&0xF0)>>4) ];            out_str += _AppOctStrmContent_encode_chars[ (c2&0xF)<<2 ];            out_str += "=";            break;        }        // read the third byte        c3 = in_str[i++];        // convert into four bytes string        out_str += _AppOctStrmContent_encode_chars[ c1>>2 ];        out_str += _AppOctStrmContent_encode_chars[ ((c1&0x3)<<4) | ((c2&0xF0)>>4) ];        out_str += _AppOctStrmContent_encode_chars[ ((c2&0xF)<<2) | ((c3&0xC0)>>6) ];        out_str += _AppOctStrmContent_encode_chars[ c3&0x3F ];    }    return out_str;}int CSendMail::sendRequest(const std::string content,bool bout){    int len_s=send(_socket, content.c_str(), content.length(), 0);    if ( len_s < 0 )    {        m_logInfo.logInfo("[ERROR]SEND:%s",content.c_str());        return false;    }    //输出信息    if(bout)    {        m_logInfo.logInfo("[INFO]SEND:%s",content.c_str());    }    return len_s;}bool CSendMail::rcvResponse(const std::string expected_response){    int recv_bytes = 0;    char response_buffer[MAX_BUFFER_SIZE];    if ( (recv_bytes = recv(_socket, response_buffer, MAX_BUFFER_SIZE, 0)) < 0 )    {        m_logInfo.logInfo("[ERROR]RECV:%s",expected_response.c_str());        return false;    }    //输出信息    std::string response(response_buffer, recv_bytes);    m_logInfo.logInfo("[INFO]RECV(%s):%s",expected_response.c_str(),response.c_str());    if ( response.substr(0, 3) != expected_response )    {        return false;    }    return true;}std::string CSendMail::prepareDate(){    char date_string[MAX_BUFFER_SIZE];    time_t seconds;    time(&seconds);    strftime(date_string, MAX_BUFFER_SIZE,         "%a, %d %b %y %H:%M:%S +0800",         localtime(&seconds));          // +0800 maybe hard code    return date_string;}////////////////////////////////////////////////工作函数//////////////////////////////////////////////////////////////////////bool CSendMail::CReateSocket()  {      WORD wVersionRequested;      WSADATA wsaData;      int err;      wVersionRequested = MAKEWORD( 2, 2 );      err = WSAStartup( wVersionRequested, &wsaData );      if ( err != 0 )       {          m_logInfo.logInfo("WSAStartup调用失败!");        return false;      }      if ( LOBYTE( wsaData.wVersion ) != 2 ||          HIBYTE( wsaData.wVersion ) != 2 )      {          WSACleanup( );          return false;       }      _socket = socket(AF_INET,SOCK_STREAM,IPPROTO_IP);      if (_socket == INVALID_SOCKET)      {          m_logInfo.logInfo("socket创建失败!");        return false;      }      sockaddr_in servaddr;      memset(&servaddr,0,sizeof(sockaddr_in));      servaddr.sin_family = AF_INET;      servaddr.sin_port = htons(SERVICE_PORT);//发邮件一般都是25端口      struct hostent *hp=gethostbyname(m_ServerName.c_str());//使用名称      if (hp == NULL)    {        DWORD dwErrCode =    GetLastError();        return false;    }    servaddr.sin_addr.s_addr=*(int*)(*hp->h_addr_list);      int ret = connect(_socket,(sockaddr*)&servaddr,sizeof(servaddr));//建立连接      if (ret == SOCKET_ERROR)      {          DWORD dwErr = GetLastError();        return false;      }      if(!rcvResponse("220"))        return false;    return true;  }  bool CSendMail::Logon(){    char local_host[MAX_BUFFER_SIZE];    if ( gethostname(local_host, MAX_BUFFER_SIZE) != 0 )    {        m_logInfo.logInfo("Get local host name error!");        return false;    }        std::string msg;        msg  = "HELO ";    msg += std::string(local_host) + "\r\n";    sendRequest(msg);    if(!rcvResponse("250"))    {        return false;    }    msg = "AUTH LOGIN\r\n";    sendRequest(msg);    if(!rcvResponse("334"))    {        return false;    }          msg = Base64Encode(m_UserName) + "\r\n";    sendRequest(msg);    if(!rcvResponse("334"))    {        return false;    }    msg = Base64Encode(m_UserPwd) + "\r\n";    sendRequest(msg);    if(!rcvResponse("235"))    {        return false;    }    return true;//登录成功  }///////////////////////////////////SendMail//////////////////////////////////////////////////////发送邮件头 bool CSendMail::SendHead(){    std::string msg;    msg  = "MAIL FROM:<";    msg += m_SenderAddr + ">\r\n";    sendRequest(msg);    if(!rcvResponse("250"))    {        m_logInfo.logInfo("邮件地址错误:%s",m_SenderAddr.c_str());        return false;    }    //遍历获得receiver    for(RECEIVERS::iterator itrRec=m_Receivers.begin();itrRec!=m_Receivers.end();itrRec++)    {        msg  = "RCPT TO: <";        msg += itrRec->second + ">\r\n";        sendRequest(msg);        if(!rcvResponse("250"))        {            return false;        }        }    msg  = "DATA\r\n";    sendRequest(msg);    if(!rcvResponse("354"))    {        return false;    }    //发送Headers    msg  = "From:\"" + m_SenderName + "\"<" + m_SenderAddr + ">\r\n";    //遍历receiver    msg += "To: ";        for(RECEIVERS::iterator itrRec=m_Receivers.begin();itrRec!=m_Receivers.end();itrRec++)    {        std::string szRecv;        szRecv = "\"" + itrRec->first + "\"<" + itrRec->second + ">, ";        msg += szRecv;    }    msg += "\r\n";    msg += "Date: ";    msg += prepareDate() + "\r\n";    msg += "Subject: ";    msg += m_MailTitle + "\r\n";    msg += "X-Mailer: six_beauty \r\n";    msg += "MIME-Version: 1.0\r\n";    msg += "Content-type: multipart/mixed;  boundary=\"INVT\"\r\n\r\n";    msg += "\r\n";    sendRequest(msg);    return true;  }bool CSendMail::SendTextBody()  {      std::string msg;    msg  = "--INVT\r\nContent-Type: text/plain;\r\n  charset=\"gb2312\"\r\n\r\n";    msg += m_TextBody;    msg += "\r\n\r\n";    int len_s=sendRequest(msg,true);    if(len_s != msg.length())    {        m_logInfo.logInfo("发送邮件正文出错,应该发送长度(%d):实际发送长度(%d)",msg.length(),len_s);        return false;    }    return true;    }  bool CSendMail::SendFileBody()  {      std::string msg;    //遍历发送附件文件    for(std::list<std::string>::iterator itrList=m_FilePathList.begin();itrList!=m_FilePathList.end();itrList++)    {        std::string filePath=*itrList;        std::string fileName=GetFileName(filePath);        std::string szContent=GetFileData(filePath);                msg  = "--INVT\r\nContent-Type: application/octet-stream;\r\n  name=\"";        msg += fileName;        msg += "\"\r\nContent-Transfer-Encoding: base64\r\nContent-Disposition: attachment;\r\n  filename=\"";        msg += fileName;        msg += "\"\r\n\r\n";        sendRequest(msg,true);        int npos=0,len=szContent.length();        while(npos<len)        {            std::string szBuffer=Base64Encode(szContent.substr(npos,min(len-npos,3000)));            szBuffer+="\r\n";            sendRequest(szBuffer);            npos += min(len-npos,3000);        }    }    return true;  }  bool CSendMail::SendEnd()  {      std::string msg;    msg = "--INVT--\r\n.\r\n";    sendRequest(msg,true);    msg = "QUIT\r\n";    sendRequest(msg,true);    closesocket(_socket);      WSACleanup();        return true;  }  

 

然后是需要用户实现的一个输出类,请自己实现输出的方式,这里直接cout出来。

#include<iostream>#include<stdarg.h>using namespace std;const int BUF_SIZE=4096;//实现输出类class LogInfo{public:    LogInfo(){};    ~LogInfo(){};    void logInfo(char *szFormat,...)    {        char szBuf[BUF_SIZE]={};        va_list args;                            //第一步        va_start(args,szFormat);                 //第二步        _vsnprintf(szBuf,BUF_SIZE,szFormat,args);    //第三步        va_end(args);                            //第四步        //在这是实现输出方式        std::cout<<szBuf<<endl;        return ;    }};

最后是测试代码:

#include "CSendMail.h"#include "iostream"using namespace std;int main(){    CSendMail sMailer;    //    freopen("F://mailfile//out.txt","w+",stdout);    sMailer.setServerName("smtp.126.com");                                                        //邮箱smtp,如"smtp.126.com"    sMailer.setUserName("userName");                                                                //邮箱账号名,如"****@126.com"    sMailer.setUserPwd("userPwd");                                                                //邮箱密码    sMailer.setSenderName("陈家喵");                                                                //发件人名字    sMailer.setSenderAddress("sanyue9394@126.com");                                                //发送邮箱地址,填你账号的地址,上面的邮箱账号名"****@126.com"    sMailer.setReceiver("柯林林","kelinting@163.com");                                            //添加邮件接收者    sMailer.addReceiver("sixbeauty","sanyue9394@126.com");    sMailer.AddFilePath("F:\\mailfile\\out.txt");            //添加附件//    sMailer.AddFilePath("F:/mailfile/libcurl.exp");                                                //添加附件    //发送第一份邮件    if(sMailer.Connent())                                                                        //每次发邮件前都需要connect    {        if(sMailer.SendMail("CMailSender:阿垃垃圾君","你想快速发家致富吗?你想一夜成名吗?访问 http://www.sb.com"))            //第一个字符串是邮件标题,第二个是邮件内容            cout<<"邮件发送完成!";    }        //发送第二份邮件    if(sMailer.Connent())                                                                        //每次发邮件前都需要connect    {        std::string title,content;        title="测试邮件part_2";        content="柯林是个大八嘎!";        if(sMailer.SendMail(title,content))                                                        //第一个字符串是邮件标题,第二个是邮件内容            cout<<"邮件发送完成!";    }    return 0;}

测试时,把

sMailer.setUserName("userName");                                                          sMailer.setUserPwd("userPwd");

改了就可以发送邮件了。

附实现好的工程下载:http://download.csdn.net/detail/biantaiwangzi/7948843

 

参考:

比较出名也写得比较好的SMailer【一组实现邮件发送功能的C++封装类】:http://morningspace.51.net/resource/SMailer.php

实现逻辑抄自【C++发送邮件和附件】:http://blog.csdn.net/ybjx111/article/details/7031055#

c++封装的发邮件类CSendMail