http://blog.csdn.net/abqchina/article/details/53405269
1、运行环境vs2015
2、libcurl版本:curl-7.51.0
3、拼接MIME协议
4、附上代码
- //smtp.h
- #pragma once
- #include <string>
- #include <vector>
- #define SKIP_PEER_VERIFICATION
- #define SKIP_HOSTNAME_VERIFICATION
- class Smtp {
- public:
- //构造smtp对象设置邮件编码
- nst std::string& charset="utf-8");//
- //设置stmp服务器、用户名、密码、端口(端口其实不用指定,libcurl默认25,但如果是smtps则默认是465)
- void SetSmtpServer(const std::string &username, const std::string& password, const std::string& servername, const std::string &port="25");
- //发送者姓名,可以不用
- void SetSendName(const std::string& sendname);
- //发送者邮箱
- tSendMail(const std::string& sendmail);
- //添加收件人
- ddRecvMail(const std::string& recvmail);
- //设置主题
- etSubject(const std::string &subject);
- //设置正文内容
- etBodyContent(const std::string &content);
- //添加附件
- dAttachment(const std::string &filename);
- //发送邮件
- bool SendMail();
- private:
- //回调函数,将MIME协议的拼接的字符串由libcurl发出
- size_t payload_source(void *ptr, size_t size, size_t nmemb, void *stream);
- //创建邮件MIME内容
- reatMessage();
- //获取文件类型
- tFileType(std::string const& stype);
- //设置文件名
- etFileName(const std::string& FileName);
- //设置文件的contenttype
- etContentType(std::string const& stype);
- //得到文件名
- etFileName(const std::string& file, std::string& filename);
- //得到文件类型
- void GetFileType(const std::string& file, std::string& stype);
- private:
- std::string m_strCharset; //邮件编码
- std::string m_strSubject; //邮件主题
- std::string m_strContent; //邮件内容
- std::string m_strFileName; //文件名
- std::string m_strMessage;// 整个MIME协议字符串
- std::string m_strUserName;//用户名
- std::string m_strPassword;//密码
- std::string m_strServerName;//smtp服务器
- std::string m_strPort;//端口
- std::string m_strSendName;//发送者姓名
- std::string m_strSendMail;//发送者邮箱
- std::string m_strContentType;//附件contenttype
- std::string m_strFileContent;//附件内容
- std::vector<std::string> m_vRecvMail; //收件人容器
- std::vector<std::string> m_vAttachMent;//附件容器
- };
- #include "smtp.h"
- #include "base64.h"
- #include <curl/curl.h>
- #include <iostream>
- #include <sstream>
- #include <fstream>
- Smtp::Smtp(const std::string & charset)
- {
- m_strCharset = charset;
- m_vRecvMail.clear();
- }
- void Smtp::SetSmtpServer(const std::string & username, const std::string &password, const std::string & servername, const std::string & port)
- {
- m_strUserName = username;
- m_strPassword = password;
- m_strServerName = servername;
- m_strPort = port;
- }
- void Smtp::SetSendName(const std::string & sendname)
- {
- std::string strTemp = "";
- strTemp += "=?";
- strTemp += m_strCharset;
- strTemp += "?B?";
- strTemp += base64_encode((unsigned char *)sendname.c_str(), sendname.size());
- strTemp += "?=";
- m_strSendName = strTemp;
- }
- void Smtp::SetSendMail(const std::string & sendmail)
- {
- m_strSendMail = sendmail;
- }
- void Smtp::AddRecvMail(const std::string & recvmail)
- {
- m_vRecvMail.push_back(recvmail);
- }
- void Smtp::SetSubject(const std::string & subject)
- {
- std::string strTemp = "";
- strTemp = "Subject: ";
- strTemp += "=?";
- strTemp += m_strCharset;
- strTemp += "?B?";
- strTemp += base64_encode((unsigned char *)subject.c_str(), subject.size());
- strTemp += "?=";
- m_strSubject = strTemp;
- }
- void Smtp::SetBodyContent(const std::string & content)
- {
- m_strContent = content;
- }
- void Smtp::AddAttachment(const std::string & filename)
- {
- m_vAttachMent.push_back(filename);
- }
- bool Smtp::SendMail()
- {
- CreatMessage();
- bool ret = true;
- CURL *curl;
- CURLcode res = CURLE_OK;
- struct curl_slist *recipients = NULL;
- curl = curl_easy_init();
- if (curl) {
- /* Set username and password */
- curl_easy_setopt(curl, CURLOPT_USERNAME, m_strUserName.c_str());
- curl_easy_setopt(curl, CURLOPT_PASSWORD, m_strPassword.c_str());
- std::string tmp = "smtp://";
- tmp += m_strServerName;
- curl_easy_setopt(curl, CURLOPT_URL, tmp);
- /* If you want to connect to a site who isn't using a certificate that is
- * signed by one of the certs in the CA bundle you have, you can skip the
- * verification of the server's certificate. This makes the connection
- * A LOT LESS SECURE.
- *
- * If you have a CA cert for the server stored someplace else than in the
- * default bundle, then the CURLOPT_CAPATH option might come handy for
- * you. */
- #ifdef SKIP_PEER_VERIFICATION
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
- #endif
- /* If the site you're connecting to uses a different host name that what
- * they have mentioned in their server certificate's commonName (or
- * subjectAltName) fields, libcurl will refuse to connect. You can skip
- * this check, but this will make the connection less secure. */
- #ifdef SKIP_HOSTNAME_VERIFICATION
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
- #endif
- /* Note that this option isn't strictly required, omitting it will result
- * in libcurl sending the MAIL FROM command with empty sender data. All
- * autoresponses should have an empty reverse-path, and should be directed
- * to the address in the reverse-path which triggered them. Otherwise,
- * they could cause an endless loop. See RFC 5321 Section 4.5.5 for more
- * details.
- */
- //curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM);
- curl_easy_setopt(curl, CURLOPT_MAIL_FROM, m_strSendMail.c_str());
- /* Add two recipients, in this particular case they correspond to the
- * To: and Cc: addressees in the header, but they could be any kind of
- * recipient. */
- for (size_t i = 0; i < m_vRecvMail.size(); i++) {
- recipients = curl_slist_append(recipients, m_vRecvMail[i].c_str());
- }
- curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
- std::stringstream stream;
- stream.str(m_strMessage);
- stream.flush();
- /* We're using a callback function to specify the payload (the headers and
- * body of the message). You could just use the CURLOPT_READDATA option to
- * specify a FILE pointer to read from. */
- curl_easy_setopt(curl, CURLOPT_READFUNCTION, &Smtp::payload_source);
- curl_easy_setopt(curl, CURLOPT_READDATA, (void *)&stream);
- curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
- /* Since the traffic will be encrypted, it is very useful to turn on debug
- * information within libcurl to see what is happening during the
- * transfer */
- curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
- /* Send the message */
- res = curl_easy_perform(curl);
- CURLINFO info = CURLINFO_NONE;
- curl_easy_getinfo(curl, info);
- /* Check for errors */
- if (res != CURLE_OK) {
- fprintf(stderr, "curl_easy_perform() failed: %s\n\n",
- curl_easy_strerror(res));
- ret = false;
- }
- /* Free the list of recipients */
- curl_slist_free_all(recipients);
- /* Always cleanup */
- curl_easy_cleanup(curl);
- }
- return ret;
- }
- size_t Smtp::payload_source(void *ptr, size_t size, size_t nmemb, void *stream)
- {
- size_t num_bytes = size * nmemb;
- char* data = (char*)ptr;
- std::stringstream* strstream = (std::stringstream*)stream;
- strstream->read(data, num_bytes);
- return strstream->gcount();
- }
- void Smtp::CreatMessage()
- {
- m_strMessage = "From: ";
- m_strMessage += m_strSendMail;
- m_strMessage += "\r\nReply-To: ";
- m_strMessage += m_strSendMail;
- m_strMessage += "\r\nTo: ";
- for (size_t i = 0; i < m_vRecvMail.size(); i++)
- {
- if (i > 0) {
- m_strMessage += ",";
- }
- m_strMessage += m_vRecvMail[i];
- }
- m_strMessage += "\r\n";
- m_strMessage += m_strSubject;
- m_strMessage += "\r\nX-Mailer: The Bat! (v3.02) Professional";
- m_strMessage += "\r\nMime-Version: 1.0";
- m_strMessage += "\r\nContent-Type: multipart/mixed;";
- m_strMessage += "boundary=\"simple boundary\"";
- m_strMessage += "\r\nThis is a multi-part message in MIME format.";
- m_strMessage += "\r\n--simple boundary";
- //正文
- m_strMessage += "\r\nContent-Type: text/html;";
- m_strMessage += "charset=";
- m_strMessage += "\"";
- m_strMessage += m_strCharset;
- m_strMessage += "\"";
- m_strMessage += "\r\nContent-Transfer-Encoding: 7BIT";
- m_strMessage += "\r\n\r\n";
- m_strMessage += m_strContent;
- //附件
- std::string filename = "";
- std::string filetype = "";
- for (size_t i = 0; i < m_vAttachMent.size(); i++)
- {
- m_strMessage += "\r\n--simple boundary";
- GetFileName(m_vAttachMent[i], filename);
- GetFileType(m_vAttachMent[i], filetype);
- SetContentType(filetype);
- SetFileName(filename);
- m_strMessage += "\r\nContent-Type: ";
- m_strMessage += m_strContentType;
- m_strMessage += "\tname=";
- m_strMessage += "\"";
- m_strMessage += m_strFileName;
- m_strMessage += "\"";
- m_strMessage += "\r\nContent-Disposition:attachment;filename=";
- m_strMessage += "\"";
- m_strMessage += m_strFileName;
- m_strMessage += "\"";
- m_strMessage += "\r\nContent-Transfer-Encoding:base64";
- m_strMessage += "\r\n\r\n";
- FILE *pt = NULL;
- if ((pt = fopen(m_vAttachMent[i].c_str(), "rb")) == NULL) {
- std::cerr << "打开文件失败: " << m_vAttachMent[i] <<std::endl;
- continue;
- }
- fseek(pt, 0, SEEK_END);
- int len = ftell(pt);
- fseek(pt, 0, SEEK_SET);
- int rlen = 0;
- char buf[55];
- for (size_t i = 0; i < len / 54 + 1; i++)
- {
- memset(buf, 0, 55);
- rlen = fread(buf, sizeof(char), 54, pt);
- m_strMessage += base64_encode((const unsigned char*)buf, rlen);
- m_strMessage += "\r\n";
- }
- fclose(pt);
- pt = NULL;
- }
- m_strMessage += "\r\n--simple boundary--\r\n";
- }
- int Smtp::getFileType(std::string const & stype)
- {
- if (stype == "txt")
- {
- return 0;
- }
- else if (stype == "xml")
- {
- return 1;
- }
- else if (stype == "html")
- {
- return 2;
- }
- else if (stype == "jpeg")
- {
- return 3;
- }
- else if (stype == "png")
- {
- return 4;
- }
- else if (stype == "gif")
- {
- return 5;
- }
- else if (stype == "exe")
- {
- return 6;
- }
- return -1;
- }
- void Smtp::SetFileName(const std::string & FileName)
- {
- std::string EncodedFileName = "=?";
- EncodedFileName += m_strCharset;
- EncodedFileName += "?B?";//修改
- EncodedFileName += base64_encode((unsigned char *)FileName.c_str(), FileName.size());
- EncodedFileName += "?=";
- m_strFileName = EncodedFileName;
- }
- void Smtp::SetContentType(std::string const & stype)
- {
- int type = getFileType(stype);
- switch (type)
- {//
- case 0:
- m_strContentType = "plain/text;";
- break;
- case 1:
- m_strContentType = "text/xml;";
- break;
- case 2:
- m_strContentType = "text/html;";
- case 3:
- m_strContentType = "image/jpeg;";
- break;
- case 4:
- m_strContentType = "image/png;";
- break;
- case 5:
- m_strContentType = "image/gif;";
- break;
- case 6:
- m_strContentType = "application/x-msdownload;";
- break;
- default:
- m_strContentType = "application/octet-stream;";
- break;
- }
- }
- void Smtp::GetFileName(const std::string& file, std::string& filename)
- {
- std::string::size_type p = file.find_last_of('/');
- if (p == std::string::npos)
- p = file.find_last_of('\\');
- if (p != std::string::npos) {
- p += 1; // get past folder delimeter
- filename = file.substr(p, file.length() - p);
- }
- }
- void Smtp::GetFileType(const std::string & file, std::string & stype)
- {
- std::string::size_type p = file.find_last_of('.');
- if (p != std::string::npos) {
- p += 1; // get past folder delimeter
- stype = file.substr(p, file.length() - p);
- }
- }
- //64编码
- #include <string>
- #ifndef _BASE64_H_
- #define _BASE64_H_
- std::string base64_encode(unsigned char const* , unsigned int len);
- std::string base64_decode(std::string const& s);
- #endif
- /*
- base64.cpp and base64.h
- Copyright (C) 2004-2008 Ren?Nyffenegger
- This source code is provided 'as-is', without any express or implied
- warranty. In no event will the author be held liable for any damages
- arising from the use of this software.
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
- 1. The origin of this source code must not be misrepresented; you must not
- claim that you wrote the original source code. If you use this source code
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original source code.
- 3. This notice may not be removed or altered from any source distribution.
- Ren?Nyffenegger rene.nyffenegger@adp-gmbh.ch
- */
- #include "base64.h"
- #include <iostream>
- static const std::string base64_chars =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789+/";
- static inline bool is_base64(unsigned char c)
- {
- return (isalnum(c) || (c == '+') || (c == '/'));
- }
- std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len)
- {
- std::string ret;
- int i = 0, j = 0;
- unsigned char char_array_3[3], char_array_4[4];
- while (in_len--)
- {
- char_array_3[i++] = *(bytes_to_encode++);
- if (i == 3)
- {
- char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
- char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
- char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
- char_array_4[3] = char_array_3[2] & 0x3f;
- for(i = 0; (i <4) ; i++)
- ret += base64_chars[char_array_4[i]];
- i = 0;
- }
- }
- if (i)
- {
- for(j = i; j < 3; j++)
- char_array_3[j] = '\0';
- char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
- char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
- char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
- char_array_4[3] = char_array_3[2] & 0x3f;
- for (j = 0; (j < i + 1); j++)
- ret += base64_chars[char_array_4[j]];
- while((i++ < 3))
- ret += '=';
- }
- return ret;
- }
- std::string base64_decode(std::string const& encoded_string)
- {
- int in_len = encoded_string.size();
- int i = 0, j = 0, in_ = 0;
- unsigned char char_array_4[4], char_array_3[3];
- std::string ret;
- while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_]))
- {
- char_array_4[i++] = encoded_string[in_]; in_++;
- if (i ==4) {
- for (i = 0; i <4; i++)
- char_array_4[i] = base64_chars.find(char_array_4[i]);
- char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
- char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
- char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
- for (i = 0; (i < 3); i++)
- ret += char_array_3[i];
- i = 0;
- }
- }
- if (i)
- {
- for (j = i; j <4; j++)
- char_array_4[j] = 0;
- for (j = 0; j <4; j++)
- char_array_4[j] = base64_chars.find(char_array_4[j]);
- char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
- char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
- char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
- for (j = 0; (j < i - 1); j++)
- ret += char_array_3[j];
- }
- return ret;
- }