由于業(yè)務(wù)上存在發(fā)送報(bào)警郵件的需求,一直想找一個(gè)簡(jiǎn)單易用的發(fā)送Email的C++庫(kù)。
終于找到了,它就是jwSTMP(http://sourceforge.net/projects/jwsmtp/)。
最新的jwSTMP版本(1.32.15)能夠跨平臺(tái)(BSD、Linux和Windows等)的支持以C++代碼或者C++庫(kù)的形式編碼發(fā)送Email。它可以發(fā)送附件、支持多個(gè)收件人(最多100個(gè)),支持CC(抄送)和BCC(隱藏性抄送);同樣的,它也支持以HTML的方式發(fā)送郵件。
我們知道發(fā)送Email有POP3和SMTP兩種方式。目前jwSTMP不支持POP3的方式。但是它提供了MX lookup方式,即直接得到目的地址的郵件交換服務(wù)器地址(MX)將郵件發(fā)送出去。
現(xiàn)在說(shuō)說(shuō)如何使用吧。
下載和編譯。請(qǐng)到sourceforge上將它下載下來(lái)。如果使用Windows平臺(tái),直接點(diǎn)擊工程文件即可(缺省是VC6的工程文件,我使用VS2008將工程文件轉(zhuǎn)化也是可以的)然后編譯即可;如果使用Linux,請(qǐng)執(zhí)行通行的三部曲:
./configure
make
make install
代碼修改。適合中國(guó)人的習(xí)慣,我將使用163的郵箱服務(wù)展示jwSMTP的用法。
最簡(jiǎn)單的demo1.cpp文件如下:
[cpp]
view plaincopy#include <iostream>
// 由于頭文件所處的位置是jwsmtp-1.32.15\jwsmtp\jwsmtp,所以,需要注意include的路徑
#include "jwsmtp/jwsmtp.h"
int main(int argc, char* argv[])
{
jwsmtp::mailer m("testjwstmp@163.com"/*接收者*/, "testjwstmp@163.com"/*發(fā)送者*/, "這里填寫(xiě)郵件標(biāo)題",
"這里填寫(xiě)郵件內(nèi)容", "smtp.163.com",
jwsmtp::mailer::SMTP_PORT, false);
//經(jīng)過(guò)測(cè)試,163支持的auth認(rèn)證是PLAIN模式
m.authtype(jwsmtp::mailer::PLAIN);
//這里輸入認(rèn)證用戶(hù)名,注意哦,需要是***@163.com的用戶(hù)名
m.username("testjwstmp@163.com");
//這里輸入密碼
m.password("******");
m.send(); // 這里發(fā)送郵件,需要注意的是,這里是同步模式哦!
std ::cout << m.response() << std::endl;//這里返回是否成功,250代表發(fā)送郵件成功;
system("pause");
return 0;
}
需要注意的是,雖然我在測(cè)試時(shí)發(fā)送在cpp文件中寫(xiě)入中文使用163.com發(fā)送是沒(méi)有出現(xiàn)亂碼的,但是,在公司中發(fā)送報(bào)警郵件則會(huì)出現(xiàn)亂碼。為了解決亂碼問(wèn)題,需要使用網(wǎng)絡(luò)上有人提供的string s2utfs(const string& strSrc)函數(shù)進(jìn)行轉(zhuǎn)碼為utf8。
[cpp]
view plaincopy#ifndef __CHARSET_CVT__
#define __CHARSET_CVT__
#include <string>
#include <clocale>
std::string ws2s(const std::wstring& ws)
{
std::string curLocale = setlocale(LC_ALL, NULL); // curLocale = "C";
setlocale(LC_ALL, "chs");
const wchar_t* _Source = ws.c_str();
size_t _Dsize = 2 * ws.size() + 1;
char *_Dest = new char[_Dsize];
memset(_Dest, 0, _Dsize);
wcstombs(_Dest, _Source, _Dsize);
std::string result = _Dest;
delete [] _Dest;
setlocale(LC_ALL, curLocale.c_str());
return result;
}
std::wstring s2ws(const std::string& s)
{
setlocale(LC_ALL, "chs");
const char* _Source = s.c_str();
size_t _Dsize = s.size() + 1;
wchar_t* _Dest = new wchar_t[_Dsize];
wmemset(_Dest, 0, _Dsize);
int nret = mbstowcs(_Dest, _Source, _Dsize);
std::wstring result = _Dest;
delete [] _Dest;
setlocale(LC_ALL, "C");
return result;
}
std::wstring UTF2Uni(const char* src, std::wstring &t)
{
if (src == NULL)
{
return L"";
}
int size_s = strlen(src);
int size_d = size_s + 10;
wchar_t *des = new wchar_t[size_d];
memset(des, 0, size_d * sizeof(wchar_t));
int s = 0, d = 0;
bool toomuchbyte = true; //set true to skip error prefix.
while (s < size_s && d < size_d)
{
unsigned char c = src[s];
if ((c & 0x80) == 0)
{
des[d++] += src[s++];
}
else if((c & 0xE0) == 0xC0) /// < 110x-xxxx 10xx-xxxx
{
WCHAR &wideChar = des[d++];
wideChar = (src[s + 0] & 0x3F)<<6;
wideChar |= (src[s + 1] & 0x3F);
s += 2;
}
else if((c & 0xF0) == 0xE0) /// < 1110-xxxx 10xx-xxxx 10xx-xxxx
{
WCHAR &wideChar = des[d++];
wideChar = (src[s + 0] & 0x1F)<<12;
wideChar |= (src[s + 1] & 0x3F)<<6;
wideChar |= (src[s + 2] & 0x3F);
s += 3;
}
else if((c & 0xF8) == 0xF0) /// < 1111-0xxx 10xx-xxxx 10xx-xxxx 10xx-xxxx
{
WCHAR &wideChar = des[d++];
wideChar = (src[s + 0] & 0x0F)<<18;
wideChar = (src[s + 1] & 0x3F)<<12;
wideChar |= (src[s + 2] & 0x3F)<<6;
wideChar |= (src[s + 3] & 0x3F);
s += 4;
}
else
{
WCHAR &wideChar = des[d++]; /// < 1111-10xx 10xx-xxxx 10xx-xxxx 10xx-xxxx 10xx-xxxx
wideChar = (src[s + 0] & 0x07)<<24;
wideChar = (src[s + 1] & 0x3F)<<18;
wideChar = (src[s + 2] & 0x3F)<<12;
wideChar |= (src[s + 3] & 0x3F)<<6;
wideChar |= (src[s + 4] & 0x3F);
s += 5;
}
}
t = des;
delete[] des;
des = NULL;
return t;
}
int Uni2UTF(const std::wstring& strRes, char *utf8, int nMaxSize)
{
if (utf8 == NULL)
{
return -1;
}
int len = 0;
int size_d = nMaxSize;
for (std::wstring::const_iterator it = strRes.begin(); it != strRes.end(); ++it)
{
wchar_t wchar = *it;
if (wchar < 0x80)
{
//length = 1;
utf8[len++] = (char)wchar;
}
else if(wchar < 0x800)
{
//length = 2;
if (len + 1 >= size_d)
{
return -1;
}
utf8[len++] = 0xc0 | ( wchar >> 6 );
utf8[len++] = 0x80 | ( wchar & 0x3f );
}
else if(wchar < 0x10000)
{
//length = 3;
if (len + 2 >= size_d)
{
return -1;
}
utf8[len++] = 0xe0 | ( wchar >> 12 );
utf8[len++] = 0x80 | ( (wchar >> 6) & 0x3f );
utf8[len++] = 0x80 | ( wchar & 0x3f );
}
else if( wchar < 0x200000)
{
//length = 4;
if (len + 3 >= size_d)
{
return -1;
}
utf8[len++] = 0xf0 | ( (int)wchar >> 18 );
utf8[len++] = 0x80 | ( (wchar >> 12) & 0x3f );
utf8[len++] = 0x80 | ( (wchar >> 6) & 0x3f );
utf8[len++] = 0x80 | ( wchar & 0x3f );
}
}
return len;
}
std::string s2utfs(const std::string& strSrc)
{
std::string strRes;
std::wstring wstrUni = s2ws(strSrc);
char* chUTF8 = new char[wstrUni.length() * 3];
memset(chUTF8, 0x00, wstrUni.length() * 3);
Uni2UTF(wstrUni, chUTF8, wstrUni.length() * 3);
strRes = chUTF8;
delete [] chUTF8;
return strRes;
}
std::string utfs2s(const std::string& strutf)
{
std::wstring wStrTmp;
UTF2Uni(strutf.c_str(), wStrTmp);
return ws2s(wStrTmp);
}
#endif
給多人發(fā)送HTML的demo2.cpp文件如下
[cpp]
view plaincopy#include <iostream>
// 由于頭文件所處的位置是jwsmtp-1.32.15\jwsmtp\jwsmtp,所以,需要注意include的路徑
#include "jwsmtp/jwsmtp.h"
std::string html("<html>"
"<body>"
"This is the html part of the message<br><br>"
"<b>bold</b><br>"
"<i>italic</i><br>"
"<font size=\"7\">Large Text</font><br><br>"
"Or a link: <a href=\"http://johnwiggins.net\">johnwiggins.net</a><br><br>"
"And an image: <br><img alt=\"an image in email\" src=\"http://johnwiggins.net/jwsmtp/example.png\"><br>"
"</body>"
"</html>");
int main(int argc, char* argv[])
{
jwsmtp::mailer m(""/*接收者不填寫(xiě)*/, "testjwstmp@163.com"/*發(fā)送者*/, "這里填寫(xiě)郵件標(biāo)題",
"這里填寫(xiě)郵件內(nèi)容", "smtp.163.com",
jwsmtp::mailer::SMTP_PORT, false);
//添加多個(gè)接收者
m.addrecipient("testjwstmp@163.com");
m.addrecipient("testjwstmp@gmail.com");
m.addrecipient("testjwstmp@qq.com");
//添加HTML的發(fā)送內(nèi)容,它會(huì)替換構(gòu)造函數(shù)中的“這里填寫(xiě)郵件內(nèi)容”
m.setmessageHTML(html);
//經(jīng)過(guò)測(cè)試,163支持的auth認(rèn)證是PLAIN模式
m.authtype(jwsmtp::mailer::PLAIN);
//這里輸入認(rèn)證用戶(hù)名,注意哦,需要是***@163.com的用戶(hù)名
m.username("testjwstmp@163.com");
//這里輸入密碼
m.password("******");
m.send(); // 這里發(fā)送郵件,需要注意的是,這里是同步模式哦!
std ::cout << m.response() << std::endl;//這里如果展示的是250,代表發(fā)送郵件成功
system("pause");
return 0;
}
附上發(fā)送Email的返回碼
郵件服務(wù)返回代碼含義
500 格式錯(cuò)誤,命令不可識(shí)別(此錯(cuò)誤也包括命令行過(guò)長(zhǎng))
501 參數(shù)格式錯(cuò)誤
502 命令不可實(shí)現(xiàn)
503 錯(cuò)誤的命令序列
504 命令參數(shù)不可實(shí)現(xiàn)
211 系統(tǒng)狀態(tài)或系統(tǒng)幫助響應(yīng)
214 幫助信息
220 服務(wù)就緒
221 服務(wù)關(guān)閉傳輸信道
421 服務(wù)未就緒,關(guān)閉傳輸信道(當(dāng)必須關(guān)閉時(shí),此應(yīng)答可以作為對(duì)任何命令的響應(yīng))
250 要求的郵件操作完成
251 用戶(hù)非本地,將轉(zhuǎn)發(fā)向
450 要求的郵件操作未完成,郵箱不可用(例如,郵箱忙)
550 要求的郵件操作未完成,郵箱不可用(例如,郵箱未找到,或不可訪問(wèn))
451 放棄要求的操作;處理過(guò)程中出錯(cuò)
551 用戶(hù)非本地,請(qǐng)嘗試
452 系統(tǒng)存儲(chǔ)不足,要求的操作未執(zhí)行
552 過(guò)量的存儲(chǔ)分配,要求的操作未執(zhí)行
553 郵箱名不可用,要求的操作未執(zhí)行(例如郵箱格式錯(cuò)誤)
354 開(kāi)始郵件輸入,以.結(jié)束
554 操作失敗
535 用戶(hù)驗(yàn)證失敗
235 用戶(hù)驗(yàn)證成功
334 等待用戶(hù)輸入驗(yàn)證信