C++实现邮件发送程序在vs2013测试通过,一共3个文件,发邮件的程序封装为Csmtp 类。
1.测试用的主函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
// #include "Csmtp.h" #pragma comment(lib, "Kernel32.lib") int main() { Csmtp mail( 25, "smtp.126.com" , "username@126.com" , // 来源邮箱 "pwd" , "username@126.com" //目标邮箱 ); if (!mail.CReateSocket()) { cout << "ReateSocket failed!" << endl; return -1; // } mail.setTitle( "test mail" ); mail.setContent( "this is content." ); mail.addfile( "test1.png" ); //添加附件 mail.addfile( "test2.png" ); //添加附件 mail.SendMail(); //类主函数 return 0; } |
2.Csmtp类定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
#include <iostream> #include <string> #include <vector> #include <fstream> #include <WinSock2.h> //适用平台 Windows #pragma comment(lib, "ws2_32.lib") /*链接ws2_32.lib动态链接库*/ // POP3服务器(端口:110) Csmtp服务器(端口:25) using namespace std; class Csmtp { int port; string domain; string user; string pass; string target; string title; //邮件标题 string content; //邮件内容 HOSTENT* pHostent; SOCKET sockClient; //客户端的套接字 vector <string> filename; //存储附件名的向量 public : Csmtp( int _port, //端口25 string _domain, //域名 string _user, //发送者的邮箱 string _pass, //密码 string _target) //目标邮箱 :port(_port),domain(_domain),user(_user),pass(_pass), target(_target){}; //内容 bool CReateSocket(); void setTitle(string tem){title = tem;} void setContent(string tem){content = tem;} int SendAttachment(SOCKET &sockClient); int SendMail(); void addfile(string str){filename.push_back(str);} }; |
3. Csmtp 类的实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
|
#include "Csmtp.h" //#include <afx.h>//异常类 static const char base64Char[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ; char * base64Encode( char const * origSigned, unsigned origLength) { unsigned char const * orig = (unsigned char const *)origSigned; // in case any input bytes have the MSB set if (orig == NULL) return NULL; unsigned const numOrig24BitValues = origLength / 3; bool havePadding = origLength > numOrig24BitValues * 3; bool havePadding2 = origLength == numOrig24BitValues * 3 + 2; unsigned const numResultBytes = 4 * (numOrig24BitValues + havePadding); char * result = new char [numResultBytes + 3]; // allow for trailing '/0' // Map each full group of 3 input bytes into 4 output base-64 characters: unsigned i; for (i = 0; i < numOrig24BitValues; ++i) { result[4 * i + 0] = base64Char[(orig[3 * i] >> 2) & 0x3F]; result[4 * i + 1] = base64Char[(((orig[3 * i] & 0x3) << 4) | (orig[3 * i + 1] >> 4)) & 0x3F]; result[4 * i + 2] = base64Char[((orig[3 * i + 1] << 2) | (orig[3 * i + 2] >> 6)) & 0x3F]; result[4 * i + 3] = base64Char[orig[3 * i + 2] & 0x3F]; } // Now, take padding into account. (Note: i == numOrig24BitValues) if (havePadding) { result[4 * i + 0] = base64Char[(orig[3 * i] >> 2) & 0x3F]; if (havePadding2) { result[4 * i + 1] = base64Char[(((orig[3 * i] & 0x3) << 4) | (orig[3 * i + 1] >> 4)) & 0x3F]; result[4 * i + 2] = base64Char[(orig[3 * i + 1] << 2) & 0x3F]; } else { result[4 * i + 1] = base64Char[((orig[3 * i] & 0x3) << 4) & 0x3F]; result[4 * i + 2] = '=' ; } result[4 * i + 3] = '=' ; } result[numResultBytes] = '\0' ; return result; } int Csmtp::SendAttachment(SOCKET &sockClient) /*发送附件*/ { for (std::vector<string>::iterator iter = filename.begin();iter != filename.end(); iter++) { cout << "Attachment is sending··· " << endl; string path=*iter; ifstream ifs(path, ios::in | ios::binary); //'或链接2个属性,以输入、二进制打开' if ( false == ifs.is_open()) { cout<< "无法打开文件!" <<endl; return 1; } string sendstring; sendstring = "--@boundary@\r\nContent-Type: application/octet-stream; name=\"1.jpg\"\r\n" ; sendstring += "Content-Disposition: attachment; filename=\"1.jpg\"\r\n" ; sendstring += "Content-Transfer-Encoding: base64\r\n\r\n" ; send(sockClient, sendstring.c_str(), sendstring.length(), 0); //infile.read((char*)buffer,sizeof(数据类型)); // get length of file: ifs.seekg (0, ifs.end); int length = ifs.tellg(); ifs.seekg (0, ifs.beg); cout<< "length:" <<length<<endl; // allocate memory: char * buffer = new char [length]; // read data as a block: ifs.read (buffer,length); ifs.close(); char *pbase; pbase = base64Encode(buffer, length); delete []buffer; string str(pbase); delete []pbase; str+= "\r\n" ; int err =send(sockClient, str.c_str(), strlen (str.c_str()), 0); if (err != strlen (str.c_str())) { cout << "文件传送出错!" << endl; return 1; } } return 0; } bool Csmtp::CReateSocket() { WSADATA wsaData; WORD wVersionRequested = MAKEWORD(2, 1); //WSAStarup,即WSA(Windows SocKNDs Asynchronous,Windows套接字异步)的启动命令 int err = WSAStartup(wVersionRequested, &wsaData); cout<< "WSAStartup(0:successful):" <<err<<endl; char namebuf[128]; //获得本地计算机名 string ip_list; if (0==gethostname(namebuf,128)) { struct hostent* pHost; //获得本地IP地址 pHost=gethostbyname(namebuf); //pHost返回的是指向主机的列表 for ( int i=0;pHost!=NULL&&pHost->h_addr_list[i]!=NULL;i++) { string tem = inet_ntoa(*( struct in_addr *)pHost->h_addr_list[i]); ip_list += tem; ip_list += "\n" ; } } else { cout<< "获取主机信息失败..." <<endl ; } ////////////////////////////////////////////////////////////////////////// title=namebuf; // 邮件标题 content=ip_list; //主机ip sockClient = socket(AF_INET, SOCK_STREAM, 0); //建立socket对象 pHostent = gethostbyname(domain.c_str()); //得到有关于域名的信息 if (pHostent == NULL) { printf ( "创建连接失败,也许没联网!\n" ); return false ; } return true ; } int Csmtp::SendMail() { char *ecode; char buff[500]; //recv函数返回的结果 int err = 0; string message; // SOCKADDR_IN addrServer; //服务端地址 addrServer.sin_addr.S_un.S_addr = *(( DWORD *)pHostent->h_addr_list[0]); //得到smtp服务器的网络字节序的ip地址 addrServer.sin_family = AF_INET; addrServer.sin_port = htons(port); //连接端口25 //int connect (SOCKET s , const struct sockaddr FAR *name , int namelen ); err = connect(sockClient, (SOCKADDR*)&addrServer, sizeof (SOCKADDR)); //向服务器发送请求 cout<< "connect:" <<err<<endl; //telnet smtp.126.com 25 连接服务器结束 buff[recv(sockClient, buff, 500, 0)]= '\0' ; //cout<<"connect:"<<buff<<endl; message= "ehlo 126.com\r\n" ; send(sockClient, message.c_str(), message.length(), 0); buff[recv(sockClient, buff, 500, 0)]= '\0' ; //cout<<"helo:"<<buff<<endl; message= "auth login \r\n" ; send(sockClient, message.c_str(), message.length(), 0); buff[recv(sockClient, buff, 500, 0)]= '\0' ; //cout<<"auth login:"<<buff<<endl; //上传邮箱名 message=user; ecode = base64Encode(message.c_str(), strlen (message.c_str())); message = ecode; message += "\r\n" ; delete []ecode; send(sockClient, message.c_str(), message.length(), 0); buff[recv(sockClient, buff, 500, 0)]= '\0' ; //cout<<"usrname:"<<buff<<endl; //上传邮箱密码 message=pass; ecode = base64Encode(message.c_str(), strlen (message.c_str())); message = ecode; delete []ecode; message += "\r\n" ; send(sockClient, message.c_str(), message.length(), 0); buff[recv(sockClient, buff, 500, 0)]= '\0' ; //cout<<"password:"<<buff<<endl; message= "mail from:<" +user+ ">\r\nrcpt to:<" +target+ ">\r\n" ; send(sockClient, message.c_str(), message.length(), 0); buff[recv(sockClient, buff, 500, 0)]= '\0' ; //cout<<"mail from: "<<buff<<endl; buff[recv(sockClient, buff, 500, 0)]= '\0' ; //cout<<"rcpt to: "<<buff<<endl; message= "data\r\n" ; //data要单独发送一次 send(sockClient, message.c_str(), message.length(), 0); buff[recv(sockClient, buff, 500, 0)]= '\0' ; //cout<<"data: "<<buff<<endl; ///-----------------------------------------DATA------------------------------------- //要使用Csmtp 发送附件, 需要对Csmtp 头信息进行说明, 改变Content-type 及为每一段正文添加BOUNDARY 名, cout<< "-------------------DATA------------------------" <<endl; // 头 message= "from:" +user+ "\r\nto:" +target+ "\r\nsubject:" +title+ "\r\n" ; message += "MIME-Version: 1.0\r\n" ; message += "Content-Type: multipart/mixed;boundary=@boundary@\r\n\r\n" ; send(sockClient, message.c_str(), message.length(), 0); // 正文 message = "--@boundary@\r\nContent-Type: text/plain;charset=\"gb2312\"\r\n\r\n" +content+ "\r\n\r\n" ; send(sockClient, message.c_str(), message.length(), 0); //------------------------------------------------------------------------------------------------ // 发送附件 SendAttachment(sockClient); /*发送结尾信息*/ message = "--@boundary@--\r\n.\r\n" ; send(sockClient, message.c_str(), message.length(), 0); buff[recv(sockClient, buff, 500, 0)]= '\0' ; //cout<<"end_qwertyuiop:"<<buff<<endl; message= "QUIT\r\n" ; send(sockClient, message.c_str(), message.length(), 0); buff[recv(sockClient, buff, 500, 0)]= '\0' ; cout<< "Send mail is finish:" <<buff<<endl; return 0; } |
容易理解的简化版可以点击->这里
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/sinat_36219858/article/details/80439782