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] = '\0';
 
        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\n\n",
                    curl_easy_strerror(res));
 
                char achTip[512] = { 0 };
                sprintf(achTip, "curl_easy_perform() failed: %s\n\n", 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 += "\r\nReply-To: ";
        m_strMessage += m_strSendMail;
        m_strMessage += "\r\nTo: ";
        for (size_t i = 0; i < m_vRecvMail.size(); i++)
        {

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

            m_strMessage += m_vRecvMail[i];
        }

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

            m_strMessage += "\r\n--simple boundary";
            GetFileName(m_vAttachMent[i], filename);
            GetFileType(m_vAttachMent[i], filetype);
            SetContentType(filetype);
            SetFileName(filename);
 
            m_strMessage += "\r\nContent-Type: ";
            m_strMessage += m_strContentType;
            m_strMessage += "\tname=";
            m_strMessage += "\"";
            m_strMessage += m_strFileName;
            m_strMessage += "\"";
            m_strMessage += "\r\nContent-Disposition:attachment;filename=";
            m_strMessage += "\"";
            m_strMessage += m_strFileName;
            m_strMessage += "\"";
            m_strMessage += "\r\nContent-Transfer-Encoding:base64";
            m_strMessage += "\r\n\r\n";
 
 
            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 += "\r\n";
            }

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

 
    //获取文件类型
    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;
}

posted @ 2017-09-28 14:01  Mr.R123  阅读(1252)  评论(0编辑  收藏  举报