C++实现发送邮件

备注:代码是从别人博客拷贝下来,如有问题;请联系 QQ:972510639

SmtpEmail.h

 1 #ifndef __SMTP_EMAIL_H__ //避免重复包含
 2 #define __SMTP_EMAIL_H__
 3 
 4 #include <iostream>
 5 #include <list>
 6 #include <WinSock2.h>
 7 using namespace std;
 8 
 9 const int MAXLEN = 1024;
10 const int MAX_FILE_LEN = 6000;
11 
12 static const char base64Char[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
13 
14 struct FILEINFO /*用来记录文件的一些信息*/
15 {
16     char fileName[128]; /*文件名称*/
17     char filePath[256]; /*文件绝对路径*/
18 };
19 
20 class CSmtpEmail
21 {
22 public:
23     CSmtpEmail(void);
24     CSmtpEmail(
25         int port,
26         string srvDomain,    //smtp服务器域名
27         string userName,    //用户名
28         string password,    //密码
29         string targetEmail, //目的邮件地址
30         string emailTitle,  //主题
31         string content       //内容
32     );
33 public:
34     ~CSmtpEmail(void);
35 public:
36     int port;
37 public:
38     string domain;
39     string user;
40     string pass;
41     string targetAddr;
42     string title;
43     string content;
44     /*为了方便添加文件,删除文件神马的,使用list容器最为方便,相信大家在数据结构里面都学过*/
45     list <FILEINFO *> listFile;
46 
47 public:
48     char buff[MAXLEN + 1];
49     int buffLen;
50     SOCKET sockClient;    //客户端的套接字
51 public:
52     bool CreateConn(); /*创建连接*/
53 
54     bool Send(string &message);
55     bool Recv();
56 
57     void FormatEmailHead(string &email);//格式化要发送的邮件头部
58     int Login();
59     bool SendEmailHead();        //发送邮件头部信息
60     bool SendTextBody();        //发送文本信息
61                                 //bool SendAttachment();        //发送附件
62     int SendAttachment_Ex();
63     bool SendEnd();
64 public:
65     void AddAttachment(string &filePath); //添加附件
66     void DeleteAttachment(string &filePath); //删除附件
67     void DeleteAllAttachment(); //删除所有的附件
68 
69     void SetSrvDomain(string &domain);
70     void SetUserName(string &user);
71     void SetPass(string &pass);
72     void SetTargetEmail(string &targetAddr);
73     void SetEmailTitle(string &title);
74     void SetContent(string &content);
75     void SetPort(int port);
76     int SendEmail_Ex();
77     /*关于错误码的说明:1.网络错误导致的错误2.用户名错误3.密码错误4.文件不存在0.成功*/
78     char* base64Encode(char const* origSigned, unsigned origLength);
79 };
80 
81 #endif // !__SMTP_EMAIL_H__

SmtpEmail.cpp

  1 #include "stdafx.h"
  2 #include "SmtpEmail.h"
  3 #include <iostream>
  4 #include <fstream>
  5 using namespace std;
  6 
  7 #pragma  comment(lib, "ws2_32.lib")    /*链接ws2_32.lib动态链接库*/
  8 
  9 /*base64采用别人的编码,不过,这不是重点,重点是我完成了我的一个比较好的邮件发送客户端*/
 10 char* CSmtpEmail::base64Encode(char const* origSigned, unsigned origLength)
 11 {
 12     unsigned char const* orig = (unsigned char const*)origSigned; // in case any input bytes have the MSB set
 13     if (orig == NULL) return NULL;
 14 
 15     unsigned const numOrig24BitValues = origLength / 3;
 16     bool havePadding = origLength > numOrig24BitValues * 3;
 17     bool havePadding2 = origLength == numOrig24BitValues * 3 + 2;
 18     unsigned const numResultBytes = 4 * (numOrig24BitValues + havePadding);
 19     char* result = new char[numResultBytes + 3]; // allow for trailing '/0'
 20 
 21                                                  // Map each full group of 3 input bytes into 4 output base-64 characters:
 22     unsigned i;
 23     for (i = 0; i < numOrig24BitValues; ++i)
 24     {
 25         result[4 * i + 0] = base64Char[(orig[3 * i] >> 2) & 0x3F];
 26         result[4 * i + 1] = base64Char[(((orig[3 * i] & 0x3) << 4) | (orig[3 * i + 1] >> 4)) & 0x3F];
 27         result[4 * i + 2] = base64Char[((orig[3 * i + 1] << 2) | (orig[3 * i + 2] >> 6)) & 0x3F];
 28         result[4 * i + 3] = base64Char[orig[3 * i + 2] & 0x3F];
 29     }
 30 
 31     // Now, take padding into account.  (Note: i == numOrig24BitValues)
 32     if (havePadding)
 33     {
 34         result[4 * i + 0] = base64Char[(orig[3 * i] >> 2) & 0x3F];
 35         if (havePadding2)
 36         {
 37             result[4 * i + 1] = base64Char[(((orig[3 * i] & 0x3) << 4) | (orig[3 * i + 1] >> 4)) & 0x3F];
 38             result[4 * i + 2] = base64Char[(orig[3 * i + 1] << 2) & 0x3F];
 39         }
 40         else
 41         {
 42             result[4 * i + 1] = base64Char[((orig[3 * i] & 0x3) << 4) & 0x3F];
 43             result[4 * i + 2] = '=';
 44         }
 45         result[4 * i + 3] = '=';
 46     }
 47 
 48     result[numResultBytes] = '\0';
 49     return result;
 50 }
 51 CSmtpEmail::CSmtpEmail(void)
 52 {
 53     this->content = "";
 54     this->port = 25;
 55     this->user = "";
 56     this->pass = "";
 57     this->targetAddr = "";
 58     this->title = "";
 59     this->domain = "";
 60 
 61     WORD wVersionRequested;
 62     WSADATA wsaData;
 63     int err;
 64     wVersionRequested = MAKEWORD(2, 1);
 65     err = WSAStartup(wVersionRequested, &wsaData);
 66     this->sockClient = 0;
 67 
 68 }
 69 
 70 CSmtpEmail::~CSmtpEmail(void)
 71 {
 72     DeleteAllAttachment();
 73     closesocket(sockClient);
 74     WSACleanup();
 75 }
 76 
 77 
 78 CSmtpEmail::CSmtpEmail(
 79     int port,
 80     string srvDomain,
 81     string userName,
 82     string password,
 83     string targetEmail,
 84     string emailTitle,
 85     string content
 86 )
 87 {
 88     this->content = content;
 89     this->port = port;
 90     this->user = userName;
 91     this->pass = password;
 92     this->targetAddr = targetEmail;
 93     this->title = emailTitle;
 94     this->domain = srvDomain;
 95 
 96     WORD wVersionRequested;
 97     WSADATA wsaData;
 98     int err;
 99     wVersionRequested = MAKEWORD(2, 1);
100     err = WSAStartup(wVersionRequested, &wsaData);
101     this->sockClient = 0;
102 }
103 
104 bool CSmtpEmail::CreateConn()
105 {
106     //为建立socket对象做准备,初始化环境
107     SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0); //建立socket对象
108     SOCKADDR_IN addrSrv;
109     HOSTENT* pHostent;
110     pHostent = gethostbyname(domain.c_str());  //得到有关于域名的信息
111 
112     addrSrv.sin_addr.S_un.S_addr = *((DWORD *)pHostent->h_addr_list[0]);    //得到smtp服务器的网络字节序的ip地址   
113     addrSrv.sin_family = AF_INET;
114     addrSrv.sin_port = htons(port);
115     int err = connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));   //向服务器发送请求 
116     if (err != 0)
117     {
118         return false;
119         //printf("链接失败\n");
120     }
121     this->sockClient = sockClient;
122     if (false == Recv())
123     {
124         return false;
125     }
126     return true;
127 }
128 
129 bool CSmtpEmail::Send(string &message)
130 {
131     int err = send(sockClient, message.c_str(), message.length(), 0);
132     if (err == SOCKET_ERROR)
133     {
134         return false;
135     }
136     string message01;
137     cout << message.c_str() << endl;
138     return true;
139 }
140 
141 bool CSmtpEmail::Recv()
142 {
143     memset(buff, 0, sizeof(char)* (MAXLEN + 1));
144     int err = recv(sockClient, buff, MAXLEN, 0); //接收数据
145     if (err == SOCKET_ERROR)
146     {
147         return false;
148     }
149     buff[err] = '\0';
150     cout << buff << endl;
151     return true;
152 }
153 
154 int CSmtpEmail::Login()
155 {
156     string sendBuff;
157     sendBuff = "EHLO ";
158     sendBuff += user;
159     sendBuff += "\r\n";
160 
161     if (false == Send(sendBuff) || false == Recv()) //既接收也发送
162     {
163         return 1; /*1表示发送失败由于网络错误*/
164     }
165 
166     sendBuff.empty();
167     sendBuff = "AUTH LOGIN\r\n";
168     if (false == Send(sendBuff) || false == Recv()) //请求登陆
169     {
170         return 1; /*1表示发送失败由于网络错误*/
171     }
172 
173     sendBuff.empty();
174     int pos = user.find('@', 0);
175     sendBuff = user.substr(0, pos); //得到用户名
176 
177     char *ecode;
178     /*在这里顺带扯一句,关于string类的length函数与C语言中的strlen函数的区别,strlen计算出来的长度,只到'\0'字符为止,而string::length()函数实际上返回的是string类中字符数组的大小,你自己可以测试一下,这也是为什么我下面不使用string::length()的原因*/
179 
180     ecode = base64Encode(sendBuff.c_str(), strlen(sendBuff.c_str()));
181     sendBuff.empty();
182     sendBuff = ecode;
183     sendBuff += "\r\n";
184     delete[]ecode;
185 
186     if (false == Send(sendBuff) || false == Recv()) //发送用户名,并接收服务器的返回
187     {
188         return 1; /*错误码1表示发送失败由于网络错误*/
189     }
190 
191     sendBuff.empty();
192     ecode = base64Encode(pass.c_str(), strlen(pass.c_str()));
193     sendBuff = ecode;
194     sendBuff += "\r\n";
195     delete[]ecode;
196 
197     if (false == Send(sendBuff) || false == Recv()) //发送用户密码,并接收服务器的返回
198     {
199         return 1; /*错误码1表示发送失败由于网络错误*/
200     }
201 
202     if (NULL != strstr(buff, "550"))
203     {
204         return 2;/*错误码2表示用户名错误*/
205     }
206 
207     if (NULL != strstr(buff, "535")) /*535是认证失败的返回*/
208     {
209         return 3; /*错误码3表示密码错误*/
210     }
211     return 0;
212 }
213 
214 bool CSmtpEmail::SendEmailHead()        //发送邮件头部信息
215 {
216     string sendBuff;
217     sendBuff = "MAIL FROM: <" + user + ">\r\n";
218     if (false == Send(sendBuff) || false == Recv())
219     {
220         return false; /*表示发送失败由于网络错误*/
221     }
222 
223 
224     sendBuff.empty();
225     sendBuff = "RCPT TO: <" + targetAddr + ">\r\n";
226     if (false == Send(sendBuff) || false == Recv())
227     {
228         return false; /*表示发送失败由于网络错误*/
229     }
230 
231     sendBuff.empty();
232     sendBuff = "DATA\r\n";
233     if (false == Send(sendBuff) || false == Recv())
234     {
235         return false; //表示发送失败由于网络错误
236     }
237 
238     sendBuff.empty();
239     FormatEmailHead(sendBuff);
240     if (false == Send(sendBuff))
241         //发送完头部之后不必调用接收函数,因为你没有\r\n.\r\n结尾,服务器认为你没有发完数据,所以不会返回什么值
242     {
243         return false; /*表示发送失败由于网络错误*/
244     }
245     return true;
246 }
247 
248 void CSmtpEmail::FormatEmailHead(string &email)
249 {/*格式化要发送的内容*/
250     email = "From: ";
251     email += user;
252     email += "\r\n";
253 
254     email += "To: ";
255     email += targetAddr;
256     email += "\r\n";
257 
258     email += "Subject: ";
259     email += title;
260     email += "\r\n";
261 
262     email += "MIME-Version: 1.0";
263     email += "\r\n";
264 
265     email += "Content-Type: multipart/mixed;boundary=qwertyuiop";
266     email += "\r\n";
267     email += "\r\n";
268 }
269 
270 bool CSmtpEmail::SendTextBody()  /*发送邮件文本*/
271 {
272     string sendBuff;
273     sendBuff = "--qwertyuiop\r\n";
274     sendBuff += "Content-Type: text/plain;";
275     sendBuff += "charset=\"gb2312\"\r\n\r\n";
276     sendBuff += content;
277     sendBuff += "\r\n\r\n";
278     return Send(sendBuff);
279 }
280 
281 int CSmtpEmail::SendAttachment_Ex() /*发送附件*/
282 {
283     for (list<FILEINFO *>::iterator pIter = listFile.begin(); pIter != listFile.end(); pIter++)
284     {
285         cout << "Attachment is sending ~~~~~" << endl;
286         cout << "Please be patient!" << endl;
287         string sendBuff;
288         sendBuff = "--qwertyuiop\r\n";
289         sendBuff += "Content-Type: application/octet-stream;\r\n";
290         sendBuff += " name=\"";
291         sendBuff += (*pIter)->fileName;
292         sendBuff += "\"";
293         sendBuff += "\r\n";
294 
295         sendBuff += "Content-Transfer-Encoding: base64\r\n";
296         sendBuff += "Content-Disposition: attachment;\r\n";
297         sendBuff += " filename=\"";
298         sendBuff += (*pIter)->fileName;
299         sendBuff += "\"";
300 
301         sendBuff += "\r\n";
302         sendBuff += "\r\n";
303         Send(sendBuff);
304         ifstream ifs((*pIter)->filePath, ios::in | ios::binary);
305         if (false == ifs.is_open())
306         {
307             return 4; /*错误码4表示文件打开错误*/
308         }
309         char fileBuff[MAX_FILE_LEN];
310         char *chSendBuff;
311         memset(fileBuff, 0, sizeof(fileBuff));
312         /*文件使用base64加密传送*/
313         while (ifs.read(fileBuff, MAX_FILE_LEN))
314         {
315             //cout << ifs.gcount() << endl;
316             chSendBuff = base64Encode(fileBuff, MAX_FILE_LEN);
317             chSendBuff[strlen(chSendBuff)] = '\r';
318             chSendBuff[strlen(chSendBuff)] = '\n';
319             send(sockClient, chSendBuff, strlen(chSendBuff), 0);
320             delete[]chSendBuff;
321         }
322         //cout << ifs.gcount() << endl;
323         chSendBuff = base64Encode(fileBuff, ifs.gcount());
324         chSendBuff[strlen(chSendBuff)] = '\r';
325         chSendBuff[strlen(chSendBuff)] = '\n';
326         int err = send(sockClient, chSendBuff, strlen(chSendBuff), 0);
327 
328         if (err != strlen(chSendBuff))
329         {
330             cout << "文件传送出错!" << endl;
331             return 1;
332         }
333         delete[]chSendBuff;
334     }
335     return 0;
336 }
337 
338 bool CSmtpEmail::SendEnd() /*发送结尾信息*/
339 {
340     string sendBuff;
341     sendBuff = "--qwertyuiop--";
342     sendBuff += "\r\n.\r\n";
343     if (false == Send(sendBuff) || false == Recv())
344     {
345         return false;
346     }
347     cout << buff << endl;
348     sendBuff.empty();
349     sendBuff = "QUIT\r\n";
350     return (Send(sendBuff) && Recv());
351 }
352 
353 int CSmtpEmail::SendEmail_Ex()
354 {
355     if (false == CreateConn())
356     {
357         return 1;
358     }
359     //Recv();
360     int err = Login(); //先登录
361     if (err != 0)
362     {
363         return err; //错误代码必须要返回
364     }
365     if (false == SendEmailHead()) //发送EMAIL头部信息
366     {
367         return 1; /*错误码1是由于网络的错误*/
368     }
369     if (false == SendTextBody())
370     {
371         return 1; /*错误码1是由于网络的错误*/
372     }
373     err = SendAttachment_Ex();
374     if (err != 0)
375     {
376         return err;
377     }
378     if (false == SendEnd())
379     {
380         return 1; /*错误码1是由于网络的错误*/
381     }
382     return 0; /*0表示没有出错*/
383 }
384 
385 void CSmtpEmail::AddAttachment(string &filePath) //添加附件
386 {
387     FILEINFO *pFile = new FILEINFO;
388     strcpy_s(pFile->filePath, filePath.c_str());
389     const char *p = filePath.c_str();
390     strcpy_s(pFile->fileName, p + filePath.find_last_of("\\") + 1);
391     listFile.push_back(pFile);
392 }
393 
394 void CSmtpEmail::DeleteAttachment(string &filePath) //删除附件
395 {
396     list<FILEINFO *>::iterator pIter;
397     for (pIter = listFile.begin(); pIter != listFile.end(); pIter++)
398     {
399         if (strcmp((*pIter)->filePath, filePath.c_str()) == 0)
400         {
401             FILEINFO *p = *pIter;
402             listFile.remove(*pIter);
403             delete p;
404             break;
405         }
406     }
407 }
408 
409 void CSmtpEmail::DeleteAllAttachment() /*删除所有的文件*/
410 {
411     for (list<FILEINFO *>::iterator pIter = listFile.begin(); pIter != listFile.end();)
412     {
413         FILEINFO *p = *pIter;
414         pIter = listFile.erase(pIter);
415         delete p;
416     }
417 }
418 
419 void CSmtpEmail::SetSrvDomain(string &domain)
420 {
421     this->domain = domain;
422 }
423 
424 void CSmtpEmail::SetUserName(string &user)
425 {
426     this->user = user;
427 }
428 
429 void CSmtpEmail::SetPass(string &pass)
430 {
431     this->pass = pass;
432 }
433 void CSmtpEmail::SetTargetEmail(string &targetAddr)
434 {
435     this->targetAddr = targetAddr;
436 }
437 void CSmtpEmail::SetEmailTitle(string &title)
438 {
439     this->title = title;
440 }
441 void CSmtpEmail::SetContent(string &content)
442 {
443     this->content = content;
444 }
445 void CSmtpEmail::SetPort(int port)
446 {
447     this->port = port;
448 }

实现

 1 CSmtpEmail smtp(
 2         25,                                /*smtp端口*/
 3         "smtp.qq.com",                    /*smtp服务器地址*/
 4         "972510639@qq.com",    /*你的邮箱地址*/
 5         "******",                    /*邮箱密码*///QQ邮箱密码获取 详见https://service.mail.qq.com/cgi-bin/help?subtype=1&&id=28&&no=1001256  163只需要原来密码
 6         "8473003889@qq.com",    /*目的邮箱地址*/
 7         "邮件测试",                            /*主题*/
 8         "测试邮件无需回复!!"        /*邮件正文*/
 9     );
10     /**
11     //添加附件时注意,\一定要写成\\,因为转义字符的缘故
12     string filePath("D:\\课程设计报告.doc");
13     smtp.AddAttachment(filePath);
14     */
15 
16     /*还可以调用CSmtp::DeleteAttachment函数删除附件,还有一些函数,自己看头文件吧!*/
17     //filePath = "C:\\Users\\李懿虎\\Desktop\\sendEmail.cpp";
18     //smtp.AddAttachment(filePath);
19 
20     int err;
21     if ((err = smtp.SendEmail_Ex()) != 0)
22     {
23         if (err == 1)
24             AfxMessageBox(L"错误1: 由于网络不畅通,发送失败!");
25         if (err == 2)
26             AfxMessageBox(L"错误2: 用户名错误,请核对!");
27         if (err == 3)
28             AfxMessageBox(L"错误3: 用户密码错误,请核对!");
29         if (err == 4)
30             AfxMessageBox(L"错误4: 请检查附件目录是否正确,以及文件是否存在!");
31     }

 

转载于:https://www.cnblogs.com/huyupei/p/10135549.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值