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;
    }
    

      

  • 相关阅读:
    PAT 甲级 1115 Counting Nodes in a BST (30 分)
    PAT 甲级 1114 Family Property (25 分)
    PAT 甲级 1114 Family Property (25 分)
    Python Ethical Hacking
    Python Ethical Hacking
    Python Ethical Hacking
    Python Ethical Hacking
    Python Ethical Hacking
    Python Ethical Hacking
    Python Ethical Hacking
  • 原文地址:https://www.cnblogs.com/gd-luojialin/p/10963063.html
Copyright © 2011-2022 走看看