zoukankan      html  css  js  c++  java
  • SMTP实现发送邮箱2(封装版)

    SMTP.h

    #ifndef __SMTP_H__ //避免重复包含
    #define __SMTP_H__
    
    #include <iostream>
    #include <list>
    #include <WinSock2.h>
    using namespace std;
    
    const int MAXLEN = 1024;
    const int MAX_FILE_LEN = 6000;
    
    static const char base64Char[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    
    struct FILEINFO /*记录文件信息*/
    {
        char fileName[128]; /*文件名称*/
        char filePath[256]; /*文件绝对路径*/
    };
    
    class CSmtp
    {
    public:
        CSmtp(void);
        CSmtp(
            int port,
            string srvDomain,	//smtp服务器域名
            string userName,	//用户名
            string password,	//密码
            string targetEmail, //目的邮件地址
            string emailTitle,  //主题
            string content       //内容
        );
    public:
        ~CSmtp(void);
    public:
        int port;
    public:
        string domain;
        string user;
        string pass;
        string targetAddr;
        string title;
        string content;
        /*将文件存入list里,便于删除与增加*/
        list <FILEINFO *> listFile;
    
    public:
        char buff[MAXLEN + 1];
        int buffLen;
        SOCKET sockClient;	//客户端的套接字
    public:
        bool CreateConn(); /*创建连接*/
    
        bool Send(string &message);
        bool Recv();
    
        void FormatEmailHead(string &email);//格式化要发送的邮件头部
        int Login();
        bool SendEmailHead();		//发送邮件头部信息
        bool SendTextBody();	    //发送文本信息
                                    //bool SendAttachment();	    //发送附件
        int SendAttachment_Ex();
        bool SendEnd();
    public:
        void AddAttachment(string &filePath); //添加附件
        void DeleteAttachment(string &filePath); //删除附件
        void DeleteAllAttachment(); //删除所有的附件
    
        void SetSrvDomain(string &domain);
        void SetUserName(string &user);
        void SetPass(string &pass);
        void SetTargetEmail(string &targetAddr);
        void SetEmailTitle(string &title);
        void SetContent(string &content);
        void SetPort(int port);
        int SendEmail_Ex();
        /*关于错误码的说明:1.网络错误导致的错误2.用户名错误3.密码错误4.文件不存在0.成功*/
        char* base64Encode(char const* origSigned, unsigned origLength);
    };
    
    #endif // !__SMTP_H__
    

      

    SMTP.cpp

    #define _WINSOCK_DEPRECATED_NO_WARNINGS
    
    #include "Smtp.h"
    #include <winsock2.h>
    #include <iostream>
    #include <fstream>
    using namespace std;
    
    #pragma  comment(lib, "ws2_32.lib")	/*链接ws2_32.lib动态链接库*/
    
    /*base64编码*/
    char* CSmtp::base64Encode(char const* origSigned, unsigned origLength)
    {
        unsigned char const* orig = (unsigned char const*)origSigned; // in case any input bytes have the MSB set
        if (orig == NULL) return NULL;
    
        unsigned const numOrig24BitValues = origLength / 3;
        bool havePadding = origLength > numOrig24BitValues * 3;
        bool havePadding2 = origLength == numOrig24BitValues * 3 + 2;
        unsigned const numResultBytes = 4 * (numOrig24BitValues + havePadding);
        char* result = new char[numResultBytes + 3]; // allow for trailing '/0'
    
                                                     // Map each full group of 3 input bytes into 4 output base-64 characters:
        unsigned i;
        for (i = 0; i < numOrig24BitValues; ++i)
        {
            result[4 * i + 0] = base64Char[(orig[3 * i] >> 2) & 0x3F];
            result[4 * i + 1] = base64Char[(((orig[3 * i] & 0x3) << 4) | (orig[3 * i + 1] >> 4)) & 0x3F];
            result[4 * i + 2] = base64Char[((orig[3 * i + 1] << 2) | (orig[3 * i + 2] >> 6)) & 0x3F];
            result[4 * i + 3] = base64Char[orig[3 * i + 2] & 0x3F];
        }
    
        // Now, take padding into account.  (Note: i == numOrig24BitValues)
        if (havePadding)
        {
            result[4 * i + 0] = base64Char[(orig[3 * i] >> 2) & 0x3F];
            if (havePadding2)
            {
                result[4 * i + 1] = base64Char[(((orig[3 * i] & 0x3) << 4) | (orig[3 * i + 1] >> 4)) & 0x3F];
                result[4 * i + 2] = base64Char[(orig[3 * i + 1] << 2) & 0x3F];
            }
            else
            {
                result[4 * i + 1] = base64Char[((orig[3 * i] & 0x3) << 4) & 0x3F];
                result[4 * i + 2] = '=';
            }
            result[4 * i + 3] = '=';
        }
    
        result[numResultBytes] = '';
        return result;
    }
    CSmtp::CSmtp(void)
    {
        this->content = "";
        this->port = 25;
        this->user = "";
        this->pass = "";
        this->targetAddr = "";
        this->title = "";
        this->domain = "";
    
        WORD wVersionRequested;
        WSADATA wsaData;
        int err;
        wVersionRequested = MAKEWORD(2, 1);
        err = WSAStartup(wVersionRequested, &wsaData);
        this->sockClient = 0;
    }
    
    CSmtp::~CSmtp(void)
    {
        DeleteAllAttachment();
        closesocket(sockClient);
        WSACleanup();
    }
    
    CSmtp::CSmtp(
        int port,
        string srvDomain,
        string userName,
        string password,
        string targetEmail,
        string emailTitle,
        string content
    )
    {
        this->content = content;
        this->port = port;
        this->user = userName;
        this->pass = password;
        this->targetAddr = targetEmail;
        this->title = emailTitle;
        this->domain = srvDomain;
    
        WORD wVersionRequested;
        WSADATA wsaData;
        int err;
        wVersionRequested = MAKEWORD(2, 1);
        err = WSAStartup(wVersionRequested, &wsaData);
        this->sockClient = 0;
    }
    
    bool CSmtp::CreateConn()
    {
        SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0); //建立socket对象
        SOCKADDR_IN addrSrv;
        HOSTENT* pHostent;
        pHostent = gethostbyname(domain.c_str());  //得到有关于域名的信息
    
        addrSrv.sin_addr.S_un.S_addr = *((DWORD *)pHostent->h_addr_list[0]);	//得到smtp服务器的网络字节序的ip地址
        addrSrv.sin_family = AF_INET;
        addrSrv.sin_port = htons(port);
        int err = connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));   //向服务器发送请求
        if (err != 0)
        {
            return false;
        }
        this->sockClient = sockClient;
        if (false == Recv())
        {
            return false;
        }
        return true;
    }
    
    bool CSmtp::Send(string &message)
    {
        int err = send(sockClient, message.c_str(), message.length(), 0);
        if (err == SOCKET_ERROR)
        {
            return false;
        }
        cout << message.c_str() << endl;
        return true;
    }
    
    bool CSmtp::Recv()
    {
        memset(buff, 0, sizeof(char)* (MAXLEN + 1));
        int err = recv(sockClient, buff, MAXLEN, 0); //接收数据
        if (err == SOCKET_ERROR)
        {
            return false;
        }
        buff[err] = '';
        cout << buff << endl;
        return true;
    }
    
    int CSmtp::Login()
    {
        string sendBuff;
        sendBuff = "EHLO ";
        sendBuff += user;
        sendBuff += "
    ";
    
        if (false == Send(sendBuff) || false == Recv()) //既接收也发送
        {
            return 1; /*1表示发送失败由于网络错误*/
        }
    
        sendBuff.empty();
        sendBuff = "AUTH LOGIN
    ";
        if (false == Send(sendBuff) || false == Recv()) //请求登陆
        {
            return 1; /*1表示发送失败由于网络错误*/
        }
    
        sendBuff.empty();
        int pos = user.find('@', 0);
        sendBuff = user.substr(0, pos); //得到用户名
    
        char *ecode;
        /*在这里顺带扯一句,关于string类的length函数与C语言中的strlen函数的区别,strlen计算出来的长度,只到''字符为止,而string::length()函数实际上返回的是string类中字符数组的大小,你自己可以测试一下,这也是为什么我下面不使用string::length()的原因*/
    
        ecode = base64Encode(sendBuff.c_str(), strlen(sendBuff.c_str()));
        sendBuff.empty();
        sendBuff = ecode;
        sendBuff += "
    ";
        delete[]ecode;
    
        if (false == Send(sendBuff) || false == Recv()) //发送用户名,并接收服务器的返回
        {
            return 1; /*错误码1表示发送失败由于网络错误*/
        }
    
        sendBuff.empty();
        ecode = base64Encode(pass.c_str(), strlen(pass.c_str()));
        sendBuff = ecode;
        sendBuff += "
    ";
        delete[]ecode;
    
        if (false == Send(sendBuff) || false == Recv()) //发送用户密码,并接收服务器的返回
        {
            return 1; /*错误码1表示发送失败由于网络错误*/
        }
    
        if (NULL != strstr(buff, "550"))
        {
            return 2;/*错误码2表示用户名错误*/
        }
    
        if (NULL != strstr(buff, "535")) /*535是认证失败的返回*/
        {
            return 3; /*错误码3表示密码错误*/
        }
        return 0;
    }
    
    bool CSmtp::SendEmailHead()		//发送邮件头部信息
    {
        string sendBuff;
        sendBuff = "MAIL FROM: <" + user + ">
    ";
        if (false == Send(sendBuff) || false == Recv())
        {
            return false; /*表示发送失败由于网络错误*/
        }
    
        sendBuff.empty();
        sendBuff = "RCPT TO: <" + targetAddr + ">
    ";
        if (false == Send(sendBuff) || false == Recv())
        {
            return false; /*表示发送失败由于网络错误*/
        }
    
        sendBuff.empty();
        sendBuff = "DATA
    ";
        if (false == Send(sendBuff) || false == Recv())
        {
            return false; //表示发送失败由于网络错误
        }
    
        sendBuff.empty();
        FormatEmailHead(sendBuff);
        if (false == Send(sendBuff))
            //发送完头部之后不必调用接收函数,因为你没有
    .
    结尾,服务器认为你没有发完数据,所以不会返回什么值
        {
            return false; /*表示发送失败由于网络错误*/
        }
        return true;
    }
    
    void CSmtp::FormatEmailHead(string &email)
    {/*格式化要发送的内容*/
        email = "From: ";
        email += user;
        email += "
    ";
    
        email += "To: ";
        email += targetAddr;
        email += "
    ";
    
        email += "Subject: ";
        email += title;
        email += "
    ";
    
        email += "MIME-Version: 1.0";
        email += "
    ";
    
        email += "Content-Type: multipart/mixed;boundary=qwertyuiop";
        email += "
    ";
        email += "
    ";
    }
    
    bool CSmtp::SendTextBody()  /*发送邮件文本*/
    {
        string sendBuff;
        sendBuff = "--qwertyuiop
    ";
        sendBuff += "Content-Type: text/plain;";
        sendBuff += "charset="gb2312"
    
    ";
        sendBuff += content;
        sendBuff += "
    
    ";
        return Send(sendBuff);
    }
    
    int CSmtp::SendAttachment_Ex() /*发送附件*/
    {
        for (list<FILEINFO *>::iterator pIter = listFile.begin(); pIter != listFile.end(); pIter++)
        {
            cout << "Attachment is sending ~~~~~" << endl;
            cout << "Please be patient!" << endl;
            string sendBuff;
            sendBuff = "--qwertyuiop
    ";
            sendBuff += "Content-Type: application/octet-stream;
    ";
            sendBuff += " name="";
            sendBuff += (*pIter)->fileName;
            sendBuff += """;
            sendBuff += "
    ";
    
            sendBuff += "Content-Transfer-Encoding: base64
    ";
            sendBuff += "Content-Disposition: attachment;
    ";
            sendBuff += " filename="";
            sendBuff += (*pIter)->fileName;
            sendBuff += """;
    
            sendBuff += "
    ";
            sendBuff += "
    ";
            Send(sendBuff);
            ifstream ifs((*pIter)->filePath, ios::in | ios::binary);
            if (false == ifs.is_open())
            {
                return 4; /*错误码4表示文件打开错误*/
            }
            char fileBuff[MAX_FILE_LEN];
            char *chSendBuff;
            memset(fileBuff, 0, sizeof(fileBuff));
            /*文件使用base64加密传送*/
            while (ifs.read(fileBuff, MAX_FILE_LEN))
            {
                //cout << ifs.gcount() << endl;
                chSendBuff = base64Encode(fileBuff, MAX_FILE_LEN);
                chSendBuff[strlen(chSendBuff)] = '
    ';
                chSendBuff[strlen(chSendBuff)] = '
    ';
                send(sockClient, chSendBuff, strlen(chSendBuff), 0);
                delete[]chSendBuff;
            }
            //cout << ifs.gcount() << endl;
            chSendBuff = base64Encode(fileBuff, ifs.gcount());
            chSendBuff[strlen(chSendBuff)] = '
    ';
            chSendBuff[strlen(chSendBuff)] = '
    ';
            int err = send(sockClient, chSendBuff, strlen(chSendBuff), 0);
    
            if (err != strlen(chSendBuff))
            {
                cout << "文件传送出错!" << endl;
                return 1;
            }
            delete[]chSendBuff;
        }
        return 0;
    }
    
    bool CSmtp::SendEnd() /*发送结尾信息*/
    {
        string sendBuff;
        sendBuff = "--qwertyuiop--";
        sendBuff += "
    .
    ";
        if (false == Send(sendBuff) || false == Recv())
        {
            return false;
        }
        cout << buff << endl;
        sendBuff.empty();
        sendBuff = "QUIT
    ";
        return (Send(sendBuff) && Recv());
    }
    
    int CSmtp::SendEmail_Ex()
    {
        if (false == CreateConn())
        {
            return 1;
        }
        //Recv();
        int err = Login(); //先登录
        if (err != 0)
        {
            return err; //错误代码必须要返回
        }
        if (false == SendEmailHead()) //发送EMAIL头部信息
        {
            return 1; /*错误码1是由于网络的错误*/
        }
        if (false == SendTextBody())
        {
            return 1; /*错误码1是由于网络的错误*/
        }
        err = SendAttachment_Ex();
        if (err != 0)
        {
            return err;
        }
        if (false == SendEnd())
        {
            return 1; /*错误码1是由于网络的错误*/
        }
        return 0; /*0表示没有出错*/
    }
    
    void CSmtp::AddAttachment(string &filePath) //添加附件
    {
        FILEINFO *pFile = new FILEINFO;
        strcpy_s(pFile->filePath, filePath.c_str());
        const char *p = filePath.c_str();
        strcpy_s(pFile->fileName, p + filePath.find_last_of("\") + 1);
        listFile.push_back(pFile);
    }
    
    void CSmtp::DeleteAttachment(string &filePath) //删除附件
    {
        list<FILEINFO *>::iterator pIter;
        for (pIter = listFile.begin(); pIter != listFile.end(); pIter++)
        {
            if (strcmp((*pIter)->filePath, filePath.c_str()) == 0)
            {
                FILEINFO *p = *pIter;
                listFile.remove(*pIter);
                delete p;
                break;
            }
        }
    }
    
    void CSmtp::DeleteAllAttachment() /*删除所有的文件*/
    {
        for (list<FILEINFO *>::iterator pIter = listFile.begin(); pIter != listFile.end();)
        {
            FILEINFO *p = *pIter;
            pIter = listFile.erase(pIter);
            delete p;
        }
    }
    
    void CSmtp::SetSrvDomain(string &domain)
    {
        this->domain = domain;
    }
    
    void CSmtp::SetUserName(string &user)
    {
        this->user = user;
    }
    
    void CSmtp::SetPass(string &pass)
    {
        this->pass = pass;
    }
    void CSmtp::SetTargetEmail(string &targetAddr)
    {
        this->targetAddr = targetAddr;
    }
    void CSmtp::SetEmailTitle(string &title)
    {
        this->title = title;
    }
    void CSmtp::SetContent(string &content)
    {
        this->content = content;
    }
    void CSmtp::SetPort(int port)
    {
        this->port = port;
    }
    

      

    main.cpp

    #include "Smtp.h"
    #include <iostream>
    using namespace std;
    
    int main()
    {
        CSmtp smtp(
            25,								/*smtp端口*/
            "smtp.163.com",					/*smtp服务器地址*/
            "XXX_XXX@163.com",	/*你的邮箱地址*/
            "XXXX",					/*邮箱密码*/
            "XXXXX@qq.com",	/*目的邮箱地址*/
            "Jason!",							/*主题*/
            "Jason come from China"		/*邮件正文*/
        );
    
        //添加附件AddAttachment
        string filePath("D:\1.txt");
        smtp.AddAttachment(filePath);
    
        //删除附件smtp.DeleteAttachment(filePath);
    
        int err;
        if ((err = smtp.SendEmail_Ex()) != 0)
        {
            if (err == 1)
                cout << "错误1: 由于网络不畅通,发送失败!" << endl;
            if (err == 2)
                cout << "错误2: 用户名错误,请核对!" << endl;
            if (err == 3)
                cout << "错误3: 用户密码错误,请核对!" << endl;
            if (err == 4)
                cout << "错误4: 请检查附件目录是否正确,以及文件是否存在!" << endl;
        }
        system("pause");
        return 0;
    }
    

      

  • 相关阅读:
    [转载]RTSP in Stagefright
    FFMPEG for WMA Build Script
    Merge AACExtractor from ICS to Froyo
    查看部署在Heroku上的项目信息
    About AudioSystem Mute
    C++标准转换运算符reinterpret_cast
    纯CSS动态效果的画廊
    基于正则表达式匹配的C++语法高亮度显示
    C++标准转换运算符static_cast
    C++标准转换运算符const_cast
  • 原文地址:https://www.cnblogs.com/gd-luojialin/p/10963063.html
Copyright © 2011-2022 走看看