zoukankan      html  css  js  c++  java
  • curl发送SMTP邮件类


    以下是使用
    curl 7.55发送smtp邮件的封装类:
    smtp.hpp


    static const std::string base64_chars =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz"
        "0123456789+/";
     

    static inline bool is_base64(unsigned char c)
    {
        return (isalnum(c) || (c == '+') || (c == '/'));
    }

     
    inline std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len)
    {
        std::string ret;
        int i = 0, j = 0;
        unsigned char char_array_3[3], char_array_4[4];
     

        while (in_len--)
        {

            char_array_3[i++] = *(bytes_to_encode++);
            if (i == 3)
            {

                char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
                char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
                char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
                char_array_4[3] = char_array_3[2] & 0x3f;
     
                for (i = 0; (i < 4); i++)
                    ret += base64_chars[char_array_4[i]];
                i = 0;
            }

        }
     
        if (i)
        {

            for (j = i; j < 3; j++)
                char_array_3[j] = '';
     
            char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
            char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
            char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
            char_array_4[3] = char_array_3[2] & 0x3f;
     
            for (j = 0; (j < i + 1); j++)
                ret += base64_chars[char_array_4[j]];
     
            while ((i++ < 3))
                ret += '=';
        }

     
        return ret;
     
    }
     
    inline std::string base64_decode(std::string const& encoded_string)
    {
        int in_len = encoded_string.size();
        int i = 0, j = 0, in_ = 0;
        unsigned char char_array_4[4], char_array_3[3];
        std::string ret;
     

        while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_]))
        {

            char_array_4[i++] = encoded_string[in_]; in_++;
            if (i == 4) {
                for (i = 0; i < 4; i++)
                    char_array_4[i] = base64_chars.find(char_array_4[i]);
     
                char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
                char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
                char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
     
                for (i = 0; (i < 3); i++)
                    ret += char_array_3[i];
                i = 0;
            }

        }
     
        if (i)
        {

            for (j = i; j < 4; j++)
                char_array_4[j] = 0;
     
            for (j = 0; j < 4; j++)
                char_array_4[j] = base64_chars.find(char_array_4[j]);
     
            char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
            char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
            char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
     
            for (j = 0; (j < i - 1); j++)
                ret += char_array_3[j];
        }

     
        return ret;
    }

     
    #define SKIP_PEER_VERIFICATION
    #define SKIP_HOSTNAME_VERIFICATION
    class CSmtpSendMail
    {
    public:
        CSmtpSendMail(const std::string & charset = "gb2312") // 也可以传入utf,gb2312
        {

            m_strCharset = charset;
            m_vRecvMail.clear();
        }

     

        //设置stmp服务器、用户名、密码、端口(端口其实不用指定,libcurl默认25,但如果是smtps则默认是465)
        inline void SetSmtpServer(const std::string &username, const std::string& password, const std::string& servername, const std::string &port = "25")
        {

            m_strUserName = username;
            m_strPassword = password;
            m_strServerName = servername;
            m_strPort = port;
        }

     
        //发送者姓名,可以不用
        inline void SetSendName(const std::string& sendname)
        {

            std::string strTemp = "";
            strTemp += "=?";
            strTemp += m_strCharset;
            strTemp += "?B?";
            strTemp += base64_encode((unsigned char *)sendname.c_str(), sendname.size());
            strTemp += "?=";
            m_strSendName = strTemp;
        }

     
        inline void SetSendMail(const std::string& sendmail)
        {

            m_strSendMail = sendmail;
        }

     
        inline void AddRecvMail(const std::string& recvmail)
        {

            m_vRecvMail.push_back(recvmail);
        }

     
        inline void SetSubject(const std::string &subject)
        {

            std::string strTemp = "";
            strTemp = "Subject: ";
            strTemp += "=?";
            strTemp += m_strCharset;
            strTemp += "?B?";
            strTemp += base64_encode((unsigned char *)subject.c_str(), subject.size());
            strTemp += "?=";
            m_strSubject = strTemp;
        }

     
        inline void SetBodyContent(const std::string &content)
        {

            m_strContent = content;
        }

     
        inline void AddAttachment(const std::string &filename)
        {

            m_vAttachMent.push_back(filename);
        }

     
        inline bool SendMail()
        {

            CreatMessage();
            bool ret = true;
            CURL *curl;
            CURLcode res = CURLE_OK;
            struct curl_slist *recipients = NULL;
     
            curl = curl_easy_init();
            if (curl)
            {

     
                curl_easy_setopt(curl, CURLOPT_USERNAME, m_strUserName.c_str());
                curl_easy_setopt(curl, CURLOPT_PASSWORD, m_strPassword.c_str());
                std::string tmp = "smtp://";
                tmp += m_strServerName;
     
                curl_easy_setopt(curl, CURLOPT_URL, tmp.c_str());
    #ifdef SKIP_PEER_VERIFICATION
                curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
    #endif
     

     

    #ifdef SKIP_HOSTNAME_VERIFICATION
                curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
    #endif
     

                printf("m_strSendMail = %s", m_strSendMail.c_str());
                curl_easy_setopt(curl, CURLOPT_MAIL_FROM, m_strSendMail.c_str());
                for (size_t i = 0; i < m_vRecvMail.size(); i++)
                {

     
                    recipients = curl_slist_append(recipients, m_vRecvMail[i].c_str());
                }

                curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
     
                std::stringstream stream;
                stream.str(m_strMessage.c_str());
                stream.flush();
     
                // 注意回调函数必须设置为static
                curl_easy_setopt(curl, CURLOPT_READFUNCTION, &CSmtpSendMail::payload_source);
                curl_easy_setopt(curl, CURLOPT_READDATA, (void *)&stream);
                curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
     
                curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
     
                int nTimes = 0;
                /* Send the message */
                res = curl_easy_perform(curl);
                CURLINFO info = CURLINFO_NONE;
                curl_easy_getinfo(curl, info, NULL);
                /* Check for errors */
                while (res != CURLE_OK)
                {

                    nTimes++;
                    if (nTimes > 5)
                    {

                        break;
                    }

                    fprintf(stderr, "curl_easy_perform() failed: %s ",
                        curl_easy_strerror(res));
     
                    char achTip[512] = { 0 };
                    sprintf(achTip, "curl_easy_perform() failed: %s ", curl_easy_strerror(res));
                    ret = false;
                }

     
                curl_slist_free_all(recipients);
     
                curl_easy_cleanup(curl);
     
            }
            return ret;
        }

    private:
        //回调函数,将MIME协议拼接的字符串由libcurl发出
        static inline size_t payload_source(void *ptr, size_t size, size_t nmemb, void *stream)
        {

            size_t num_bytes = size * nmemb;
            char* data = (char*)ptr;
            std::stringstream* strstream = (std::stringstream*)stream;
     

            strstream->read(data, num_bytes);
     
            return strstream->gcount();
        }

     
        //创建邮件MIME内容
        inline void CreatMessage()
        {

            m_strMessage = "From: ";
            m_strMessage += m_strSendMail;
            m_strMessage += " Reply-To: ";
            m_strMessage += m_strSendMail;
            m_strMessage += " To: ";
            for (size_t i = 0; i < m_vRecvMail.size(); i++)
            {

                if (i > 0) {
                    m_strMessage += ",";
                }

                m_strMessage += m_vRecvMail[i];
            }

            m_strMessage += " ";
            m_strMessage += m_strSubject;
            m_strMessage += " X-Mailer: The Bat! (v3.02) Professional";
            m_strMessage += " Mime-Version: 1.0";
            m_strMessage += " Content-Type: multipart/mixed;";
            m_strMessage += "boundary="simple boundary"";
            m_strMessage += " This is a multi-part message in MIME format.";
            m_strMessage += " --simple boundary";
            //正文
            m_strMessage += " Content-Type: text/html;";
            m_strMessage += "charset=";
            m_strMessage += """;
            m_strMessage += m_strCharset;
            m_strMessage += """;
            m_strMessage += " Content-Transfer-Encoding: 7BIT";
            m_strMessage += " ";
            m_strMessage += m_strContent;
     
            //附件
            std::string filename = "";
            std::string filetype = "";
            for (size_t i = 0; i < m_vAttachMent.size(); i++)
            {

                m_strMessage += " --simple boundary";
                GetFileName(m_vAttachMent[i], filename);
                GetFileType(m_vAttachMent[i], filetype);
                SetContentType(filetype);
                SetFileName(filename);
     
                m_strMessage += " Content-Type: ";
                m_strMessage += m_strContentType;
                m_strMessage += " name=";
                m_strMessage += """;
                m_strMessage += m_strFileName;
                m_strMessage += """;
                m_strMessage += " Content-Disposition:attachment;filename=";
                m_strMessage += """;
                m_strMessage += m_strFileName;
                m_strMessage += """;
                m_strMessage += " Content-Transfer-Encoding:base64";
                m_strMessage += " ";
     
     
                FILE *pt = NULL;
                if ((pt = fopen(m_vAttachMent[i].c_str(), "rb")) == NULL) {
     
                    std::cerr << "打开文件失败: " << m_vAttachMent[i] << std::endl;
                    continue;
                }

                fseek(pt, 0, SEEK_END);
                int len = ftell(pt);
                fseek(pt, 0, SEEK_SET);
                int rlen = 0;
                char buf[55];
                for (size_t i = 0; i < len / 54 + 1; i++)
                {

                    memset(buf, 0, 55);
                    rlen = fread(buf, sizeof(char), 54, pt);
                    m_strMessage += base64_encode((const unsigned char*)buf, rlen);
                    m_strMessage += " ";
                }

                fclose(pt);
                pt = NULL;
     
            }
            m_strMessage += " --simple boundary-- ";
        }

     
        //获取文件类型
        inline int GetFileType(std::string const& stype)
        {

            if (stype == "txt")
            {

                return 0;
            }

            else if (stype == "xml")
            {

                return 1;
            }

            else if (stype == "html")
            {

                return 2;
            }

            else if (stype == "jpeg")
            {

                return 3;
            }

            else if (stype == "png")
            {

                return 4;
            }

            else if (stype == "gif")
            {

                return 5;
            }

            else if (stype == "exe")
            {

                return 6;
            }

     
            return -1;
        }

     
        //设置文件名
        inline void SetFileName(const std::string& FileName)
        {

            std::string EncodedFileName = "=?";
            EncodedFileName += m_strCharset;
            EncodedFileName += "?B?";//修改
            EncodedFileName += base64_encode((unsigned char *)FileName.c_str(), FileName.size());
            EncodedFileName += "?=";
            m_strFileName = EncodedFileName;
        }

     
        //设置文件的contenttype
        inline void SetContentType(std::string const& stype)
        {

            int type = GetFileType(stype);
            switch (type)
            {//
            case 0:
                m_strContentType = "plain/text;";
                break;
     
            case 1:
                m_strContentType = "text/xml;";
                break;
     
            case 2:
                m_strContentType = "text/html;";
     
            case 3:
                m_strContentType = "image/jpeg;";
                break;
     
            case 4:
                m_strContentType = "image/png;";
                break;
     
            case 5:
                m_strContentType = "image/gif;";
                break;
     
            case 6:
                m_strContentType = "application/x-msdownload;";
                break;
     
            default:
                m_strContentType = "application/octet-stream;";
                break;
            }

        }
     
        //得到文件名
        inline void GetFileName(const std::string& file, std::string& filename)
        {

            std::string::size_type p = file.find_last_of('/');
            if (p == std::string::npos)
                p = file.find_last_of('\');
            if (p != std::string::npos) {
                p += 1; // get past folder delimeter
                filename = file.substr(p, file.length() - p);
            }

        }
     
        //得到文件类型
        inline void GetFileType(const std::string& file, std::string& stype)
        {

            std::string::size_type p = file.find_last_of('.');
            if (p != std::string::npos)
            {

                p += 1; // get past folder delimeter
                stype = file.substr(p, file.length() - p);
            }

        }
     
    private:
        std::string m_strCharset; //邮件编码
        std::string m_strSubject; //邮件主题
        std::string m_strContent; //邮件内容
        std::string m_strFileName; //文件名
        std::string m_strMessage;// 整个MIME协议字符串
        std::string m_strUserName;//用户名
        std::string m_strPassword;//密码
        std::string m_strServerName;//smtp服务器
        std::string m_strPort;//端口
        std::string m_strSendName;//发送者姓名
        std::string m_strSendMail;//发送者邮箱
        std::string m_strContentType;//附件contenttype
        std::string m_strFileContent;//附件内容
     

        std::vector<std::string> m_vRecvMail; //收件人容器
        std::vector<std::string> m_vAttachMent;//附件容器
    };

     
    inline bool SendEmail(string sUser, string sPwd, string sSvrAddr, string sFrom, string sTo, string sSub, string sContent)
    {
        CSmtpSendMail sendMail;
        sendMail.SetSmtpServer(sUser, sPwd, sSvrAddr);
        sendMail.SetSendMail(sFrom);
        vector<string> vtRecv = split(sTo, ",");
        for (int i = 0; i < vtRecv.size(); i++)
        {

            sendMail.AddRecvMail(vtRecv[i]);
        }

        sendMail.SetSubject(sSub);
        sendMail.SetBodyContent(sContent);
        return sendMail.SendMail();
    }

        
    inline bool SendSMS()
    {
        return 0;
    }

  • 相关阅读:
    北京南天软件java工程师面试题
    祝福自己
    致青春——IT之路
    PL/SQL devloper 常用设置
    CENTOS LINUX查询内存大小、频率
    centOS安装openoffice
    echo > 和 echo >>的区别
    sqoop job 增量导入
    sqoop job从创建到执行
    sqoop导入增量数据
  • 原文地址:https://www.cnblogs.com/skiing886/p/7606403.html
Copyright © 2011-2022 走看看