最近做了一个小项目需要在windows c++ 环境下,发送邮件
在网上查了很多,大部分编译不成功,少部分中文乱码
参考了 libcurl实例及,网友的源码,努力了两天终于得到了比较圆满的结果
从 https://github.com/honeyligo/curlsmtp.git 上修改
话不多说上源码
调用方式
std::vector<std::string> to = { "43982653@qq.com" }; std::vector<std::string> cc = { "fj1981@126.com" }; std::vector<std::string> 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);
<ustd_string.h>
#ifndef __CURL_SMTP_H__ #define __CURL_SMTP_H__ #include <vector> #include <string.h> #include <unordered_map> #include <curl/curl.h> #include "ustd_string.h" #define SMTP_SERVER "smtp.126.com" #define SMTP_PORT "25" class CurlSmtp { struct WriteThis { int pos; int counter; std::vector<std::string> 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<std::string>& to); void set_secret(const std::vector<std::string>& secret); void set_cc(const std::vector<std::string>& cc); void set_attach(const std::vector<std::string>& 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<std::string> send_buffer_; std::string from_; std::vector<std::string> to_; std::vector<std::string> cc_; std::vector<std::string> secret_; std::vector<std::string> 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::pair<std::vector<char>, std::string>> attachment_; CURL *curl_ = nullptr; struct curl_slist* rcpt_list_; struct WriteThis pooh_; std::unordered_map<std::string, std::string> typeMap_; }; #endif // !__CURL_SMTP_H__
<curlsmtp.cpp>
#include "stdafx.h" //#include <fstream> #include "curlsmtp.h" #include <fstream> #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 * 10 size_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<std::string>& to) { to_.resize(to.size()); to_.assign(to.begin(), to.end()); } void CurlSmtp::set_secret(const std::vector<std::string>& secret) { secret_.resize(secret.size()); secret_.assign(secret.begin(), secret.end()); } void CurlSmtp::set_cc(const std::vector<std::string>& cc) { cc_.resize(cc.size()); cc_.assign(cc.begin(), cc.end()); } void CurlSmtp::set_attach(const std::vector<std::string>& attach) { attach_.resize(attach.size()); attach_.assign(attach.begin(), attach.end()); } void CurlSmtp::set_subject(const std::string& subject) { std::vector<char> 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<char> filedata; char c = file.get(); for (; file.good(); c = file.get()) { if (file.bad()) break; filedata.push_back(c); } std::vector<char> 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::pair<std::vector<char>, 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; } }
<ustd_string.h>
#ifndef __USTD_STRING_H__ #define __USTD_STRING_H__ #include <vector> #include <string> #include <stdarg.h> #include <stdlib.h> #include <unordered_map> #include <algorithm> #include <cctype> namespace ustd { namespace string { static std::string sprintf(const char *format, ...); static size_t base64encode(const char *data, const int &len, std::vector<char> &dest); static size_t base64decode(const char *data, const int &len, std::vector<char> &dest); static size_t split(const std::string &src, const std::string &delim, std::vector<std::string> &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<std::string, std::string> &args_map, const std::string &delim = "&"); std::string url_base64encode(const std::string &url) { std::string url_text(url); std::vector<char> 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<char> 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<char> &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<char> &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<std::string> &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<char>(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<std::string, std::string> &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<std::string> 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
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。