以下是使用curl 7.55发送smtp邮件的封装类:
smtp.hpp
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(unsigned char c)
{
return (isalnum(c) || (c == '+') || (c == '/'));
}
inline 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;
}
inline 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;
}
#define SKIP_PEER_VERIFICATION
#define SKIP_HOSTNAME_VERIFICATION
class CSmtpSendMail
{
public:
CSmtpSendMail(const std::string & charset = "gb2312") // 也可以传入utf,gb2312
{
m_strCharset = charset;
m_vRecvMail.clear();
}
//设置stmp服务器、用户名、密码、端口(端口其实不用指定,libcurl默认25,但如果是smtps则默认是465)
inline void SetSmtpServer(const std::string &username, const std::string& password, const std::string& servername, const std::string &port = "25")
{
m_strUserName = username;
m_strPassword = password;
m_strServerName = servername;
m_strPort = port;
}
//发送者姓名,可以不用
inline void 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;
}
inline void SetSendMail(const std::string& sendmail)
{
m_strSendMail = sendmail;
}
inline void AddRecvMail(const std::string& recvmail)
{
m_vRecvMail.push_back(recvmail);
}
inline void 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;
}
inline void SetBodyContent(const std::string &content)
{
m_strContent = content;
}
inline void AddAttachment(const std::string &filename)
{
m_vAttachMent.push_back(filename);
}
inline bool SendMail()
{
CreatMessage();
bool ret = true;
CURL *curl;
CURLcode res = CURLE_OK;
struct curl_slist *recipients = NULL;
curl = curl_easy_init();
if (curl)
{
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.c_str());
#ifdef SKIP_PEER_VERIFICATION
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
#endif
#ifdef SKIP_HOSTNAME_VERIFICATION
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
#endif
printf("m_strSendMail = %s", m_strSendMail.c_str());
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, m_strSendMail.c_str());
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.c_str());
stream.flush();
// 注意回调函数必须设置为static
curl_easy_setopt(curl, CURLOPT_READFUNCTION, &CSmtpSendMail::payload_source);
curl_easy_setopt(curl, CURLOPT_READDATA, (void *)&stream);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
int nTimes = 0;
/* Send the message */
res = curl_easy_perform(curl);
CURLINFO info = CURLINFO_NONE;
curl_easy_getinfo(curl, info, NULL);
/* Check for errors */
while (res != CURLE_OK)
{
nTimes++;
if (nTimes > 5)
{
break;
}
fprintf(stderr, "curl_easy_perform() failed: %s\n\n",
curl_easy_strerror(res));
char achTip[512] = { 0 };
sprintf(achTip, "curl_easy_perform() failed: %s\n\n", curl_easy_strerror(res));
ret = false;
}
curl_slist_free_all(recipients);
curl_easy_cleanup(curl);
}
return ret;
}
private:
//回调函数,将MIME协议拼接的字符串由libcurl发出
static inline size_t 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();
}
//创建邮件MIME内容
inline void 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";
}
//获取文件类型
inline int 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;
}
//设置文件名
inline void 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;
}
//设置文件的contenttype
inline void 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;
}
}
//得到文件名
inline void 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);
}
}
//得到文件类型
inline void 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);
}
}
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;//附件容器
};
inline bool SendEmail(string sUser, string sPwd, string sSvrAddr, string sFrom, string sTo, string sSub, string sContent)
{
CSmtpSendMail sendMail;
sendMail.SetSmtpServer(sUser, sPwd, sSvrAddr);
sendMail.SetSendMail(sFrom);
vector<string> vtRecv = split(sTo, ",");
for (int i = 0; i < vtRecv.size(); i++)
{
sendMail.AddRecvMail(vtRecv[i]);
}
sendMail.SetSubject(sSub);
sendMail.SetBodyContent(sContent);
return sendMail.SendMail();
}
inline bool SendSMS()
{
return 0;
}