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     }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM