C++基于Smtp协议发送邮件

SMTP协议的定义:

  •   SMTP 是一种TCP协议支持的提供可靠且有效电子邮件传输的应用层协议;
  •   SMTP 是建立在 TCP上的一种邮件服务,主要用于传输系统之间的邮件信息并提供来信有关的通知;
  •   SMTP 独立于特定的传输子系统,且只需要可靠有序的数据流信道支持;
  •   SMTP 重要特性之一是其能跨越网络传输邮件,即“ SMTP 邮件中继”;
  •   SMTP是一个相对简单的基于文本的协议。

SMTP邮件发送实现步骤

一、连接到邮件服务器

既然SMTP是建立在TCP协议上的,那么只需要采用传统的socket来连接到服务器即可

1int SmtpEmail::Connect() 2{ 3 m_socketfd = socket(AF_INET, SOCK_STREAM, 0); 4 if (m_socketfd == INVALID_SOCKET) 5 { 6 m_lastErrorMsg = "Error on creating socket fd."; 7 return -1; 8 } 9 10 addrinfo inAddrInfo = { 0 }; 11 inAddrInfo.ai_family = AF_INET; 12 inAddrInfo.ai_socktype = SOCK_STREAM; 13 14 15 if (getaddrinfo(m_host.c_str(), m_port.c_str(), &inAddrInfo, &m_addrinfo) != 0) // error occurs 16 { 17 m_lastErrorMsg = "Error on calling getadrrinfo()."; 18 return -2; 19 } 20 21 22 if (connect(m_socketfd, m_addrinfo->ai_addr, m_addrinfo->ai_addrlen)) 23 { 24 m_lastErrorMsg = "Error on calling connect()."; 25 return -3; 26 } 27 return 0; 28}

二、向服务器发送ehlo指令

1 Read(buffer, 999); 2 if (strncmp(buffer, "220", 3) != 0) // not equal to 220 3 { 4 m_lastErrorMsg = buffer; 5 return 220; 6 } 7 8 //向服务器发送ehlo 9 std::string command = "ehlo EmailService\r\n"; 10 Write(command.c_str(), command.length());

三、进行登录验证

1 command = "AUTH PLAIN "; 2 std::string auth = '\0' + info.senderEmail + '\0' + info.password; 3 command += base64Encode(auth.data(), auth.size()); 4 command += "\r\n"; 5 Write(command.c_str(), command.length());

四、设置邮件发送者的邮箱地址

1command = "mail FROM:<" + info.senderEmail + ">\r\n"; 2Write( command.c_str(), command.length());

五、设置邮件接收者的邮箱地址

1command = "RCPT TO:<" + info.recipientEmail + ">\r\n"; 2Write( command.c_str(), command.length());

六、准备发送邮件

1command = "data\r\n"; 2Write( command.c_str(), command.length());

七、组装并发送邮件内容

1std::string SimpleSmtpEmail::GetEmailBody(const EmailInfo &info) 2{ 3 //设定邮件的发送者名称、接收者名称、邮件主题,邮件内容。 4 std::ostringstream message; 5 message << "From: =?" << info.charset << "?b?" << base64Encode(info.sender.c_str(), info.sender.length()) << "?= <" << info.senderEmail << ">\r\n"; 6 7 std::vector<std::string> vecToList; 8 for (auto item : info.recvList) 9 { 10 std::string to = "=?" + info.charset + "?b?" + base64Encode(item.second.c_str(), item.second.length()) + "?= <" + item.first + ">"; 11 vecToList.push_back(to); 12 } 13 14 message << "To: " << join(vecToList, ",") << "\r\n"; 15 message << "Subject: =?" << info.charset << "?b?" << base64Encode(info.subject.c_str(), info.subject.length()) << "?=\r\n"; 16 message << "MIME-Version: 1.0\r\n"; 17 18 if (info.ccEmail.size() > 0) 19 { 20 std::vector<std::string> vecCcList; 21 for (auto item : info.ccEmail) 22 { 23 std::string cc = "=?" + info.charset + "?b?" + base64Encode(item.first.c_str(), item.first.length()) + "?= <" + item.second + ">"; 24 vecCcList.push_back(cc); 25 } 26 message << "Cc:" << join(vecCcList, ",") << "\r\n"; 27 } 28 29 message << "Content-Type: " << "text/plain" << "; charset=\"" << info.charset << "\"\r\n"; 30 message << "Content-Transfer-Encoding: base64\r\n"; 31 message << "\r\n"; 32 message << base64Encode(info.message.c_str(), info.message.length()); 33 message << "\r\n.\r\n"; 34 return message.str(); 35} 36 37command = std::move(GetEmailBody(info)); 38Write( command.c_str(), command.length());

八、结束发送过程

Write( "quit\r\n", 6);

附完整代码,支持ssl

头文件:

1#pragma once 2#include <string> 3#include <vector> 4#include <map> 5 6#include <openssl/ossl_typ.h> 7 8#ifndef WIN32 9#include<netdb.h> 10#endif 11 12class SmtpBase 13{ 14protected: 15 struct EmailInfo 16 { 17 std::string smtpServer; //the SMTP server 18 std::string serverPort; //the SMTP server port 19 std::string charset; //the email character set 20 std::string sender; //the sender's name 21 std::string senderEmail; //the sender's email 22 std::string password; //the password of sender 23 std::string recipient; //the recipient's name 24 std::string recipientEmail; //the recipient's email 25 26 std::map<std::string, std::string> recvList; //收件人列表<email, name> 27 28 std::string subject; //the email message's subject 29 std::string message; //the email message body 30 31 std::map<std::string, std::string> ccEmail; //抄送列表 32 std::vector<std::string> attachment; //附件 33 }; 34public: 35 36 virtual ~SmtpBase() {} 37 38 39 virtual int SendEmail(const std::string& from, const std::string& passs, const std::string& to, const std::string& subject, const std::string& strMessage) = 0; 40 41 virtual int SendEmail(const std::string& from, const std::string& passs, const std::vector<std::string>& vecTo, 42 const std::string& subject, const std::string& strMessage, const std::vector<std::string>& attachment,const std::vector<std::string>& ccList) = 0; 43 44 std::string GetLastError() 45 { 46 return m_lastErrorMsg; 47 } 48 49 virtual int Read(void* buf, int num) = 0; 50 virtual int Write(const void* buf, int num) = 0; 51 virtual int Connect() = 0; 52 virtual int DisConnect() = 0; 53 54protected: 55 56 std::string m_lastErrorMsg; 57 58 59}; 60 61 62class SmtpEmail : public SmtpBase 63{ 64 65public: 66 SmtpEmail(const std::string& emailHost, const std::string& port); 67 ~SmtpEmail(); 68 69 int SendEmail(const std::string& from, const std::string& passs, const std::string& to, const std::string& subject, const std::string& strMessage); 70 71 int SendEmail(const std::string& from, const std::string& passs, const std::vector<std::string>& vecTo, 72 const std::string& subject, const std::string& strMessage, const std::vector<std::string>& attachment, const std::vector<std::string>& ccList); 73protected: 74 int Read(void* buf, int num); 75 int Write(const void* buf, int num); 76 int Connect(); 77 int DisConnect(); 78 79 virtual std::string GetEmailBody(const EmailInfo & info); 80private: 81 //int SMTPSSLComunicate(SSL *connection, const EmailInfo &info); 82 int SMTPComunicate(const EmailInfo &info); 83 84 85 86 87protected: 88 addrinfo* m_addrinfo; 89 int m_socketfd; 90 91 std::string m_host; 92 std::string m_port; 93 94 bool m_isConnected; 95}; 96 97class SimpleSmtpEmail : public SmtpEmail 98{ 99public: 100 using SmtpEmail::SmtpEmail; 101 virtual std::string GetEmailBody(const EmailInfo & info); 102}; 103 104class SslSmtpEmail : public SmtpEmail 105{ 106public: 107 using SmtpEmail::SmtpEmail; 108 ~SslSmtpEmail(); 109 110 int Connect(); 111 int DisConnect(); 112protected: 113 int Read(void* buf, int num); 114 int Write(const void* buf, int num); 115private: 116 SSL_CTX *m_ctx; 117 SSL *m_ssl; 118}; 119 120class SimpleSslSmtpEmail : public SslSmtpEmail 121{ 122public: 123 using SslSmtpEmail::SslSmtpEmail; 124 virtual std::string GetEmailBody(const EmailInfo & info); 125};

实现文件:

1#ifdef WIN32 2#include <WinSock2.h> 3#endif 4#include "SSLEmail.h" 5#include <fstream> 6#include <sstream> 7#include <string.h> 8#include <openssl/err.h> 9#include <openssl/ssl.h> 10#ifdef WIN32 11#include <WinSock2.h> 12#include <WS2tcpip.h> 13#pragma comment(lib, "ws2_32.lib") 14#else 15#include <unistd.h> 16#include <arpa/inet.h> 17#include <sys/types.h> /* See NOTES */ 18#include <sys/socket.h> 19#define INVALID_SOCKET -1 20#endif 21 22template<typename T> 23std::string join(T& vecData, const std::string& delim) 24{ 25 if (vecData.size() <= 0) 26 { 27 return std::string(); 28 } 29 std::stringstream ss; 30 for (auto& item : vecData) 31 { 32 ss << delim << item ; 33 } 34 35 return ss.str().substr(delim.length()); 36} 37 38const char MimeTypes[][2][128] = 39{ 40 { "***", "application/octet-stream" }, 41 { "csv", "text/csv" }, 42 { "tsv", "text/tab-separated-values" }, 43 { "tab", "text/tab-separated-values" }, 44 { "html", "text/html" }, 45 { "htm", "text/html" }, 46 { "doc", "application/msword" }, 47 { "docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document" }, 48 { "ods", "application/x-vnd.oasis.opendocument.spreadsheet" }, 49 { "odt", "application/vnd.oasis.opendocument.text" }, 50 { "rtf", "application/rtf" }, 51 { "sxw", "application/vnd.sun.xml.writer" }, 52 { "txt", "text/plain" }, 53 { "xls", "application/vnd.ms-excel" }, 54 { "xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }, 55 { "pdf", "application/pdf" }, 56 { "ppt", "application/vnd.ms-powerpoint" }, 57 { "pps", "application/vnd.ms-powerpoint" }, 58 { "pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation" }, 59 { "wmf", "image/x-wmf" }, 60 { "atom", "application/atom+xml" }, 61 { "xml", "application/xml" }, 62 { "json", "application/json" }, 63 { "js", "application/javascript" }, 64 { "ogg", "application/ogg" }, 65 { "ps", "application/postscript" }, 66 { "woff", "application/x-woff" }, 67 { "xhtml","application/xhtml+xml" }, 68 { "xht", "application/xhtml+xml" }, 69 { "zip", "application/zip" }, 70 { "gz", "application/x-gzip" }, 71 { "rar", "application/rar" }, 72 { "rm", "application/vnd.rn-realmedia" }, 73 { "rmvb", "application/vnd.rn-realmedia-vbr" }, 74 { "swf", "application/x-shockwave-flash" }, 75 { "au", "audio/basic" }, 76 { "snd", "audio/basic" }, 77 { "mid", "audio/mid" }, 78 { "rmi", "audio/mid" }, 79 { "mp3", "audio/mpeg" }, 80 { "aif", "audio/x-aiff" }, 81 { "aifc", "audio/x-aiff" }, 82 { "aiff", "audio/x-aiff" }, 83 { "m3u", "audio/x-mpegurl" }, 84 { "ra", "audio/vnd.rn-realaudio" }, 85 { "ram", "audio/vnd.rn-realaudio" }, 86 { "wav", "audio/x-wave" }, 87 { "wma", "audio/x-ms-wma" }, 88 { "m4a", "audio/x-m4a" }, 89 { "bmp", "image/bmp" }, 90 { "gif", "image/gif" }, 91 { "jpe", "image/jpeg" }, 92 { "jpeg", "image/jpeg" }, 93 { "jpg", "image/jpeg" }, 94 { "jfif", "image/jpeg" }, 95 { "png", "image/png" }, 96 { "svg", "image/svg+xml" }, 97 { "tif", "image/tiff" }, 98 { "tiff", "image/tiff" }, 99 { "ico", "image/vnd.microsoft.icon" }, 100 { "css", "text/css" }, 101 { "bas", "text/plain" }, 102 { "c", "text/plain" }, 103 { "h", "text/plain" }, 104 { "rtx", "text/richtext" }, 105 { "mp2", "video/mpeg" }, 106 { "mpa", "video/mpeg" }, 107 { "mpe", "video/mpeg" }, 108 { "mpeg", "video/mpeg" }, 109 { "mpg", "video/mpeg" }, 110 { "mpv2", "video/mpeg" }, 111 { "mov", "video/quicktime" }, 112 { "qt", "video/quicktime" }, 113 { "lsf", "video/x-la-asf" }, 114 { "lsx", "video/x-la-asf" }, 115 { "asf", "video/x-ms-asf" }, 116 { "asr", "video/x-ms-asf" }, 117 { "asx", "video/x-ms-asf" }, 118 { "avi", "video/x-msvideo" }, 119 { "3gp", "video/3gpp" }, 120 { "3gpp", "video/3gpp" }, 121 { "3g2", "video/3gpp2" }, 122 { "movie","video/x-sgi-movie" }, 123 { "mp4", "video/mp4" }, 124 { "wmv", "video/x-ms-wmv" }, 125 { "webm","video/webm" }, 126 { "m4v", "video/x-m4v" }, 127 { "flv", "video/x-flv" } 128}; 129 130 131std::string fileBasename(const std::string path) 132{ 133 std::string filename = path.substr(path.find_last_of("/\\") + 1); 134 return filename; 135} 136 137std::string getFileContents(const char *filename) 138{ 139 std::ifstream in(filename, std::ios::in | std::ios::binary); 140 if (in) 141 { 142 std::string contents; 143 in.seekg(0, std::ios::end); 144 contents.resize(in.tellg()); 145 in.seekg(0, std::ios::beg); 146 in.read(&contents[0], contents.size()); 147 in.close(); 148 return(contents); 149 } 150 throw(errno); 151} 152 153std::string GetFileExtension(const std::string& FileName) 154{ 155 if (FileName.find_last_of(".") != std::string::npos) 156 return FileName.substr(FileName.find_last_of(".") + 1); 157 return ""; 158} 159 160const char* GetMimeTypeFromFileName(char* szFileExt) 161{ 162 for (unsigned int i = 0; i < sizeof(MimeTypes) / sizeof(MimeTypes[0]); i++) 163 { 164 if (strcmp(MimeTypes[i][0], szFileExt) == 0) 165 { 166 return MimeTypes[i][1]; 167 } 168 } 169 return MimeTypes[0][1]; //if does not match any, "application/octet-stream" is returned 170} 171 172char* base64Encode(char const* origSigned, unsigned origLength) 173{ 174 static const char base64Char[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 175 unsigned char const* orig = (unsigned char const*)origSigned; // in case any input bytes have the MSB set 176 if (orig == NULL) return NULL; 177 178 unsigned const numOrig24BitValues = origLength / 3; 179 bool havePadding = origLength > numOrig24BitValues * 3; 180 bool havePadding2 = origLength == numOrig24BitValues * 3 + 2; 181 unsigned const numResultBytes = 4 * (numOrig24BitValues + havePadding); 182 char* result = new char[numResultBytes + 3]; // allow for trailing '/0' 183 184 // Map each full group of 3 input bytes into 4 output base-64 characters: 185 unsigned i; 186 for (i = 0; i < numOrig24BitValues; ++i) 187 { 188 result[4 * i + 0] = base64Char[(orig[3 * i] >> 2) & 0x3F]; 189 result[4 * i + 1] = base64Char[(((orig[3 * i] & 0x3) << 4) | (orig[3 * i + 1] >> 4)) & 0x3F]; 190 result[4 * i + 2] = base64Char[((orig[3 * i + 1] << 2) | (orig[3 * i + 2] >> 6)) & 0x3F]; 191 result[4 * i + 3] = base64Char[orig[3 * i + 2] & 0x3F]; 192 } 193 194 // Now, take padding into account. (Note: i == numOrig24BitValues) 195 if (havePadding) 196 { 197 result[4 * i + 0] = base64Char[(orig[3 * i] >> 2) & 0x3F]; 198 if (havePadding2) 199 { 200 result[4 * i + 1] = base64Char[(((orig[3 * i] & 0x3) << 4) | (orig[3 * i + 1] >> 4)) & 0x3F]; 201 result[4 * i + 2] = base64Char[(orig[3 * i + 1] << 2) & 0x3F]; 202 } 203 else 204 { 205 result[4 * i + 1] = base64Char[((orig[3 * i] & 0x3) << 4) & 0x3F]; 206 result[4 * i + 2] = '='; 207 } 208 result[4 * i + 3] = '='; 209 } 210 211 result[numResultBytes] = '\0'; 212 return result; 213} 214 215int SmtpEmail::SMTPComunicate(const EmailInfo &info) 216{ 217 if (Connect() != 0) 218 { 219 return -1; 220 } 221 char * buffer = new char[1000]; 222 memset(buffer, 0, 1000); 223 224 Read(buffer, 999); 225 if (strncmp(buffer, "220", 3) != 0) // not equal to 220 226 { 227 m_lastErrorMsg = buffer; 228 return 220; 229 } 230 231 //向服务器发送ehlo 232 std::string command = "ehlo EmailService\r\n"; 233 Write(command.c_str(), command.length()); 234 235 memset(buffer, 0, 1000); 236 Read(buffer, 999); 237 if (strncmp(buffer, "250", 3) != 0) // ehlo failed 238 { 239 m_lastErrorMsg = buffer; 240 return 250; 241 } 242 243 //进行登录验证 244 command = "AUTH PLAIN "; 245 std::string auth = '\0' + info.senderEmail + '\0' + info.password; 246 command += base64Encode(auth.data(), auth.size()); 247 command += "\r\n"; 248 Write(command.c_str(), command.length()); 249 250 memset(buffer, 0, 1000); 251 Read(buffer, 999); 252 if (strncmp(buffer, "235", 3) != 0) // login failed 253 { 254 m_lastErrorMsg = buffer; 255 return 250; 256 } 257 258 //设置邮件发送者的邮箱地址 259 command = "mail FROM:<" + info.senderEmail + ">\r\n"; 260 Write( command.c_str(), command.length()); 261 262 memset(buffer, 0, 1000); 263 Read(buffer, 999); 264 if (strncmp(buffer, "250", 3) != 0) // not ok 265 { 266 m_lastErrorMsg = buffer; 267 return 250; 268 } 269 270 //设置邮件接收者的邮箱地址 271 command = "RCPT TO:<" + info.recipientEmail + ">\r\n"; 272 Write( command.c_str(), command.length()); 273 274 memset(buffer, 0, 1000); 275 Read( buffer, 999); 276 if (strncmp(buffer, "250", 3) != 0) // not ok 277 { 278 m_lastErrorMsg = buffer; 279 return 250; 280 } 281 282 283 284 //准备发送邮件 285 command = "data\r\n"; 286 Write( command.c_str(), command.length()); 287 288 memset(buffer, 0, 1000); 289 Read( buffer, 999); 290 if (strncmp(buffer, "354", 3) != 0) // not ready to receive message 291 { 292 m_lastErrorMsg = buffer; 293 return 354; 294 } 295 296 command = std::move(GetEmailBody(info)); 297 Write( command.c_str(), command.length()); 298 299 memset(buffer, 0, 1000); 300 Read(buffer, 999); 301 if (strncmp(buffer, "250", 3) != 0) // not ok 302 { 303 m_lastErrorMsg = buffer; 304 return 250; 305 } 306 307 //结束发送过程 308 delete buffer; 309 Write( "quit\r\n", 6); 310 311 DisConnect(); 312 return 0; 313} 314 315std::string SmtpEmail::GetEmailBody(const EmailInfo &info) 316{ 317 //设定邮件的发送者名称、接收者名称、邮件主题,邮件内容。 318 std::ostringstream message; 319 message << "From: =?" << info.charset << "?b?" << base64Encode(info.sender.c_str(), info.sender.length()) << "?= <" << info.senderEmail << ">\r\n"; 320 321 std::vector<std::string> vecToList; 322 for (auto item : info.recvList) 323 { 324 std::string to = "=?" + info.charset + "?b?" + base64Encode(item.second.c_str(), item.second.length()) + "?= <" + item.first + ">"; 325 vecToList.push_back(to); 326 } 327 328 message << "To: " << join(vecToList, ",") << "\r\n"; 329 message << "Subject: =?" << info.charset << "?b?" << base64Encode(info.subject.c_str(), info.subject.length()) << "?=\r\n"; 330 message << "MIME-Version: 1.0\r\n"; 331 332 if (info.ccEmail.size() > 0) 333 { 334 std::vector<std::string> vecCcList; 335 for (auto item : info.ccEmail) 336 { 337 std::string cc = "=?" + info.charset + "?b?" + base64Encode(item.first.c_str(), item.first.length()) + "?= <" + item.second + ">"; 338 vecCcList.push_back(cc); 339 } 340 message << "Cc:" << join(vecCcList, ",") << "\r\n"; 341 } 342 343 message << "Content-Type:multipart/mixed; boundary=\"Separator_ztq_000\"\r\n\r\n"; 344 message << "--Separator_ztq_000\r\n"; 345 message << "Content-Type: multipart/alternative; boundary=\"Separator_ztq_111\"\r\n\r\n"; 346 message << "--Separator_ztq_111\r\n"; 347 message << "Content-Type: " << "text/plain" << "; charset=\"" << info.charset << "\"\r\n"; 348 message << "Content-Transfer-Encoding: base64\r\n"; 349 message << base64Encode(info.message.c_str(), info.message.length()); 350 message << "\r\n\r\n"; 351 message << "--Separator_ztq_111--\r\n"; 352 //----------------------------------------------------------- 353 354 for (auto item : info.attachment) 355 { 356 std::string filename = fileBasename(item); 357 std::string strContext = getFileContents(item.c_str()); 358 std::string fileContext = base64Encode(strContext.c_str(), strContext.length()); 359 std::string extension = GetFileExtension(filename); 360 std::string mimetype = GetMimeTypeFromFileName((char*)extension.c_str()); 361 message << "--Separator_ztq_000\r\n"; 362 message << "Content-Type: " << mimetype << "; name=\"" << filename << "\"\r\n"; 363 message << "Content-Transfer-Encoding: base64\r\n"; 364 message << "Content-Disposition: attachment; filename=\"" << filename << "\"\r\n\r\n"; 365 message << fileContext + "\r\n\r\n"; 366 } 367 368 //----------------------------------------------------------- 369 message << "\r\n.\r\n"; 370 return message.str(); 371} 372 373SmtpEmail::SmtpEmail(const std::string& emailHost, const std::string& port) :m_host(emailHost), m_port(port) 374{ 375 376} 377 378SmtpEmail::~SmtpEmail() 379{ 380 381} 382 383int SmtpEmail::Read(void* buf, int num) 384{ 385 return recv(m_socketfd, (char*)buf, num, 0); 386} 387int SmtpEmail::Write(const void* buf, int num) 388{ 389 return send(m_socketfd, (char*)buf, num, 0); 390} 391 392int SmtpEmail::Connect() 393{ 394#ifdef WIN32 395 //start socket connection 396 WSADATA wsadata; 397 WSAStartup(MAKEWORD(2, 2), &wsadata); 398#endif 399 m_socketfd = socket(AF_INET, SOCK_STREAM, 0); 400 if (m_socketfd == INVALID_SOCKET) 401 { 402 m_lastErrorMsg = "Error on creating socket fd."; 403 return -1; 404 } 405 406 addrinfo inAddrInfo = { 0 }; 407 inAddrInfo.ai_family = AF_INET; 408 inAddrInfo.ai_socktype = SOCK_STREAM; 409 410 411 if (getaddrinfo(m_host.c_str(), m_port.c_str(), &inAddrInfo, &m_addrinfo) != 0) // error occurs 412 { 413 m_lastErrorMsg = "Error on calling getadrrinfo()."; 414 return -2; 415 } 416 417 418 if (connect(m_socketfd, m_addrinfo->ai_addr, m_addrinfo->ai_addrlen)) 419 { 420 m_lastErrorMsg = "Error on calling connect()."; 421 return -3; 422 } 423 return 0; 424} 425 426int SmtpEmail::DisConnect() 427{ 428 freeaddrinfo(m_addrinfo); 429#ifdef WIN32 430 closesocket(m_socketfd); 431#else 432 close(m_socketfd); 433#endif 434 return 0; 435} 436 437/*********************************************************************************/ 438 439 440std::string SimpleSmtpEmail::GetEmailBody(const EmailInfo &info) 441{ 442 //设定邮件的发送者名称、接收者名称、邮件主题,邮件内容。 443 std::ostringstream message; 444 message << "From: =?" << info.charset << "?b?" << base64Encode(info.sender.c_str(), info.sender.length()) << "?= <" << info.senderEmail << ">\r\n"; 445 446 std::vector<std::string> vecToList; 447 for (auto item : info.recvList) 448 { 449 std::string to = "=?" + info.charset + "?b?" + base64Encode(item.second.c_str(), item.second.length()) + "?= <" + item.first + ">"; 450 vecToList.push_back(to); 451 } 452 453 message << "To: " << join(vecToList, ",") << "\r\n"; 454 message << "Subject: =?" << info.charset << "?b?" << base64Encode(info.subject.c_str(), info.subject.length()) << "?=\r\n"; 455 message << "MIME-Version: 1.0\r\n"; 456 457 if (info.ccEmail.size() > 0) 458 { 459 std::vector<std::string> vecCcList; 460 for (auto item : info.ccEmail) 461 { 462 std::string cc = "=?" + info.charset + "?b?" + base64Encode(item.first.c_str(), item.first.length()) + "?= <" + item.second + ">"; 463 vecCcList.push_back(cc); 464 } 465 message << "Cc:" << join(vecCcList, ",") << "\r\n"; 466 } 467 468 message << "Content-Type: " << "text/plain" << "; charset=\"" << info.charset << "\"\r\n"; 469 message << "Content-Transfer-Encoding: base64\r\n"; 470 message << "\r\n"; 471 message << base64Encode(info.message.c_str(), info.message.length()); 472 message << "\r\n.\r\n"; 473 return message.str(); 474} 475 476/***************************************************************************************************/ 477 478SslSmtpEmail::~SslSmtpEmail() 479{ 480 481} 482 483int SslSmtpEmail::Connect() 484{ 485 if (SmtpEmail::Connect() == 0) 486 { 487 SSL_library_init(); 488 OpenSSL_add_all_algorithms(); 489 SSL_load_error_strings(); 490 m_ctx = SSL_CTX_new(SSLv23_client_method()); 491 492 m_ssl = SSL_new(m_ctx); 493 SSL_set_fd(m_ssl, m_socketfd); 494 SSL_connect(m_ssl); 495 } 496 return 0; 497} 498 499int SslSmtpEmail::DisConnect() 500{ 501 SSL_shutdown(m_ssl); 502 SSL_free(m_ssl); 503 SSL_CTX_free(m_ctx); 504 505 SmtpEmail::DisConnect(); 506 return 0; 507} 508 509 510 511int SmtpEmail::SendEmail(const std::string& from, const std::string& passs, const std::string& to, const std::string& subject, const std::string& strMessage) 512{ 513 EmailInfo info; 514 info.charset = "UTF-8"; 515 info.sender = from; 516 info.password = passs; 517 info.senderEmail = from; 518 info.recipientEmail = to; 519 520 info.recvList[to] = ""; 521 522 info.subject = subject; 523 info.message = strMessage; 524 525 return SMTPComunicate(info); 526} 527 528 529 530int SmtpEmail::SendEmail(const std::string& from, const std::string& passs, const std::vector<std::string>& vecTo, 531 const std::string& subject, const std::string& strMessage, const std::vector<std::string>& attachment, const std::vector<std::string>& ccList) 532{ 533 std::vector<std::string> recvList; 534 recvList.insert(recvList.end(), vecTo.begin(), vecTo.end()); 535 recvList.insert(recvList.end(), ccList.begin(), ccList.end()); 536 537 for (auto& item : recvList) 538 { 539 EmailInfo info; 540 info.charset = "UTF-8"; 541 info.sender = from; 542 info.password = passs; 543 info.senderEmail = from;; 544 info.recipientEmail = item; 545 546 for (auto item : vecTo) 547 { 548 info.recvList[item] = ""; 549 } 550 551 info.subject = subject; 552 info.message = strMessage; 553 554 for (auto& item : ccList) 555 { 556 info.ccEmail[item] = item; 557 } 558 559 info.attachment = attachment; 560 if (SMTPComunicate(info) != 0) 561 { 562 return -1; 563 } 564 } 565 return 0; 566} 567 568 569 570int SslSmtpEmail::Read(void * buf, int num) 571{ 572 return SSL_read(m_ssl, buf, num); 573} 574 575int SslSmtpEmail::Write(const void * buf, int num) 576{ 577 return SSL_write(m_ssl, buf, num); 578} 579 580 581std::string SimpleSslSmtpEmail::GetEmailBody(const EmailInfo &info) 582{ 583 //设定邮件的发送者名称、接收者名称、邮件主题,邮件内容。 584 std::ostringstream message; 585 message << "From: =?" << info.charset << "?b?" << base64Encode(info.sender.c_str(), info.sender.length()) << "?= <" << info.senderEmail << ">\r\n"; 586 587 std::vector<std::string> vecToList; 588 for (auto item : info.recvList) 589 { 590 std::string to = "=?" + info.charset + "?b?" + base64Encode(item.second.c_str(), item.second.length()) + "?= <" + item.first + ">"; 591 vecToList.push_back(to); 592 } 593 594 message << "To: " << join(vecToList, ",") << "\r\n"; 595 message << "Subject: =?" << info.charset << "?b?" << base64Encode(info.subject.c_str(), info.subject.length()) << "?=\r\n"; 596 message << "MIME-Version: 1.0\r\n"; 597 598 if (info.ccEmail.size() > 0) 599 { 600 std::vector<std::string> vecCcList; 601 for (auto item : info.ccEmail) 602 { 603 std::string cc = "=?" + info.charset + "?b?" + base64Encode(item.first.c_str(), item.first.length()) + "?= <" + item.second + ">"; 604 vecCcList.push_back(cc); 605 } 606 message << "Cc:" << join(vecCcList, ",") << "\r\n"; 607 } 608 609 message << "Content-Type: " << "text/plain" << "; charset=\"" << info.charset << "\"\r\n"; 610 message << "Content-Transfer-Encoding: base64\r\n"; 611 message << "\r\n"; 612 message << base64Encode(info.message.c_str(), info.message.length()); 613 message << "\r\n.\r\n"; 614 return message.str(); 615}
点赞
收藏

评论区

加载中...

相关推荐

最全总结!聊聊 Python 发送邮件的几种方式

1\.前言邮件,作为最正式规范的沟通方式,在日常办公过程中经常被用到我们都知道Python内置了对SMTP的支持,可以发送纯文本、富文本、HTML等格式的邮件本文将聊聊利用 Python发送邮件的3种方式2\.准备以126邮箱为例,在编码之前,我们需要开启SMTP服务然后,手动新增一个授权码其中,账号、授权码和服务器地址用于连接登录

最全总结!聊聊 Python 发送邮件的几种方式

1\.前言邮件,作为最正式规范的沟通方式,在日常办公过程中经常被用到我们都知道Python内置了对SMTP的支持,可以发送纯文本、富文本、HTML等格式的邮件本文将聊聊利用 Python发送邮件的3种方式2\.准备以126邮箱为例,在编码之前,我们需要开启SMTP服务然后,手动新增一个授权码其中,账号、授权码和服务器地址用于连接登录

手把手教你使用Python轻松搞定发邮件

前言现在生活节奏加快,人们之间交流方式也有了天差地别,为了更加便捷的交流沟通,电子邮件产生了,众所周知,电子邮件其实就是客户端和服务器端发送接受数据一样,他有一个发信和一个收信的功能,电子邮件的通信协议为SMTP,POP3,IMAP,而且他们都属于tcp/ip协议,像我们经常用到的QQ邮箱,网易邮箱,这些都是同样的模式。准备编辑器:sublime

JavaMail发送和接收邮件API(详解)

一、JavaMail概述:    JavaMail是由Sun定义的一套收发电子邮件的API,不同的厂商可以提供自己的实现类。但它并没有包含在JDK中,而是作为JavaEE的一部分。    厂商所提供的JavaMail服务程序可以有选择地实现某些邮件协议,常见的邮件协议包括:SMTP:简单邮件传输

TCP、UDP和HTTP简述整理

http:是用于www浏览的一个协议。tcp:是机器之间建立连接用的到的一个协议。1、TCP/IP是个协议组,可分为三个层次:网络层、传输层和应用层。在网络层有IP协议、ICMP协议、ARP协议、RARP协议和BOOTP协议。在传输层中有TCP协议与UDP协议。在应用层有FTP、HTTP、TELNET、SMTP、DNS等协

TCP、UDP和HTTP区别详解

http:是用于www浏览的一个协议。tcp:是机器之间建立连接用的到的一个协议。1、TCP/IP是个协议组,可分为三个层次:网络层、传输层和应用层。在网络层有IP协议、ICMP协议、ARP协议、RARP协议和BOOTP协议。在传输层中有TCP协议与UDP协议。在应用层有FTP、HTTP、TELNET、SMTP、DNS等协议。

C++基于Smtp协议发送邮件 - HelloWorld