libcurl实现smtp发送支持附件

http://blog.csdn.net/abqchina/article/details/53405269


1、运行环境vs2015

2、libcurl版本:curl-7.51.0

3、拼接MIME协议

4、附上代码

  1. //smtp.h  
  1. #pragma once  
  2.   
  3. #include <string>  
  4. #include <vector>  
  5.   
  6. #define SKIP_PEER_VERIFICATION  
  7. #define SKIP_HOSTNAME_VERIFICATION  
  8.   
  9.   
  10. class Smtp {  
  11. public:  
  1. //构造smtp对象设置邮件编码  
  2. nst std::string& charset="utf-8");//  
  1.        //设置stmp服务器、用户名、密码、端口(端口其实不用指定,libcurl默认25,但如果是smtps则默认是465)  
  2. void SetSmtpServer(const std::string &username, const std::string& password, const std::string& servername, const std::string &port="25");  
  3. //发送者姓名,可以不用  
  1. void SetSendName(const std::string& sendname);  
  1. //发送者邮箱  
  2. tSendMail(const std::string& sendmail);  
  1. //添加收件人  
  2. ddRecvMail(const std::string& recvmail);  
  1. //设置主题  
  2. etSubject(const std::string &subject);  
  1. //设置正文内容  
  2. etBodyContent(const std::string &content);  
  1. //添加附件  
  2. dAttachment(const std::string &filename);  
  1.        //发送邮件  
  2.     bool SendMail();  
  3. private:  
  1. //回调函数,将MIME协议的拼接的字符串由libcurl发出  
  2.  size_t payload_source(void *ptr, size_t size, size_t nmemb, void *stream);  
  1. //创建邮件MIME内容  
  2. reatMessage();  
  1. //获取文件类型  
  2. tFileType(std::string const& stype);  
  1. //设置文件名  
  2. etFileName(const std::string& FileName);  
  1. //设置文件的contenttype  
  2. etContentType(std::string const& stype);  
  1. //得到文件名  
  2. etFileName(const std::string& file, std::string& filename);  
  1.       //得到文件类型  
  2.     void GetFileType(const std::string& file, std::string& stype);  
  3.       
  4. private:  
  5.     std::string m_strCharset; //邮件编码  
  6.     std::string m_strSubject; //邮件主题  
  7.     std::string m_strContent; //邮件内容  
  8.     std::string m_strFileName; //文件名  
  9.     std::string m_strMessage;// 整个MIME协议字符串  
  10.     std::string m_strUserName;//用户名  
  11.     std::string m_strPassword;//密码  
  12.     std::string m_strServerName;//smtp服务器  
  13.     std::string m_strPort;//端口  
  14.     std::string m_strSendName;//发送者姓名  
  15.     std::string m_strSendMail;//发送者邮箱  
  16.     std::string m_strContentType;//附件contenttype  
  17.     std::string m_strFileContent;//附件内容  
  18.   
  19.     std::vector<std::string> m_vRecvMail; //收件人容器  
  20.     std::vector<std::string> m_vAttachMent;//附件容器  
  21.       
  22.   
  23. };  


//smtp.cpp
  1. #include "smtp.h"  
  2. #include "base64.h"  
  3. #include <curl/curl.h>  
  4. #include <iostream>  
  5. #include <sstream>  
  6. #include <fstream>  
  7.   
  8. Smtp::Smtp(const std::string & charset)  
  9. {  
  10.     m_strCharset = charset;  
  11.     m_vRecvMail.clear();  
  12. }  
  13.   
  14. void Smtp::SetSmtpServer(const std::string & username, const std::string &password, const std::string & servername, const std::string & port)  
  15. {  
  16.     m_strUserName = username;  
  17.     m_strPassword = password;  
  18.     m_strServerName = servername;  
  19.     m_strPort = port;  
  20. }  
  21.   
  22. void Smtp::SetSendName(const std::string & sendname)  
  23. {  
  24.     std::string strTemp = "";  
  25.     strTemp += "=?";  
  26.     strTemp += m_strCharset;  
  27.     strTemp += "?B?";  
  28.     strTemp += base64_encode((unsigned char *)sendname.c_str(), sendname.size());  
  29.     strTemp += "?=";  
  30.     m_strSendName = strTemp;  
  31. }  
  32.   
  33. void Smtp::SetSendMail(const std::string & sendmail)  
  34. {  
  35.     m_strSendMail = sendmail;  
  36. }  
  37.   
  38. void Smtp::AddRecvMail(const std::string & recvmail)  
  39. {  
  40.     m_vRecvMail.push_back(recvmail);  
  41. }  
  42.   
  43. void Smtp::SetSubject(const std::string & subject)  
  44. {  
  45.     std::string strTemp = "";  
  46.     strTemp = "Subject: ";  
  47.     strTemp += "=?";  
  48.     strTemp += m_strCharset;  
  49.     strTemp += "?B?";  
  50.     strTemp += base64_encode((unsigned char *)subject.c_str(), subject.size());  
  51.     strTemp += "?=";  
  52.     m_strSubject = strTemp;  
  53. }  
  54.   
  55. void Smtp::SetBodyContent(const std::string & content)  
  56. {  
  57.     m_strContent = content;  
  58. }  
  59.   
  60. void Smtp::AddAttachment(const std::string & filename)  
  61. {  
  62.     m_vAttachMent.push_back(filename);  
  63. }  
  64.   
  65. bool Smtp::SendMail()  
  66. {  
  67.     CreatMessage();  
  68.     bool ret = true;  
  69.     CURL *curl;  
  70.     CURLcode res = CURLE_OK;  
  71.     struct curl_slist *recipients = NULL;  
  72.       
  73.     curl = curl_easy_init();  
  74.     if (curl) {  
  75.         /* Set username and password */                                        
  76.         curl_easy_setopt(curl, CURLOPT_USERNAME, m_strUserName.c_str());  
  77.         curl_easy_setopt(curl, CURLOPT_PASSWORD, m_strPassword.c_str());  
  78.         std::string tmp = "smtp://";  
  79.         tmp += m_strServerName;  
  80.         curl_easy_setopt(curl, CURLOPT_URL, tmp);  
  81.         /* If you want to connect to a site who isn't using a certificate that is 
  82.         * signed by one of the certs in the CA bundle you have, you can skip the 
  83.         * verification of the server's certificate. This makes the connection 
  84.         * A LOT LESS SECURE. 
  85.         * 
  86.         * If you have a CA cert for the server stored someplace else than in the 
  87.         * default bundle, then the CURLOPT_CAPATH option might come handy for 
  88.         * you. */  
  89. #ifdef SKIP_PEER_VERIFICATION  
  90.         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);  
  91. #endif  
  92.   
  93.         /* If the site you're connecting to uses a different host name that what 
  94.         * they have mentioned in their server certificate's commonName (or 
  95.         * subjectAltName) fields, libcurl will refuse to connect. You can skip 
  96.         * this check, but this will make the connection less secure. */  
  97. #ifdef SKIP_HOSTNAME_VERIFICATION  
  98.         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);  
  99. #endif  
  100.   
  101.         /* Note that this option isn't strictly required, omitting it will result 
  102.         * in libcurl sending the MAIL FROM command with empty sender data. All 
  103.         * autoresponses should have an empty reverse-path, and should be directed 
  104.         * to the address in the reverse-path which triggered them. Otherwise, 
  105.         * they could cause an endless loop. See RFC 5321 Section 4.5.5 for more 
  106.         * details. 
  107.         */  
  108.         //curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM);   
  109.         curl_easy_setopt(curl, CURLOPT_MAIL_FROM, m_strSendMail.c_str());  
  110.         /* Add two recipients, in this particular case they correspond to the 
  111.         * To: and Cc: addressees in the header, but they could be any kind of 
  112.         * recipient. */  
  113.         for (size_t i = 0; i < m_vRecvMail.size(); i++) {  
  114.   
  115.             recipients = curl_slist_append(recipients, m_vRecvMail[i].c_str());  
  116.         }  
  117.         curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);  
  118.   
  119.         std::stringstream stream;  
  120.         stream.str(m_strMessage);  
  121.         stream.flush();  
  122.         /* We're using a callback function to specify the payload (the headers and 
  123.         * body of the message). You could just use the CURLOPT_READDATA option to 
  124.         * specify a FILE pointer to read from. */  
  125.         curl_easy_setopt(curl, CURLOPT_READFUNCTION, &Smtp::payload_source);  
  126.         curl_easy_setopt(curl, CURLOPT_READDATA, (void *)&stream);  
  127.         curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);  
  128.   
  129.         /* Since the traffic will be encrypted, it is very useful to turn on debug 
  130.         * information within libcurl to see what is happening during the 
  131.         * transfer */  
  132.         curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);  
  133.   
  134.         /* Send the message */  
  135.         res = curl_easy_perform(curl);  
  136.         CURLINFO info = CURLINFO_NONE;  
  137.         curl_easy_getinfo(curl, info);  
  138.         /* Check for errors */  
  139.       
  140.         if (res != CURLE_OK) {  
  141.             
  142.             fprintf(stderr, "curl_easy_perform() failed: %s\n\n",  
  143.                 curl_easy_strerror(res));  
  144.             ret = false;  
  145.         }  
  146.               
  147.         /* Free the list of recipients */  
  148.         curl_slist_free_all(recipients);  
  149.   
  150.         /* Always cleanup */  
  151.         curl_easy_cleanup(curl);  
  152.           
  153.     }  
  154.     return ret;  
  155. }  
  156.   
  157. size_t Smtp::payload_source(void *ptr, size_t size, size_t nmemb, void *stream)  
  158. {  
  159.     size_t num_bytes = size * nmemb;  
  160.     char* data = (char*)ptr;  
  161.     std::stringstream* strstream = (std::stringstream*)stream;  
  162.   
  163.     strstream->read(data, num_bytes);  
  164.   
  165.     return strstream->gcount();  
  166. }  
  167.   
  168. void Smtp::CreatMessage()  
  169. {  
  170.     m_strMessage = "From: ";  
  171.     m_strMessage += m_strSendMail;  
  172.     m_strMessage += "\r\nReply-To: ";  
  173.     m_strMessage += m_strSendMail;  
  174.     m_strMessage += "\r\nTo: ";  
  175.     for (size_t i = 0; i < m_vRecvMail.size(); i++)  
  176.     {  
  177.         if (i > 0) {  
  178.             m_strMessage += ",";  
  179.         }  
  180.         m_strMessage += m_vRecvMail[i];  
  181.     }  
  182.     m_strMessage += "\r\n";  
  183.     m_strMessage += m_strSubject;  
  184.     m_strMessage += "\r\nX-Mailer: The Bat! (v3.02) Professional";  
  185.     m_strMessage += "\r\nMime-Version: 1.0";  
  186.     m_strMessage += "\r\nContent-Type: multipart/mixed;";  
  187.     m_strMessage += "boundary=\"simple boundary\"";  
  188.     m_strMessage += "\r\nThis is a multi-part message in MIME format.";  
  189.     m_strMessage += "\r\n--simple boundary";  
  190.     //正文  
  191.     m_strMessage += "\r\nContent-Type: text/html;";  
  192.     m_strMessage += "charset=";  
  193.     m_strMessage += "\"";  
  194.     m_strMessage += m_strCharset;  
  195.     m_strMessage += "\"";  
  196.     m_strMessage += "\r\nContent-Transfer-Encoding: 7BIT";  
  197.     m_strMessage += "\r\n\r\n";  
  198.     m_strMessage += m_strContent;  
  199.       
  200.     //附件  
  201.     std::string filename = "";  
  202.     std::string filetype = "";  
  203.     for (size_t i = 0; i < m_vAttachMent.size(); i++)  
  204.     {  
  205.         m_strMessage += "\r\n--simple boundary";  
  206.         GetFileName(m_vAttachMent[i], filename);  
  207.         GetFileType(m_vAttachMent[i], filetype);  
  208.         SetContentType(filetype);  
  209.         SetFileName(filename);  
  210.       
  211.         m_strMessage += "\r\nContent-Type: ";  
  212.         m_strMessage += m_strContentType;  
  213.         m_strMessage += "\tname=";  
  214.         m_strMessage += "\"";  
  215.         m_strMessage += m_strFileName;  
  216.         m_strMessage += "\"";  
  217.         m_strMessage += "\r\nContent-Disposition:attachment;filename=";  
  218.         m_strMessage += "\"";  
  219.         m_strMessage += m_strFileName;  
  220.         m_strMessage += "\"";  
  221.         m_strMessage += "\r\nContent-Transfer-Encoding:base64";   
  222.         m_strMessage += "\r\n\r\n";  
  223.   
  224.       
  225.         FILE *pt = NULL;  
  226.         if ((pt = fopen(m_vAttachMent[i].c_str(), "rb")) == NULL) {  
  227.   
  228.             std::cerr << "打开文件失败: " << m_vAttachMent[i] <<std::endl;  
  229.             continue;  
  230.         }  
  231.         fseek(pt, 0, SEEK_END);  
  232.         int len = ftell(pt);  
  233.         fseek(pt, 0, SEEK_SET);  
  234.         int rlen = 0;  
  235.         char buf[55];  
  236.         for (size_t i = 0; i < len / 54 + 1; i++)  
  237.         {  
  238.             memset(buf, 0, 55);  
  239.             rlen = fread(buf, sizeof(char), 54, pt);  
  240.             m_strMessage += base64_encode((const unsigned char*)buf, rlen);  
  241.             m_strMessage += "\r\n";  
  242.         }  
  243.         fclose(pt);  
  244.         pt = NULL;  
  245.           
  246.     }  
  247.     m_strMessage += "\r\n--simple boundary--\r\n";  
  248.       
  249. }  
  250.   
  251.   
  252. int Smtp::getFileType(std::string const & stype)  
  253. {  
  254.     if (stype == "txt")  
  255.     {  
  256.         return 0;  
  257.     }  
  258.     else if (stype == "xml")  
  259.     {  
  260.         return 1;  
  261.     }  
  262.     else if (stype == "html")  
  263.     {  
  264.         return 2;  
  265.     }  
  266.     else if (stype == "jpeg")  
  267.     {  
  268.         return 3;  
  269.     }  
  270.     else if (stype == "png")  
  271.     {  
  272.         return 4;  
  273.     }  
  274.     else if (stype == "gif")  
  275.     {  
  276.         return 5;  
  277.     }  
  278.     else if (stype == "exe")  
  279.     {  
  280.         return 6;  
  281.     }  
  282.       
  283.     return -1;  
  284. }  
  285.   
  286. void Smtp::SetFileName(const std::string & FileName)  
  287. {  
  288.     std::string EncodedFileName = "=?";  
  289.     EncodedFileName += m_strCharset;  
  290.     EncodedFileName += "?B?";//修改  
  291.     EncodedFileName += base64_encode((unsigned char *)FileName.c_str(), FileName.size());  
  292.     EncodedFileName += "?=";  
  293.     m_strFileName = EncodedFileName;  
  294. }  
  295.   
  296. void Smtp::SetContentType(std::string const & stype)  
  297. {  
  298.     int type = getFileType(stype);  
  299.     switch (type)  
  300.     {//  
  301.     case 0:  
  302.         m_strContentType = "plain/text;";  
  303.         break;  
  304.   
  305.     case 1:  
  306.         m_strContentType = "text/xml;";  
  307.         break;  
  308.   
  309.     case 2:  
  310.         m_strContentType = "text/html;";  
  311.   
  312.     case 3:  
  313.         m_strContentType = "image/jpeg;";  
  314.         break;  
  315.   
  316.     case 4:  
  317.         m_strContentType = "image/png;";  
  318.         break;  
  319.   
  320.     case 5:  
  321.         m_strContentType = "image/gif;";  
  322.         break;  
  323.   
  324.     case 6:  
  325.         m_strContentType = "application/x-msdownload;";  
  326.         break;  
  327.   
  328.     default:  
  329.         m_strContentType = "application/octet-stream;";  
  330.         break;  
  331.     }  
  332. }  
  333.   
  334. void Smtp::GetFileName(const std::string& file, std::string& filename)  
  335. {  
  336.       
  337.     std::string::size_type p = file.find_last_of('/');  
  338.     if (p == std::string::npos)  
  339.         p = file.find_last_of('\\');  
  340.     if (p != std::string::npos) {  
  341.         p += 1; // get past folder delimeter  
  342.         filename = file.substr(p, file.length() - p);  
  343.     }  
  344. }  
  345.   
  346. void Smtp::GetFileType(const std::string & file, std::string & stype)  
  347. {  
  348.     std::string::size_type p = file.find_last_of('.');  
  349.     if (p != std::string::npos) {  
  350.         p += 1; // get past folder delimeter  
  351.         stype = file.substr(p, file.length() - p);  
  352.     }  
  353. }  
  1. //64编码  
  1. #include <string>  
  2.   
  3. #ifndef _BASE64_H_  
  4. #define _BASE64_H_  
  5.   
  6. std::string base64_encode(unsigned char const* , unsigned int len);  
  7. std::string base64_decode(std::string const& s);  
  8.   
  9. #endif  
  1. /*  
  2.    base64.cpp and base64.h 
  3.  
  4.    Copyright (C) 2004-2008 Ren?Nyffenegger 
  5.  
  6.    This source code is provided 'as-is', without any express or implied 
  7.    warranty. In no event will the author be held liable for any damages 
  8.    arising from the use of this software. 
  9.  
  10.    Permission is granted to anyone to use this software for any purpose, 
  11.    including commercial applications, and to alter it and redistribute it 
  12.    freely, subject to the following restrictions: 
  13.  
  14.    1. The origin of this source code must not be misrepresented; you must not 
  15.       claim that you wrote the original source code. If you use this source code 
  16.       in a product, an acknowledgment in the product documentation would be 
  17.       appreciated but is not required. 
  18.  
  19.    2. Altered source versions must be plainly marked as such, and must not be 
  20.       misrepresented as being the original source code. 
  21.  
  22.    3. This notice may not be removed or altered from any source distribution. 
  23.  
  24.    Ren?Nyffenegger rene.nyffenegger@adp-gmbh.ch 
  25.  
  26. */  
  27.   
  28. #include "base64.h"  
  29. #include <iostream>  
  30.   
  31. static const std::string base64_chars =   
  32.              "ABCDEFGHIJKLMNOPQRSTUVWXYZ"  
  33.              "abcdefghijklmnopqrstuvwxyz"  
  34.              "0123456789+/";  
  35.   
  36.   
  37. static inline bool is_base64(unsigned char c)   
  38. {  
  39.   return (isalnum(c) || (c == '+') || (c == '/'));  
  40. }  
  41.   
  42. std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len)   
  43. {  
  44.   std::string ret;  
  45.   int i = 0, j = 0;  
  46.   unsigned char char_array_3[3], char_array_4[4];  
  47.   
  48.   while (in_len--)  
  49.     {  
  50.     char_array_3[i++] = *(bytes_to_encode++);  
  51.     if (i == 3)   
  52.         {  
  53.       char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;  
  54.       char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);  
  55.       char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);  
  56.       char_array_4[3] = char_array_3[2] & 0x3f;  
  57.   
  58.       for(i = 0; (i <4) ; i++)  
  59.         ret += base64_chars[char_array_4[i]];  
  60.       i = 0;  
  61.     }  
  62.   }  
  63.   
  64.   if (i)  
  65.   {  
  66.     for(j = i; j < 3; j++)  
  67.       char_array_3[j] = '\0';  
  68.   
  69.     char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;  
  70.     char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);  
  71.     char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);  
  72.     char_array_4[3] = char_array_3[2] & 0x3f;  
  73.   
  74.     for (j = 0; (j < i + 1); j++)  
  75.       ret += base64_chars[char_array_4[j]];  
  76.   
  77.     while((i++ < 3))  
  78.       ret += '=';  
  79.   
  80.   }  
  81.   
  82.   return ret;  
  83.   
  84. }  
  85.   
  86. std::string base64_decode(std::string const& encoded_string)   
  87. {  
  88.   int in_len = encoded_string.size();  
  89.   int i = 0, j = 0, in_ = 0;  
  90.   unsigned char char_array_4[4], char_array_3[3];  
  91.   std::string ret;  
  92.   
  93.   while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_]))   
  94.     {  
  95.     char_array_4[i++] = encoded_string[in_]; in_++;  
  96.     if (i ==4) {  
  97.       for (i = 0; i <4; i++)  
  98.         char_array_4[i] = base64_chars.find(char_array_4[i]);  
  99.   
  100.       char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);  
  101.       char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);  
  102.       char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];  
  103.   
  104.       for (i = 0; (i < 3); i++)  
  105.         ret += char_array_3[i];  
  106.       i = 0;  
  107.     }  
  108.   }  
  109.   
  110.   if (i)   
  111.     {  
  112.     for (j = i; j <4; j++)  
  113.       char_array_4[j] = 0;  
  114.   
  115.     for (j = 0; j <4; j++)  
  116.       char_array_4[j] = base64_chars.find(char_array_4[j]);  
  117.   
  118.     char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);  
  119.     char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);  
  120.     char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];  
  121.   
  122.     for (j = 0; (j < i - 1); j++)   
  123.             ret += char_array_3[j];  
  124.   }  
  125.   
  126.   return ret;  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值