完美支持中文及附件的基于libcur邮件客户端封装类
发表于:2025-12-02 作者:千家信息网编辑
千家信息网最后更新 2025年12月02日,最近做了一个小项目需要在windows c++ 环境下,发送邮件在网上查了很多,大部分编译不成功,少部分中文乱码参考了 libcurl实例及,网友的源码,努力了两天终于得到了比较圆满的结果从 http
千家信息网最后更新 2025年12月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安全错误
数据库的锁怎样保障安全
培训软件开发教程
电脑怎么变服务器
易木服务器端
广安网络技术哪家强
服务器管理控制台在哪里
互联网公司数据库
uml软件开发餐馆点餐
软件开发端
网站开发专业包括软件开发吗
网络安全警方宣传
产品信息管理数据库设计
滁州通信软件开发
电脑软件开发职校
阿里云服务器管理办法
供电所网络安全整治排查
银行网络技术架构
matlab 读取数据库
网络安全法第六十八条
深圳软件开发工资为什么那么高
湘潭服务器
h2数据库能用吗
如何练习计算机网络技术
定制软件开发出路
中国教育电视台网络安全
命令修改linux服务器时间
厦门企诺网络技术有限公司
软件开发公司行业
mac 数据库服务器推荐
网络安全手抄报漫画版
软件开发万元笔记本推荐