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实现 蓝桥杯VIP 算法训练 字符串逆序
    Java实现 蓝桥杯VIP 算法训练 字符串逆序
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 成绩的等级输出
    Java实现 蓝桥杯VIP 算法训练 成绩的等级输出
    Qt 自定义model实现文件系统的文件名排序
  • 原文地址:https://www.cnblogs.com/skiing886/p/7606403.html
Copyright © 2011-2022 走看看