基于jwSMTP的C++发送Email的Demo

时间:2022-10-23 15:42:41

由于业务上存在发送报警邮件的需求,一直想找一个简单易用的发送Email的C++库。


终于找到了,它就是jwSTMP(http://sourceforge.net/projects/jwsmtp/)。


最新的jwSTMP版本(1.32.15)能够跨平台(BSD、Linux和Windows等)的支持以C++代码或者C++库的形式编码发送Email。它可以发送附件、支持多个收件人(最多100个),支持CC(抄送)和BCC(隐藏性抄送);同样的,它也支持以HTML的方式发送邮件。


我们知道发送Email有POP3和SMTP两种方式。目前jwSTMP不支持POP3的方式。但是它提供了MX lookup方式,即直接得到目的地址的邮件交换服务器地址(MX)将邮件发送出去。


现在说说如何使用吧。


下载和编译。请到sourceforge上将它下载下来。如果使用Windows平台,直接点击工程文件即可(缺省是VC6的工程文件,我使用VS2008将工程文件转化也是可以的)然后编译即可;如果使用Linux,请执行通行的三部曲:

./configure
make
make install


代码修改。适合中国人的习惯,我将使用163的邮箱服务展示jwSMTP的用法。

最简单的demo1.cpp文件如下:

[cpp] view plaincopy
  1. #include <iostream>  
  2. // 由于头文件所处的位置是jwsmtp-1.32.15\jwsmtp\jwsmtp,所以,需要注意include的路径  
  3. #include "jwsmtp/jwsmtp.h"  
  4.   
  5. int main(int argc, char* argv[])  
  6. {  
  7.    jwsmtp::mailer m("testjwstmp@163.com"/*接收者*/"testjwstmp@163.com"/*发送者*/"这里填写邮件标题",  
  8.                     "这里填写邮件内容""smtp.163.com",  
  9.                     jwsmtp::mailer::SMTP_PORT, false);  
  10.   
  11.    //经过测试,163支持的auth认证是PLAIN模式  
  12.    m.authtype(jwsmtp::mailer::PLAIN);  
  13.   
  14.    //这里输入认证用户名,注意哦,需要是***@163.com的用户名  
  15.    m.username("testjwstmp@163.com");  
  16.    //这里输入密码  
  17.    m.password("******");  
  18.    m.send(); // 这里发送邮件,需要注意的是,这里是同步模式哦!  
  19.    std ::cout << m.response() << std::endl;//这里返回是否成功,250代表发送邮件成功;  
  20.    system("pause");  
  21.    return 0;  
  22. }  


需要注意的是,虽然我在测试时发送在cpp文件中写入中文使用163.com发送是没有出现乱码的,但是,在公司中发送报警邮件则会出现乱码。为了解决乱码问题,需要使用网络上有人提供的string s2utfs(const  string&  strSrc)函数进行转码为utf8。


[cpp] view plaincopy
  1. #ifndef __CHARSET_CVT__  
  2. #define __CHARSET_CVT__  
  3. #include  <string>  
  4. #include  <clocale>  
  5.   
  6. std::string ws2s(const std::wstring& ws)  
  7. {  
  8.     std::string curLocale = setlocale(LC_ALL, NULL); // curLocale = "C";   
  9.     setlocale(LC_ALL, "chs");  
  10.     const wchar_t* _Source = ws.c_str();  
  11.     size_t _Dsize = 2 * ws.size() + 1;  
  12.     char *_Dest = new char[_Dsize];  
  13.     memset(_Dest, 0, _Dsize);  
  14.     wcstombs(_Dest, _Source, _Dsize);  
  15.     std::string result = _Dest;  
  16.     delete [] _Dest;  
  17.     setlocale(LC_ALL, curLocale.c_str());  
  18.     return result;  
  19. }  
  20.   
  21. std::wstring s2ws(const std::string& s)   
  22. {  
  23.     setlocale(LC_ALL, "chs");  
  24.     const char* _Source = s.c_str();  
  25.     size_t _Dsize = s.size() + 1;  
  26.     wchar_t* _Dest = new wchar_t[_Dsize];  
  27.     wmemset(_Dest, 0, _Dsize);  
  28.     int nret = mbstowcs(_Dest, _Source, _Dsize);  
  29.     std::wstring result = _Dest;  
  30.     delete [] _Dest;  
  31.     setlocale(LC_ALL, "C");  
  32.   
  33.     return result;  
  34. }  
  35.   
  36. std::wstring UTF2Uni(const char* src, std::wstring &t)   
  37. {  
  38.     if (src == NULL)  
  39.     {  
  40.         return L"";  
  41.     }  
  42.   
  43.     int size_s = strlen(src);  
  44.     int size_d = size_s + 10;  
  45.   
  46.     wchar_t *des = new wchar_t[size_d];  
  47.     memset(des, 0, size_d * sizeof(wchar_t));  
  48.   
  49.     int s = 0, d = 0;  
  50.     bool toomuchbyte = true//set true to skip error prefix.  
  51.   
  52.     while (s  < size_s && d  < size_d)  
  53.     {  
  54.         unsigned char c = src[s];  
  55.         if ((c & 0x80) == 0)  
  56.         {  
  57.             des[d++] += src[s++];  
  58.         }  
  59.         else if((c & 0xE0) == 0xC0)  /// < 110x-xxxx 10xx-xxxx  
  60.         {  
  61.             WCHAR &wideChar = des[d++];  
  62.             wideChar  = (src[s + 0] & 0x3F)<<6;  
  63.             wideChar |= (src[s + 1] & 0x3F);  
  64.   
  65.             s += 2;  
  66.         }  
  67.         else if((c & 0xF0) == 0xE0)  /// < 1110-xxxx 10xx-xxxx 10xx-xxxx  
  68.         {  
  69.             WCHAR &wideChar = des[d++];  
  70.   
  71.             wideChar  = (src[s + 0] & 0x1F)<<12;  
  72.             wideChar |= (src[s + 1] & 0x3F)<<6;  
  73.             wideChar |= (src[s + 2] & 0x3F);  
  74.   
  75.             s += 3;  
  76.         }  
  77.         else if((c & 0xF8) == 0xF0)  /// < 1111-0xxx 10xx-xxxx 10xx-xxxx 10xx-xxxx  
  78.         {  
  79.             WCHAR &wideChar = des[d++];  
  80.   
  81.             wideChar  = (src[s + 0] & 0x0F)<<18;  
  82.             wideChar  = (src[s + 1] & 0x3F)<<12;  
  83.             wideChar |= (src[s + 2] & 0x3F)<<6;  
  84.             wideChar |= (src[s + 3] & 0x3F);  
  85.   
  86.             s += 4;  
  87.         }  
  88.         else  
  89.         {  
  90.             WCHAR &wideChar = des[d++]; /// < 1111-10xx 10xx-xxxx 10xx-xxxx 10xx-xxxx 10xx-xxxx  
  91.   
  92.             wideChar  = (src[s + 0] & 0x07)<<24;  
  93.             wideChar  = (src[s + 1] & 0x3F)<<18;  
  94.             wideChar  = (src[s + 2] & 0x3F)<<12;  
  95.             wideChar |= (src[s + 3] & 0x3F)<<6;  
  96.             wideChar |= (src[s + 4] & 0x3F);  
  97.   
  98.             s += 5;  
  99.         }  
  100.     }  
  101.   
  102.     t = des;  
  103.     delete[] des;  
  104.     des = NULL;  
  105.   
  106.     return t;  
  107. }  
  108.   
  109. int Uni2UTF(const std::wstring& strRes, char *utf8, int nMaxSize)  
  110. {  
  111.     if (utf8 == NULL)  
  112.     {  
  113.         return -1;  
  114.     }  
  115.     int len = 0;  
  116.     int size_d = nMaxSize;  
  117.   
  118.     for (std::wstring::const_iterator it = strRes.begin(); it != strRes.end(); ++it)  
  119.     {   
  120.         wchar_t wchar = *it;   
  121.         if (wchar  < 0x80)   
  122.         {  
  123.             //length = 1;  
  124.             utf8[len++] = (char)wchar;  
  125.         }  
  126.         else if(wchar  < 0x800)  
  127.         {  
  128.             //length = 2;  
  129.             if (len + 1 >= size_d)  
  130.             {  
  131.                 return -1;  
  132.             }  
  133.   
  134.             utf8[len++] = 0xc0 | ( wchar >> 6 );  
  135.             utf8[len++] = 0x80 | ( wchar & 0x3f );  
  136.         }  
  137.         else if(wchar  < 0x10000)  
  138.         {  
  139.             //length = 3;  
  140.             if (len + 2 >= size_d)  
  141.             {  
  142.                 return -1;  
  143.             }  
  144.   
  145.             utf8[len++] = 0xe0 | ( wchar >> 12 );  
  146.             utf8[len++] = 0x80 | ( (wchar >> 6) & 0x3f );  
  147.             utf8[len++] = 0x80 | ( wchar & 0x3f );  
  148.         }  
  149.         else if( wchar  < 0x200000)  
  150.         {  
  151.             //length = 4;   
  152.             if (len + 3 >= size_d)  
  153.             {  
  154.                 return -1;  
  155.             }  
  156.   
  157.             utf8[len++] = 0xf0 | ( (int)wchar >> 18 );  
  158.             utf8[len++] = 0x80 | ( (wchar >> 12) & 0x3f );  
  159.             utf8[len++] = 0x80 | ( (wchar >> 6) & 0x3f );  
  160.             utf8[len++] = 0x80 | ( wchar & 0x3f );  
  161.         }  
  162.     }  
  163.     return len;  
  164. }  
  165.   
  166. std::string s2utfs(const std::string& strSrc)   
  167. {  
  168.     std::string strRes;  
  169.     std::wstring wstrUni = s2ws(strSrc);  
  170.   
  171.     char* chUTF8 = new char[wstrUni.length() * 3];  
  172.     memset(chUTF8, 0x00, wstrUni.length() * 3);  
  173.     Uni2UTF(wstrUni, chUTF8, wstrUni.length() * 3);  
  174.     strRes = chUTF8;   
  175.     delete [] chUTF8;  
  176.     return strRes;  
  177. }  
  178.   
  179. std::string utfs2s(const std::string& strutf)   
  180. {  
  181.     std::wstring wStrTmp;  
  182.     UTF2Uni(strutf.c_str(), wStrTmp);  
  183.     return ws2s(wStrTmp);  
  184. }  
  185.   
  186. #endif  



给多人发送HTML的demo2.cpp文件如下

[cpp] view plaincopy
  1. #include <iostream>  
  2. // 由于头文件所处的位置是jwsmtp-1.32.15\jwsmtp\jwsmtp,所以,需要注意include的路径  
  3. #include "jwsmtp/jwsmtp.h"  
  4.   
  5. std::string html("<html>"  
  6. "<body>"  
  7. "This is the html part of the message<br><br>"  
  8. "<b>bold</b><br>"  
  9. "<i>italic</i><br>"  
  10. "<font size=\"7\">Large Text</font><br><br>"  
  11. "Or a link: <a href=\"http://johnwiggins.net\">johnwiggins.net</a><br><br>"  
  12. "And an image: <br><img alt=\"an image in email\" src=\"http://johnwiggins.net/jwsmtp/example.png\"><br>"  
  13. "</body>"  
  14. "</html>");  
  15.   
  16. int main(int argc, char* argv[])  
  17. {  
  18.    jwsmtp::mailer m(""/*接收者不填写*/"testjwstmp@163.com"/*发送者*/"这里填写邮件标题",  
  19.                     "这里填写邮件内容""smtp.163.com",  
  20.                     jwsmtp::mailer::SMTP_PORT, false);  
  21.   
  22.    //添加多个接收者  
  23.    m.addrecipient("testjwstmp@163.com");  
  24.    m.addrecipient("testjwstmp@gmail.com");  
  25.    m.addrecipient("testjwstmp@qq.com");  
  26.   
  27.    //添加HTML的发送内容,它会替换构造函数中的“这里填写邮件内容”  
  28.    m.setmessageHTML(html);  
  29.   
  30.    //经过测试,163支持的auth认证是PLAIN模式  
  31.    m.authtype(jwsmtp::mailer::PLAIN);  
  32.   
  33.    //这里输入认证用户名,注意哦,需要是***@163.com的用户名  
  34.    m.username("testjwstmp@163.com");  
  35.    //这里输入密码  
  36.    m.password("******");  
  37.    m.send(); // 这里发送邮件,需要注意的是,这里是同步模式哦!  
  38.    std ::cout << m.response() << std::endl;//这里如果展示的是250,代表发送邮件成功  
  39.    system("pause");  
  40.    return 0;  
  41. }  


附上发送Email的返回码

邮件服务返回代码含义  
500   格式错误,命令不可识别(此错误也包括命令行过长)  
501   参数格式错误  
502   命令不可实现  
503   错误的命令序列  
504   命令参数不可实现  
211   系统状态或系统帮助响应  
214   帮助信息  
220     服务就绪  
221     服务关闭传输信道  
421     服务未就绪,关闭传输信道(当必须关闭时,此应答可以作为对任何命令的响应)  
250   要求的邮件操作完成  
251   用户非本地,将转发向  
450   要求的邮件操作未完成,邮箱不可用(例如,邮箱忙)  
550   要求的邮件操作未完成,邮箱不可用(例如,邮箱未找到,或不可访问)  
451   放弃要求的操作;处理过程中出错  
551   用户非本地,请尝试  
452   系统存储不足,要求的操作未执行  
552   过量的存储分配,要求的操作未执行  
553   邮箱名不可用,要求的操作未执行(例如邮箱格式错误)  
354   开始邮件输入,以.结束  
554   操作失败  
535   用户验证失败  
235   用户验证成功  
334   等待用户输入验证信