博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
结合MIME C++ library与CURL发送带附件的邮件
阅读量:2392 次
发布时间:2019-05-10

本文共 13024 字,大约阅读时间需要 43 分钟。

原文地址:

使用CURL发送不带附件的例子,在CURL的官方范例simplesmtp.cpp和smtp_tls.cpp中,认真看看,使用不难。而发送附件的例子则没有了,需要了解MIME协议,将邮件按照MIME编码,在CURLOPT_READFUNCTION发送出去即可。直接用字符串拼凑MIME有点麻烦,可以结合MIME C++ library完成这项工作。MIME C++ library的下载地址http://www.codesink.org/mimetic_mime_library.html。

[cpp]
  1. #include "stdafx.h"  
  2. #include <string>  
  3. #include <iostream>  
  4. #include <mimetic/mimetic.h>  
  5. #include <sstream>  
  6. #include <iterator>  
  7. #include <stdio.h>  
  8. #include <fstream>  
  9.   
  10. int _tmain(int argc, _TCHAR* argv[])  
  11. {  
  12.   
  13.     mimetic::MimeEntity me;  
  14.     me.header().from("me <me@domain.com>");  
  15.     me.header().to("you <you@domain.com>");  
  16.     me.header().subject("my first mimetic msg");  
  17.     me.body().assign("hello there!");  
  18.     std::cout << me <<std::endl;  
  19.         return 0;  
  20. }  
显示如下:

From: me <me@domain.com>   //From:简称<邮箱地址>

To: you <you@domain.com>    //To:简称<邮箱地址>
Subject: my first mimetic msg //邮件标题
hello there!  //正文内容

这是一个最简单的MIME 流了。如果是带附件的 那么:

[cpp]
  1. #include "stdafx.h"  
  2. #include <string>  
  3. #include <iostream>  
  4. #include <mimetic/mimetic.h>  
  5. #include <sstream>  
  6. #include <iterator>  
  7. #include <stdio.h>  
  8. #include <fstream>  
  9.   
  10. int _tmain(int argc, _TCHAR* argv[])  
  11. {  
  12.   
  13.     mimetic::MultipartMixed head;  
  14.     //写件人  
  15.     head.header().from("<me@sina.com.cn>");  
  16.     //收件人  
  17.     head.header().to("<you@sina.com.cn>");  
  18.     //抄送  
  19.     head.header().cc("<he@sina.com.cn>;<she@sina.com.cn>;");  
  20.     //标题  
  21.     head.header().subject("my first mimetic msg");  
  22.     //MIME协议版本  
  23.     head.header().push_back(mimetic::Field("Mime-Version","1.0"));  
  24.     //正文,由于是MultipartMixed,这个内容是会被忽略的  
  25.     head.body().assign("hello there!");  
  26.   
  27.     //创建一个新的块,在这里是附件  
  28.     mimetic::MimeEntity* pMe = new mimetic::MimeEntity;  
  29.     //下面的代码就是开始设置这一段邮件内容的头了  
  30.   
  31.     //记住这里千万不能写成  
  32.     //pMe->header().push_back(mimetic::Field("Content-Type","pplication/octet-stream"));  
  33.     //pMe->header().push_back(mimetic::Field("name","readme.txt"));  
  34.     pMe->header().push_back(mimetic::Field("Content-Type: application/octet-stream; name=readme.txt"));  
  35.     //这里和上一句需要注意的地方一样,这里说明了这个块是一个附件  
  36.     pMe->header().push_back(mimetic::Field("Content-Disposition : attachment; filename=readme.txt"));  
  37.     //说明这个块是以BASE64编码的  
  38.     pMe->header().push_back(mimetic::Field("Content-Transfer-Encoding","base64"));  
  39.   
  40.     //设置完头以后,加载具体内容  
  41.     FILE *pfile = fopen(".\\readme.txt","rb");  
  42.     char buffer[4096];  
  43.     uint32_t totalreadbytes = 0;  
  44.     while (!feof(pfile))  
  45.     {  
  46.         //读文件  
  47.         uint32_t readbytes = fread(buffer, 1, 4028, pfile);  
  48.         if (ferror(pfile) || readbytes == 0)  
  49.         {  
  50.             break;  
  51.         }  
  52.         totalreadbytes += readbytes;  
  53.         mimetic::Base64::Encoder b64;  
  54.         std::stringstream temp;  
  55.         std::ostreambuf_iterator<char> out(temp);  
  56.         //转为BASE64编码,目标存放至std::stringstream中  
  57.         mimetic::code(buffer,  buffer + readbytes, b64, out);  
  58.         std::string str = temp.str();  
  59.         std::cout<<str;  
  60.         //将转换后的内容放入块中,不要贪方便写成  
  61.         //pMe->load(temp.str().begin(), temp.str().end(), mimetic::imNone);  
  62.         //会崩溃的  
  63.         pMe->load(str.begin(), str.end(), mimetic::imNone);  
  64.     }  
  65.   
  66.     std::cout<<head;  
  67.     return 0;  
  68. }  
显示的MIME流如下:
Content-Type: multipart/mixed;
boundary="----lrsJRnnv8qrhVhSN0z5KGo2eQwzHwv_LA_MGCzpaJN87zTe1=_2_"
From: me@sina.com.cn
To: you@sina.com.cn
CC: <he@sina.com.cn>;<she@sina.com.cn>;
Subject: my first mimetic msg
Mime-Version: 1.0
------lrsJRnnv8qrhVhSN0z5KGo2eQwzHwv_LA_MGCzpaJN87zTe1=_2_
Content-Type: application/octet-stream; name="readme.txt"
Content-Disposition : attachment; filename=readme.txt
Content-Transfer-Encoding: base64
PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09
PT09PT09PT09PT09PT09DQogICAgQ09OU09MRSBBUFBMSUNBVElPTiA6IHRlc3RfbWltZXRpYyBQ
cm9qZWN0IE92ZXJ2aWV3DQo9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09
PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KQXBwV2l6YXJkIGhhcyBjcmVhdGVk
IHRoaXMgdGVzdF9taW1ldGljIGFwcGxpY2F0aW9uIGZvciB5b3UuDQoNClRoaXMgZmlsZSBjb250
YWlucyBhIHN1bW1hcnkgb2Ygd2hhdCB5b3Ugd2lsbCBmaW5kIGluIGVhY2ggb2YgdGhlIGZpbGVz
IHRoYXQNCm1ha2UgdXAgeW91ciB0ZXN0X21pbWV0aWMgYXBwbGljYXRpb24uDQoNCg0KdGVzdF9t
aW1ldGljLnZjeHByb2oNCiAgICBUaGlzIGlzIHRoZSBtYWluIHByb2plY3QgZmlsZSBmb3IgVkMr
KyBwcm9qZWN0cyBnZW5lcmF0ZWQgdXNpbmcgYW4gQXBwbGljYXRpb24gV2l6YXJkLg0KICAgIEl0
IGNvbnRhaW5zIGluZm9ybWF0aW9uIGFib3V0IHRoZSB2ZXJzaW9uIG9mIFZpc3VhbCBDKysgdGhh
dCBnZW5lcmF0ZWQgdGhlIGZpbGUsIGFuZA0KICAgIGluZm9ybWF0aW9uIGFib3V0IHRoZSBwbGF0
Zm9ybXMsIGNvbmZpZ3VyYXRpb25zLCBhbmQgcHJvamVjdCBmZWF0dXJlcyBzZWxlY3RlZCB3aXRo
IHRoZQ0KICAgIEFwcGxpY2F0aW9uIFdpemFyZC4NCg0KdGVzdF9taW1ldGljLnZjeHByb2ouZmls
dGVycw0KICAgIFRoaXMgaXMgdGhlIGZpbHRlcnMgZmlsZSBmb3IgVkMrKyBwcm9qZWN0cyBnZW5l
cmF0ZWQgdXNpbmcgYW4gQXBwbGljYXRpb24gV2l6YXJkLiANCiAgICBJdCBjb250YWlucyBpbmZv
cm1hdGlvbiBhYm91dCB0aGUgYXNzb2NpYXRpb24gYmV0d2VlbiB0aGUgZmlsZXMgaW4geW91ciBw
cm9qZWN0IA0KICAgIGFuZCB0aGUgZmlsdGVycy4gVGhpcyBhc3NvY2lhdGlvbiBpcyB1c2VkIGlu
IHRoZSBJREUgdG8gc2hvdyBncm91cGluZyBvZiBmaWxlcyB3aXRoDQogICAgc2ltaWxhciBleHRl
bnNpb25zIHVuZGVyIGEgc3BlY2lmaWMgbm9kZSAoZm9yIGUuZy4gIi5jcHAiIGZpbGVzIGFyZSBh
c3NvY2lhdGVkIHdpdGggdGhlDQogICAgIlNvdXJjZSBGaWxlcyIgZmlsdGVyKS4NCg0KdGVzdF9t
aW1ldGljLmNwcA0KICAgIFRoaXMgaXMgdGhlIG1haW4gYXBwbGljYXRpb24gc291cmNlIGZpbGUu
DQoNCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8v
Ly8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vDQpPdGhlciBzdGFuZGFyZCBmaWxlczoNCg0KU3RkQWZ4
LmgsIFN0ZEFmeC5jcHANCiAgICBUaGVzZSBmaWxlcyBhcmUgdXNlZCB0byBidWlsZCBhIHByZWNv
bXBpbGVkIGhlYWRlciAoUENIKSBmaWxlDQogICAgbmFtZWQgdGVzdF9taW1ldGljLnBjaCBhbmQg
YSBwcmVjb21waWxlZCB0eXBlcyBmaWxlIG5hbWVkIFN0ZEFmeC5vYmouDQoNCi8vLy8vLy8vLy8v
Ly8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8v
Ly8vLy8vLy8vDQpPdGhlciBub3RlczoNCg0KQXBwV2l6YXJkIHVzZXMgIlRPRE86IiBjb21tZW50
cyB0byBpbmRpY2F0ZSBwYXJ0cyBvZiB0aGUgc291cmNlIGNvZGUgeW91DQpzaG91bGQgYWRkIHRv
IG9yIGN1c3RvbWl6ZS4NCg0KLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8v
Ly8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8NCg==
------lrsJRnnv8qrhVhSN0z5KGo2eQwzHwv_LA_MGCzpaJN87zTe1=_2_--

在这里值得一说的是Content-Type: multipart/mixed;

boundary="----lrsJRnnv8qrhVhSN0z5KGo2eQwzHwv_LA_MGCzpaJN87zTe1=_2_"这里说明了邮件有多块,以----lrsJRnnv8qrhVhSN0z5KGo2eQwzHwv_LA_MGCzpaJN87zTe1=_2_为分割标识符。如果想给邮件中添加新的一个块,比如说,除了附件还需要个正文那么需要再new mimetic::MimeEntity* pMe

[cpp]
  1. //添加一段正文  
  2. mimetic::MimeEntity* pMe2 = new mimetic::MimeEntity;  
  3. //说明块是一段文字,文字使用GB2312字符集  
  4. pMe2->header().push_back(mimetic::Field("Content-Type: text/plain; charset=GB2312"));  
  5. pMe2->header().push_back(mimetic::Field("Content-Transfer-Encoding","base64"));  
  6. //把这一块加入到整个邮件中  
  7. head.body().parts().push_back(pMe2);  
到此为止所需要的流已经生成了,剩下的就是在CURL中发送出去。
[cpp]
  1. // smtp_ex01.cpp : Defines the entry point for the console application.  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5.   
  6.   
  7. /*************************************************************************** 
  8. *                                  _   _ ____  _ 
  9. *  Project                     ___| | | |  _ \| | 
  10. *                             / __| | | | |_) | | 
  11. *                            | (__| |_| |  _ <| |___ 
  12. *                             \___|\___/|_| \_\_____| 
  13. * 
  14. * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. 
  15. * 
  16. * This software is licensed as described in the file COPYING, which 
  17. * you should have received as part of this distribution. The terms 
  18. * are also available at http://curl.haxx.se/docs/copyright.html. 
  19. * 
  20. * You may opt to use, copy, modify, merge, publish, distribute and/or sell 
  21. * copies of the Software, and permit persons to whom the Software is 
  22. * furnished to do so, under the terms of the COPYING file. 
  23. * 
  24. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 
  25. * KIND, either express or implied. 
  26. * 
  27. ***************************************************************************/   
  28. #include <stdio.h>  
  29. #include <mimetic/mimetic.h>  
  30. #include <curl/curl.h>  
  31. #include <string.h>  
  32. #include <iostream>  
  33. #include <sstream>  
  34. #include <stdio.h>  
  35. /* This is a simple example showing how to send mail using libcurl's SMTP 
  36. * capabilities. It builds on the simplesmtp.c example, adding some 
  37. * authentication and transport security. 
  38. */   
  39.   
  40. #define FROM    "<me@test.com.cn>"  
  41. #define TO      "<you@test.com.cn>"  
  42. #define CC      "<he@test.com.cn>"  
  43.   
  44. #define  BUFFERR_SIZE 4096  
  45.   
  46. struct UserData  
  47. {  
  48.     std::stringstream ss;  
  49.     size_t total;  
  50.     UserData()  
  51.         :total(0)  
  52.     {  
  53.   
  54.     }  
  55. };  
  56.   
  57.   
  58. static size_t my_read(void *ptr, size_t size, size_t nmemb, void *userp)  
  59. {  
  60.     struct UserData * pstream = static_cast<struct UserData *>(userp);  
  61.     //assert(pstream);  
  62.     if (pstream->ss.eof())  
  63.     {  
  64.         //也是因为移动到末尾时tellg()返回的数据总是不对  
  65.         return 0;  
  66.     }  
  67.     size_t before = pstream->ss.tellg();  
  68.     pstream->ss.read((char*)ptr, size*nmemb);  
  69.     size_t after = pstream->ss.tellg();  
  70.     if (pstream->ss.eof())  
  71.     {  
  72.         //对std::stringstream不熟悉,不知道为什么移动到末尾后  
  73.         //tellg()返回的数据总是不对  
  74.         std::cout<<(pstream->total - before)<<std::endl;  
  75.         return pstream->total - before;  
  76.     }  
  77.     std::cout<<(after - before)<<std::endl;  
  78.     return after - before;  
  79. }  
  80.   
  81.   
  82.   
  83. int main(void)  
  84. {  
  85.     CURL *curl;  
  86.     CURLcode res;  
  87.     struct curl_slist *recipients = NULL;  
  88.   
  89.     mimetic::MultipartMixed head;  
  90.     head.header().from("<me@test.com.cn>");  
  91.     head.header().to("<you@<span style="font-family: Arial, Helvetica, sans-serif;">test</span>.com.cn>");  
  92.     head.header().cc("<he@test.com.cn>");  
  93.     head.header().subject("my first mimetic msg");  
  94.     head.header().push_back(mimetic::Field("Mime-Version","1.0"));  
  95.     head.header().push_back(mimetic::Field("Message-ID","<dcd7cb36-11db-487a-9f3a-e652a9458efd@rfcpedant.example.org>"));  
  96.     head.body().assign("hello there!");  
  97.   
  98.     mimetic::MimeEntity* pMe = new mimetic::MimeEntity;  
  99.   
  100.     pMe->header().push_back(mimetic::Field("Content-Type: application/octet-stream; name=<span style="font-family: Arial, Helvetica, sans-serif;">readme.txt</span>"));  
  101.     pMe->header().push_back(mimetic::Field("Content-Disposition : attachment; filename=readme.txt"));  
  102.     pMe->header().push_back(mimetic::Field("Content-Transfer-Encoding","base64"));  
  103.     FILE *pfile = fopen(".\\readme.txt","rb");  
  104.     char buffer[BUFFERR_SIZE];  
  105.     uint32_t totalreadbytes = 0;  
  106.     while (!feof(pfile))  
  107.     {  
  108.         uint32_t readbytes = fread(buffer, 1, BUFFERR_SIZE - 1, pfile);  
  109.         if (ferror(pfile) || readbytes == 0)  
  110.         {  
  111.             break;  
  112.         }  
  113.         totalreadbytes += readbytes;  
  114.         mimetic::Base64::Encoder b64;  
  115.         std::stringstream temp;  
  116.         std::ostreambuf_iterator<char> out(temp);  
  117.         buffer[readbytes] = '\0';  
  118.         mimetic::code(buffer,  buffer + readbytes, b64, out);  
  119.         std::string str = temp.str();  
  120.         pMe->load(str.begin(), str.end(), mimetic::imNone);  
  121.     }  
  122.     head.body().parts().push_back(pMe);  
  123.     struct UserData ud;  
  124.     ud.ss<<head;  
  125.     ud.ss.seekg(0, std::ios::end);  
  126.     ud.total = ud.ss.tellg();  
  127.     ud.ss.seekg(0, std::ios::beg);  
  128.   
  129.   
  130.     curl = curl_easy_init();  
  131.     if (curl) {  
  132.         /* This is the URL for your mailserver. Note the use of port 587 here, 
  133.         * instead of the normal SMTP port (25). Port 587 is commonly used for 
  134.         * secure mail submission (see RFC4403), but you should use whatever 
  135.         * matches your server configuration. */   
  136.         curl_easy_setopt(curl, CURLOPT_URL, "smtp://mainserver.example.net:25");//"smtp://mainserver.example.net:25");  
  137.   
  138.         /* In this example, we'll start with a plain text connection, and upgrade 
  139.         * to Transport Layer Security (TLS) using the STARTTLS command. Be careful 
  140.         * of using CURLUSESSL_TRY here, because if TLS upgrade fails, the transfer 
  141.         * will continue anyway - see the security discussion in the libcurl 
  142.         * tutorial for more details. */   
  143.         //curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);  
  144.   
  145.         /* If your server doesn't have a valid certificate, then you can disable 
  146.         * part of the Transport Layer Security protection by setting the 
  147.         * CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST options to 0 (false). 
  148.         *   curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); 
  149.         *   curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); 
  150.         * That is, in general, a bad idea. It is still better than sending your 
  151.         * authentication details in plain text though. 
  152.         * Instead, you should get the issuer certificate (or the host certificate 
  153.         * if the certificate is self-signed) and add it to the set of certificates 
  154.         * that are known to libcurl using CURLOPT_CAINFO and/or CURLOPT_CAPATH. See 
  155.         * docs/SSLCERTS for more information. 
  156.         */   
  157.         //curl_easy_setopt(curl, CURLOPT_CAINFO, "/path/to/certificate.pem");  
  158.   
  159.         /* A common reason for requiring transport security is to protect 
  160.         * authentication details (user names and passwords) from being "snooped" 
  161.         * on the network. Here is how the user name and password are provided: */   
  162.         curl_easy_setopt(curl, CURLOPT_USERNAME, "test@test.com");  
  163.         curl_easy_setopt(curl, CURLOPT_PASSWORD, "*****");  
  164.   
  165.         /* value for envelope reverse-path */   
  166.         curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM);  
  167.         /* Add two recipients, in this particular case they correspond to the 
  168.         * To: and Cc: addressees in the header, but they could be any kind of 
  169.         * recipient. */   
  170.         recipients = curl_slist_append(recipients, TO);  
  171.         recipients = curl_slist_append(recipients, CC);  
  172.         curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);  
  173.   
  174.         /* In this case, we're using a callback function to specify the data. You 
  175.         * could just use the CURLOPT_READDATA option to specify a FILE pointer to 
  176.         * read from. 
  177.         */   
  178.         curl_easy_setopt(curl, CURLOPT_READFUNCTION, my_read);  
  179.         curl_easy_setopt(curl, CURLOPT_READDATA, &ud);  
  180.   
  181. //      curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source);  
  182. //      curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx);  
  183.   
  184.         /* Since the traffic will be encrypted, it is very useful to turn on debug 
  185.         * information within libcurl to see what is happening during the transfer. 
  186.         */   
  187.         curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);  
  188.   
  189.         /* send the message (including headers) */   
  190.         res = curl_easy_perform(curl);  
  191.   
  192.         /* free the list of recipients and clean up */   
  193.         curl_slist_free_all(recipients);  
  194.         curl_easy_cleanup(curl);  
  195.     }  
  196.     return 0;  
  197. }  
需要注意的是MIME C++ library构造邮件流的时候是将所有内容加载至内存中的,对于大的附件还得自己拼凑MIME流,不过通过对MIME C++ library学习了MIME协议这应该不是太难的问题了。

转载地址:http://mweab.baihongyu.com/

你可能感兴趣的文章
[转]KFS的部署与简单使用
查看>>
[转]KFS官方部署手册
查看>>
[转]Ubuntu 10.04 LTS 安装 sun-java6-jdk
查看>>
[转]mmap详解
查看>>
[转]HDFS和KFS 比较
查看>>
Oracle 12CR2 Oracle Restart - ASM Startup fails with PRCR-1079
查看>>
poj 2140 Herd Sums
查看>>
poj 2524 Ubiquitous Religions
查看>>
poj 1308 Is It A Tree?
查看>>
poj 1611 The Suspects
查看>>
poj 3331 The Idiot of the Year Contest!
查看>>
poj 3233 Matrix Power Series
查看>>
poj 3070 Fibonacci
查看>>
poj 1656 Counting Black
查看>>
BestCoder Round #28
查看>>
poj1845 Sumdiv
查看>>
poj3299 Humidex
查看>>
poj2159 Ancient Cipher
查看>>
poj1083 Moving Tables
查看>>
poj2255 Tree Recovery
查看>>