以下是使用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] = ' ';
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
",
curl_easy_strerror(res));
char
achTip[512] = { 0 };
sprintf(achTip, "curl_easy_perform() failed: %s
", 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
+=
"
Reply-To: ";
m_strMessage
+=
m_strSendMail;
m_strMessage
+=
"
To: ";
for (size_t
i = 0; i < m_vRecvMail.size(); i++)
{
if (i > 0) {
m_strMessage
+=
",";
}
m_strMessage
+=
m_vRecvMail[i];
}
m_strMessage
+=
"
";
m_strMessage
+=
m_strSubject;
m_strMessage
+=
"
X-Mailer: The Bat! (v3.02) Professional";
m_strMessage
+=
"
Mime-Version: 1.0";
m_strMessage
+=
"
Content-Type: multipart/mixed;";
m_strMessage
+=
"boundary="simple boundary"";
m_strMessage
+=
"
This is a multi-part message in MIME format.";
m_strMessage
+=
"
--simple boundary";
//正文
m_strMessage
+=
"
Content-Type: text/html;";
m_strMessage
+=
"charset=";
m_strMessage
+=
""";
m_strMessage
+=
m_strCharset;
m_strMessage
+=
""";
m_strMessage
+=
"
Content-Transfer-Encoding: 7BIT";
m_strMessage
+=
"
";
m_strMessage
+=
m_strContent;
//附件
std::string
filename = "";
std::string
filetype = "";
for (size_t
i = 0; i < m_vAttachMent.size(); i++)
{
m_strMessage
+=
"
--simple boundary";
GetFileName(m_vAttachMent[i], filename);
GetFileType(m_vAttachMent[i], filetype);
SetContentType(filetype);
SetFileName(filename);
m_strMessage
+=
"
Content-Type: ";
m_strMessage
+=
m_strContentType;
m_strMessage
+=
" name=";
m_strMessage
+=
""";
m_strMessage
+=
m_strFileName;
m_strMessage
+=
""";
m_strMessage
+=
"
Content-Disposition:attachment;filename=";
m_strMessage
+=
""";
m_strMessage
+=
m_strFileName;
m_strMessage
+=
""";
m_strMessage
+=
"
Content-Transfer-Encoding:base64";
m_strMessage
+=
"
";
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
+=
"
";
}
fclose(pt);
pt = NULL;
}
m_strMessage
+=
"
--simple boundary--
";
}
//获取文件类型
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;
}