热门IT资讯网

完美支持中文及附件的基于libcur邮件客户端封装类

发表于:2024-11-24 作者:热门IT资讯网编辑
编辑最后更新 2024年11月24日,最近做了一个小项目需要在windows c++ 环境下,发送邮件在网上查了很多,大部分编译不成功,少部分中文乱码参考了 libcurl实例及,网友的源码,努力了两天终于得到了比较圆满的结果从 http

最近做了一个小项目需要在windows c++ 环境下,发送邮件
在网上查了很多,大部分编译不成功,少部分中文乱码
参考了 libcurl实例及,网友的源码,努力了两天终于得到了比较圆满的结果
从 https://github.com/honeyligo/curlsmtp.git 上修改
话不多说上源码
调用方式

    std::vector to = {        "[email protected]"    };    std::vector cc = {        "[email protected]"    };    std::vector attach = {        "C:\\Users\\xxx\\Downloads\\Compressed\\curlsmtp-master\\curlsmtp.cpp"    };    auto l =L"相信相当数量的人都已经在准备吐槽了,只要看过《编程珠玑》的人都知道这道题的答案和其中极为简单的道理。不过别着急骂街,不管你信不信,这道笔试题我拿到的答案好多都长这样:";    auto aa = CStdStr::W2UTF(l);    CurlSmtp* mail = new CurlSmtp("fj1981"                                  , "*****"                                  , "smtp.126.com"                                  , "25");    mail->set_from("[email protected]");    mail->set_subject("相信相当数量的人都已经在准备吐槽了");    mail->set_message(aa);    mail->set_to(to);   // mail->set_attach(attach);    mail->send_mail();    Sleep(5);

#ifndef __CURL_SMTP_H__#define __CURL_SMTP_H__#include #include #include #include #include "ustd_string.h"#define SMTP_SERVER             "smtp.126.com"#define SMTP_PORT               "25"class CurlSmtp {    struct WriteThis {        int pos;        int counter;        std::vector data;    };  public:    CurlSmtp(const std::string& user,             const std::string& password,             const std::string& server = SMTP_SERVER,             const std::string& port = SMTP_PORT);    ~CurlSmtp();    void set_from(const std::string& from);    void set_to(const std::vector& to);    void set_secret(const std::vector& secret);    void set_cc(const std::vector& cc);    void set_attach(const std::vector& attach);    void set_subject(const std::string& subject);    void set_message(const std::string& message);    void set_server(const std::string& server);    void set_port(const std::string& port);    void set_user(const std::string& user);    void set_password(const std::string& password);    bool send_mail();    std::string last_error() const;  private:    void make_send_message();    bool attach(const std::string& filename);    void set_receiver_list();    void set_curl_option();    void clear();    static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp);    std::string get_boundary();  private:    std::vector send_buffer_;    std::string from_;    std::vector to_;    std::vector cc_;    std::vector secret_;    std::vector attach_;    std::string server_;    std::string port_;    std::string subject_;    std::string message_;    std::string user_;    std::string password_;    std::string last_error_;    std::vector, std::string>> attachment_;    CURL *curl_ = nullptr;    struct curl_slist* rcpt_list_;    struct WriteThis pooh_;    std::unordered_map typeMap_;};#endif // !__CURL_SMTP_H__

#include "stdafx.h"//#include #include "curlsmtp.h"#include #define LEFT_BRACE                    "<"#define RIGTH_BRACE                   ">"#define ENTER                       "\r\n"#define BOUNDARY_FLAG               "--"#define USER_AGENT                  "User-Agent: Mail Client"#define MIME_VER                    "MIME-Version: 1.0"#define HEADER_CONTENT_TYPE         "Content-Type: multipart/mixed;"#define MSG_CONTENT_TYPE            "Content-Type: text/html; charset=utf-8; format=flowed"#define MSG_ENCODING                "Content-Transfer-Encoding: 7bit"#define MULTI_PERFORM_HANG_TIMEOUT  60 * 1000#define CHUNCK_SIZE                 1024 * 10size_t CurlSmtp::read_callback(void *ptr, size_t size, size_t nmemb,                               void *userp) {    struct WriteThis *pooh = (struct WriteThis *)userp;    //const char *data;    if(size * nmemb < 1)        return 0;    const std::string& str = pooh->data[pooh->counter];    if(pooh->counter < (int)pooh->data.size()) {        size_t len = str.size();        int size = len - pooh->pos;        if (len < CHUNCK_SIZE || size <= CHUNCK_SIZE) {            memcpy(ptr, str.c_str() + pooh->pos, size);            pooh->counter++; /* advance pointer */            pooh->pos = 0;            return size;        } else {            memcpy(ptr, str.c_str() + pooh->pos, CHUNCK_SIZE);            pooh->pos += CHUNCK_SIZE;            return CHUNCK_SIZE;        }    }    return 0;}std::string CurlSmtp::get_boundary() {    std::string boundary;    boundary.reserve(16);    const char hex[] =        "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";    for (int i = 0; i < 16; ++i) {        int x = rand() % 62;        boundary.append(1, hex[x]);    }    return boundary;}CurlSmtp::CurlSmtp(const std::string& user,                   const std::string& password,                   const std::string& server,                   const std::string& port)    : user_(user)    , password_(password)    , server_(server)    , port_(port)    , rcpt_list_(NULL)    , curl_(curl_easy_init()) {    curl_global_init(CURL_GLOBAL_DEFAULT);    typeMap_.insert(std::make_pair(".gif", "Content-Type: image/gif;"));    typeMap_.insert(std::make_pair(".jpg", "Content-Type: image/jpg;"));    typeMap_.insert(std::make_pair(".jpeg", "Content-Type: image/jpeg;"));    typeMap_.insert(std::make_pair(".png", "Content-Type: image/png;"));    typeMap_.insert(std::make_pair(".bmp", "Content-Type: image/bmp;"));    typeMap_.insert(std::make_pair(".txt", "Content-Type: plain/txt;"));    typeMap_.insert(std::make_pair(".log", "Content-Type: plain/txt;"));    typeMap_.insert(std::make_pair(".htm", "Content-Type: plain/htm;"));    typeMap_.insert(std::make_pair(".html", "Content-Type: plain/htm;"));    typeMap_.insert(std::make_pair(".exe",                                   "Content-Type: application/X-exectype-1;"));}CurlSmtp::~CurlSmtp() {    curl_easy_cleanup(curl_);    curl_global_cleanup();}void CurlSmtp::set_from(const std::string& from) {    from_.assign(from);}void CurlSmtp::set_password(const std::string& password) {    password_.assign(password);}void CurlSmtp::set_to(const std::vector& to) {    to_.resize(to.size());    to_.assign(to.begin(), to.end());}void CurlSmtp::set_secret(const std::vector& secret) {    secret_.resize(secret.size());    secret_.assign(secret.begin(), secret.end());}void CurlSmtp::set_cc(const std::vector& cc) {    cc_.resize(cc.size());    cc_.assign(cc.begin(), cc.end());}void CurlSmtp::set_attach(const std::vector& attach) {    attach_.resize(attach.size());    attach_.assign(attach.begin(), attach.end());}void CurlSmtp::set_subject(const std::string& subject) {    std::vector outdata;    ustd::string::base64encode(&subject[0], subject.size(), outdata);    outdata.push_back(0);    std::string encode ="=?utf-8?B?";    encode += &outdata[0];    encode += "?=";    subject_= std::move(encode);}void CurlSmtp::set_message(const std::string& message) {    message_.assign(message);}void CurlSmtp::set_server(const std::string& server) {    server_.assign(server);}void CurlSmtp::set_port(const std::string& port) {    port_.assign(port);}void CurlSmtp::set_user(const std::string& user) {    user_.assign(user_);}bool CurlSmtp::send_mail() {    last_error_.clear();    set_receiver_list();    make_send_message();    set_curl_option();    auto  res = curl_easy_perform(curl_);    /* Check for errors */    if (res != CURLE_OK) {        char buff[MAX_PATH] = {};        sprintf(buff, "failed: %s\n",                curl_easy_strerror(res));        last_error_ = buff;    }    clear();    return res == CURLE_OK;}std::string CurlSmtp::last_error() const {    return last_error_;}bool CurlSmtp::attach(const std::string& filename) {    if (!filename.length()) // do silly checks.        return false;    std::ifstream file(filename.c_str(), std::ios::binary | std::ios::in);    if (!file)        return false;    std::vector filedata;    char c = file.get();    for (; file.good(); c = file.get()) {        if (file.bad())            break;        filedata.push_back(c);    }    std::vector outdata;    ustd::string::base64encode(&filedata[0], filedata.size(), outdata);    std::string fn(filename);    std::string::size_type p = fn.find_last_of('/');    if (p == std::string::npos)        p = fn.find_last_of('\\');    if (p != std::string::npos) {        p += 1; // get past folder delimeter        fn = fn.substr(p, fn.length() - p);    }    attachment_.push_back(std::make_pair(outdata, fn));    return true;}void CurlSmtp::set_receiver_list() {    for (int i = 0; i < (int)to_.size(); i++) {        rcpt_list_ = curl_slist_append(rcpt_list_,                                       std::string(LEFT_BRACE + to_[i] + RIGTH_BRACE).c_str());    }    for (int i = 0; i < (int)cc_.size(); i++) {        rcpt_list_ = curl_slist_append(rcpt_list_,                                       std::string(LEFT_BRACE + cc_[i] + RIGTH_BRACE).c_str());    }    for (int i = 0; i < (int)secret_.size(); i++) {        rcpt_list_ = curl_slist_append(rcpt_list_,                                       std::string(LEFT_BRACE + secret_[i] + RIGTH_BRACE).c_str());    }}void CurlSmtp::set_curl_option() {    pooh_.pos = 0;    pooh_.counter = 0;    pooh_.data.resize(send_buffer_.size() + 1);    pooh_.data.insert(pooh_.data.begin(), send_buffer_.begin(), send_buffer_.end());    curl_easy_setopt(curl_, CURLOPT_URL,                     std::string("smtp://" + server_ + ":" + port_).c_str());    curl_easy_setopt(curl_, CURLOPT_USERNAME, user_.c_str());    curl_easy_setopt(curl_, CURLOPT_PASSWORD, password_.c_str());    curl_easy_setopt(curl_, CURLOPT_READFUNCTION, read_callback);    curl_easy_setopt(curl_, CURLOPT_MAIL_FROM, from_.c_str());    curl_easy_setopt(curl_, CURLOPT_MAIL_RCPT, rcpt_list_);    curl_easy_setopt(curl_, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);    curl_easy_setopt(curl_, CURLOPT_SSL_VERIFYPEER, 0L);    curl_easy_setopt(curl_, CURLOPT_SSL_VERIFYHOST, 0L);    curl_easy_setopt(curl_, CURLOPT_READDATA, &pooh_);    curl_easy_setopt(curl_, CURLOPT_VERBOSE, 1L);    curl_easy_setopt(curl_, CURLOPT_SSLVERSION, 0L);    curl_easy_setopt(curl_, CURLOPT_SSL_SESSIONID_CACHE, 0L);    curl_easy_setopt(curl_, CURLOPT_UPLOAD, 1L);}void CurlSmtp::clear() {    from_.clear();    password_.clear();    to_.clear();    cc_.clear();    secret_.clear();    attach_.clear();    attachment_.clear();    subject_.clear();    message_.clear();    server_.clear();    port_.clear();    if (rcpt_list_ != NULL) {        curl_slist_free_all(rcpt_list_);        rcpt_list_ = NULL;    }}void CurlSmtp::make_send_message() {    send_buffer_.clear();    // from    send_buffer_.push_back("From: " LEFT_BRACE + from_ + RIGTH_BRACE);    // to    for (int i = 0; i < (int)to_.size(); ++i) {        send_buffer_.push_back("To: " LEFT_BRACE + to_[i] + RIGTH_BRACE);    }    // cc    for (int i = 0; i < (int)cc_.size(); ++i) {        send_buffer_.push_back("Cc: " LEFT_BRACE + cc_[i] + RIGTH_BRACE);    }    // subject    send_buffer_.push_back("Subject: " + subject_);    if (attach_.empty() && 0) {        // split body        send_buffer_.push_back(ENTER);        // message        send_buffer_.push_back(message_ + ENTER);    } else {        // user agent        send_buffer_.push_back(USER_AGENT);        send_buffer_.push_back(MIME_VER);        send_buffer_.push_back(HEADER_CONTENT_TYPE);        std::string boundary(get_boundary());        // set boundary        send_buffer_.push_back(" boundary=\"" + boundary + "\"" ENTER);        // first part of body, boundary header and message        send_buffer_.push_back(BOUNDARY_FLAG + boundary);        send_buffer_.push_back(MSG_CONTENT_TYPE);        send_buffer_.push_back(MSG_ENCODING);        // split body        send_buffer_.push_back(ENTER);        send_buffer_.push_back(message_ + ENTER);        send_buffer_.push_back(BOUNDARY_FLAG + boundary);        // attachment        for (int i = 0; i < (int)attach_.size(); ++i) {            attach(attach_[i]);        }        for (std::vector, std::string>>::iterator it1 =                    attachment_.begin();                it1 != attachment_.end(); ++it1) {            if (it1->second.length() > 3) {                // long enough for an extension                std::string typ(it1->second.substr(it1->second.length() - 4, 4));                if (typeMap_.count(typ) > 0) {                    send_buffer_.push_back(typeMap_[typ]);                } else {                    // add other types                    // everything else                    send_buffer_.push_back("Content-Type: application/X-other-1;");                }            } else {                // default to don't know                send_buffer_.push_back("Content-Type: application/X-other-1;");            }            send_buffer_.push_back(" name=\"" + it1->second + "\"");            send_buffer_.push_back("Content-Transfer-Encoding: base64");            send_buffer_.push_back("Content-Disposition: attachment; filename=\"" +                                   it1->second + "\"");            // split body            send_buffer_.push_back(ENTER);            send_buffer_.push_back(std::string(it1->first.begin(), it1->first.end()));            // terminate the message with the boundary + "--"            if ((it1 + 1) == attachment_.end())                send_buffer_.push_back(BOUNDARY_FLAG + boundary + BOUNDARY_FLAG);            else                send_buffer_.push_back(BOUNDARY_FLAG + boundary);        }    }    // add \r\n to each item    for (int i = 0; i < (int)send_buffer_.size(); ++i) {        send_buffer_[i] += ENTER;    }}

#ifndef __USTD_STRING_H__#define __USTD_STRING_H__#include #include #include #include #include #include #include namespace ustd{namespace string{static std::string sprintf(const char *format, ...);static size_t base64encode(const char *data, const int &len, std::vector &dest);static size_t base64decode(const char *data, const int &len, std::vector &dest);static size_t split(const std::string &src, const std::string &delim, std::vector &dst);static std::string ltrim(const std::string &src, const std::string &key = " ");static std::string rtrim(const std::string &src, const std::string &key = " ");static std::string trim(const std::string &src, const std::string &key = " ");static int replace(std::string &base, const std::string &src, const std::string &dst = "");static std::string url_encode(const std::string &url_text);static std::string url_base64encode(const std::string &url);static std::string url_decode(const std::string &url_text);static std::string url_base64decode(const std::string &url);static std::string tolower(const std::string &src_text);static std::string toupper(const std::string &src_text);static size_t args_parse(const std::string &args, std::unordered_map &args_map, const std::string &delim = "&");std::string url_base64encode(const std::string &url){    std::string url_text(url);    std::vector buffer;    if (ustd::string::base64encode(url_text.c_str(), url_text.size(), buffer) > 0)    {        url_text.assign(&buffer[0], buffer.size());        ustd::string::replace(url_text, "+", "-");        ustd::string::replace(url_text, "/", "_");        return url_text;    }    return "";}std::string url_base64decode(const std::string &url){    std::string url_text(url);    ustd::string::replace(url_text, "-", "+");    ustd::string::replace(url_text, "_", "/");    std::vector buffer;    if (ustd::string::base64decode(url_text.c_str(), url_text.size(), buffer) > 0)    {        return (std::string(&buffer[0], buffer.size()));    }    return "";}std::string sprintf(const char *format, ...){    char buffer[10240] = {0x00};    va_list arg_ptr;    va_start(arg_ptr, format);    vsprintf(buffer, format, arg_ptr);    va_end(arg_ptr);    return (buffer);}size_t base64encode(const char *data, const int &len, std::vector &dest){    static const char encodedict[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";    int div = len / 3;    int mod = len % 3;    int size = div * 4 + ((mod == 0) ? 0 : 4);    dest.clear();    dest.reserve(size);    for (int i = 0; i < div; ++i)    {        unsigned char c1 = *data++;        unsigned char c2 = *data++;        unsigned char c3 = *data++;        dest.push_back(encodedict[c1 >> 2]);        dest.push_back(encodedict[((c1 << 4) | (c2 >> 4)) & 0x3f]);        dest.push_back(encodedict[((c2 << 2) | (c3 >> 6)) & 0x3f]);        dest.push_back(encodedict[c3 & 0x3f]);    }    switch (mod)    {    case 1:        {            unsigned char c1 = *data++;            dest.push_back(encodedict[(c1 & 0xfc) >> 2]);            dest.push_back(encodedict[((c1 & 0x03) << 4)]);            dest.push_back('=');            dest.push_back('=');            break;        }    case 2:        {            unsigned char c1 = *data++;            unsigned char c2 = *data++;            dest.push_back(encodedict[(c1 & 0xfc) >> 2]);            dest.push_back(encodedict[((c1 & 0x03) << 4) | ((c2 & 0xf0) >> 4)]);            dest.push_back(encodedict[((c2 & 0x0f) << 2)]);            dest.push_back('=');            break;        }    default:        {            break;        }    }    return dest.size();}size_t base64decode(const char *data, const int &len, std::vector &dest){    static const char decodedict[256] = {        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,        62,        // '+'        0, 0, 0,        63,        // '/'        52, 53, 54, 55, 56, 57, 58, 59, 60, 61,                     // '0'-'9'        0, 0, 0, 0, 0, 0, 0,        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,        13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,         // 'A'-'Z'        0, 0, 0, 0, 0, 0,        26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,        39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51          // 'a'-'z'    };    dest.clear();    if (len % 4 != 0)    {        return dest.size();    }    int div = len / 4;    int size = div * 3;    dest.reserve(size);    unsigned char *udata = (unsigned char *)data;    for (int i = 0; i < div; ++i)    {        int key = decodedict[*udata++] << 18;        key += decodedict[*udata++] << 12;        dest.push_back((char)((key & 0x00ff0000) >> 16));        if (*udata != '=')        {            key += decodedict[*udata++] << 6;            dest.push_back((char)((key & 0x0000ff00) >> 8));            if (*udata != '=')            {                key += decodedict[*udata++];                dest.push_back((char)(key & 0x000000ff));            }        }    }    return dest.size();}size_t split(const std::string &src, const std::string &delim, std::vector &dst){    dst.clear();    size_t idx = 0;    size_t pos = src.find(delim, idx);    while (pos != std::string::npos)    {        dst.push_back(src.substr(idx, pos - idx));        idx = pos + delim.length();        pos = src.find(delim, idx);    }    dst.push_back(src.substr(idx));    return dst.size();}std::string ltrim(const std::string &src, const std::string &key){    size_t pos = src.find_first_not_of(key);    if (pos != std::string::npos)    {        return src.substr(pos);    }    return ("");}std::string rtrim(const std::string &src, const std::string &key){    size_t pos = src.find_last_not_of(key);    if (pos != std::string::npos)    {        return src.substr(0, pos + 1);    }    return ("");}std::string trim(const std::string &src, const std::string &key){    return ltrim(rtrim(src, key), key);}int replace(std::string &base, const std::string &src, const std::string &dst){    int count = 0;    size_t src_len = src.length();    size_t dst_len = dst.length();    size_t pos = base.find(src, 0);    while (pos != std::string::npos)    {        count += 1;        base.replace(pos, src_len, dst);        pos = base.find(src, pos + dst_len);    }    return count;}std::string url_encode(const std::string &url_text){    size_t idx = 0;    std::string encode_text;    char hex[] = "0123456789abcdef";    size_t str_size = url_text.size();    while (idx < str_size)    {        unsigned char ch = url_text[idx++];        //0-9 a-z A-Z        //- _ . ! ~ * ( ) \'        //: ; ? @ & =        if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == '-' || ch == '_' || ch == '.')        {            encode_text += ch;        }        else        {            encode_text += "%";            encode_text += hex[ch / 16];            encode_text += hex[ch % 16];        }    }    return encode_text;}std::string url_decode(const std::string &url_text){    size_t idx = 0;    std::string decode_text;    size_t str_size = url_text.size();    while (idx < str_size)    {        char ch = url_text[idx++];        switch (ch)        {        case '%':            {                std::string str = url_text.substr(idx, 2);                decode_text += static_cast(strtol(str.c_str(), NULL, 16));                idx += 2;            }            break;        case '+':            {                decode_text += ' ';            }            break;        default:            {                decode_text += ch;            }            break;        }    }    return decode_text;}std::string tolower(const std::string &src_text){    std::string lower_text = src_text;    transform(lower_text.begin(), lower_text.end(), lower_text.begin(), (int (*)(int))::tolower);    return lower_text;}std::string toupper(const std::string &src_text){    std::string upper_text = src_text;    transform(upper_text.begin(), upper_text.end(), upper_text.begin(), (int (*)(int))::toupper);    return upper_text;}size_t args_parse(const std::string &args, std::unordered_map &args_map, const std::string &delim){    args_map.clear();    size_t args_count = 0;    std::string args_text = args;    size_t idx = args.find("?");    if (idx != std::string::npos)    {        args_text = args.substr(idx + 1);    }    std::vector tokens;    if (ustd::string::split(args_text, delim, tokens) > 0)    {        for (size_t i = 0; i < tokens.size(); ++i)        {            size_t pos = tokens[i].find("=");            if (pos != std::string::npos)            {                std::string key = ustd::string::tolower(ustd::string::trim(tokens[i].substr(0, pos)));                std::string value = ustd::string::trim(tokens[i].substr(pos + 1));                if (!key.empty() && args_map.find(key) == args_map.end())                {                    args_map.insert(std::make_pair(key, value));                    args_count += 1;                }            }        }    }    return args_count;}}}#endif
0