完美支持中文及附件的基于libcur邮件客户端封装类
发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,最近做了一个小项目需要在windows c++ 环境下,发送邮件在网上查了很多,大部分编译不成功,少部分中文乱码参考了 libcurl实例及,网友的源码,努力了两天终于得到了比较圆满的结果从 http
千家信息网最后更新 2026年11月02日完美支持中文及附件的基于libcur邮件客户端封装类
最近做了一个小项目需要在windows c++ 环境下,发送邮件
在网上查了很多,大部分编译不成功,少部分中文乱码
参考了 libcurl实例及,网友的源码,努力了两天终于得到了比较圆满的结果
从 https://github.com/honeyligo/curlsmtp.git 上修改
话不多说上源码
调用方式
std::vector to = { "43982653@qq.com" }; std::vector cc = { "fj1981@126.com" }; 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("fj1981@126.com"); 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
数量
源码
答案
准备
邮件
中文
着急
成功
乱码
大部分
实例
方式
环境
珠玑
结果
网友
试题
道理
项目
c++
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
有格互联网科技
保险科技 互联网保险
天津市摩尔互联网科技
科技互联网产品
工业互联网科技新基建
麻工互联网科技
互联网的科技创新
互联网金融公司科技
有木互联网科技
无锡溥仪互联网科技有限公司
海南科技产业互联网平台
汉立互联网科技有限公司联系电话
温州喔噻互联网科技有限公司
互联网科技中介
世界互联网科技公司市值排名
青海科技产业互联网发展
浙南科技城互联网大厦建设工程
富国互联网科技002692
互联网时代科技型公司的机会
山东蛋芒互联网科技有限公司
北京路客互联网科技有限公司
科技互联网项目
科技互联网政务服务
互联网科技美容
温州喔噻互联网科技有限公司
重庆威客帮互联网科技
洛阳昕诺飞互联网科技有限公司
互联网科技和法律行业
上海万顺科技互联网有限公司招聘
恒生互联网科技趋势