這篇文章主要介紹了C++實現郵件群發的方法,較為詳細的分析了郵件發送的原理與C++相關實現技巧,非常具有實用價值,需要的朋友可以參考下 本文實例講述了C++實現郵件群發的方法。分享給大家供大家參考。具體如下:關於生成隨機QQ郵箱不精確的問題,在之後版本打算另寫一個採集器插件進行帳號採集,所以,這個軟 ...
這篇文章主要介紹了C++實現郵件群發的方法,較為詳細的分析了郵件發送的原理與C++相關實現技巧,非常具有實用價值,需要的朋友可以參考下
本文實例講述了C++實現郵件群發的方法。分享給大家供大家參考。具體如下:
關於生成隨機QQ郵箱不精確的問題,在之後版本打算另寫一個採集器插件進行帳號採集,所以,這個軟體只用來進行內容發送,郵箱進行隨機生成
如果你已經有採集來的QQ號,請複製到SendList.txt 替換內容即可
可以直接複製HTML代碼到郵件內容,保存即可。目前郵件內容最大設置為10000位元組,如果有增大的必要,歡迎提交留言。
這是我學習後VC編程中涉及到多線程,socket,及一些WINDOWS API的宗合應用
使用說明:
一、SMTP設置
1、SMTP設置中,收件箱地址:填寫郵箱地址為帳號測試郵箱,可以填寫你自己的郵箱作為接收測試。打星號為必填。郵箱帳號及密碼,是即將用於群發的帳號和密碼
2、群發發送時間間隔,預設為零,可以選擇填寫發送間隔時間,單位為秒,防止多次快速發送相同內容被停用。
3、勾選郵件標題後插入系統時間,可以在標題上加上系統時間
4、導入群發列表,勾選後,可以點擊群發,暫停,繼續。(群發列表為程式目錄中SendList.txt)如果你有郵箱採集軟體,可以把彩集的郵箱地址按照格式,一行一個,放入其中),沒有的話,可以點擊“收件箱”頁面生成隨機QQ郵箱
二、郵件內容
1、填寫郵件標題,郵件內容可以為純文本,也可以是HTML代碼,附件目前只支持TXT文本。
2、群發前,請測試郵件內容,是否完整。附件是否正常接收。
三、收件箱
1、收件箱中順序生成QQ郵箱,請不要超過6位數QQ號,位數過大,生成時間過長,容易造成假死。
2、群發前,先生成QQ郵箱列表。如果你有採集郵箱帳號,可以按格式放入SendList.txt 中
版本更新說明:
1、可增加多個附件。
2、修複標題插入日期造成程式崩潰的BUG。
3、增加發送間隔時間選項。
4、支持HTML代碼
5、增加干預碼
1 #include "stdafx.h" 2 #include <windows.h> 3 #include <windowsx.h> 4 #include "Resource.h" 5 #include "TabDlg1.h" 6 #include "winsock2.h" 7 #define MAXSTRING 10000 8 static int flag=0; //標記是否群發 9 TCHAR* pTitle = NULL; //指向標題文件內容的指針 10 HANDLE hThread=NULL; //線程返回句柄 11 long i=0; //列表控制項“行”計數 12 static long sendNum=1; //發送郵件數量 13 #pragma comment(lib,"WSOCK32.LIB") 14 extern TCHAR tcRunPath[MAX_PATH]; //程式當前路徑目錄 15 extern TCHAR shortPath[MAX_PATH]; //文件路徑,TAB2中的全局變數 16 extern TCHAR titlePath[256]; //郵件標題文件路徑 17 extern TCHAR mtPath[256]; //郵件內容文件路徑 18 extern TCHAR sendListPath[MAX_PATH]; //發送列表文件路徑 19 extern BOOL attach; //是否添加了附件 20 extern TCHAR file[MAXSTRING]; //附件部份代碼 21 BOOL WINAPI TAB1_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 22 { 23 switch(uMsg) 24 { 25 HANDLE_MSG(hWnd, WM_INITDIALOG, TAB1_OnInitDialog); 26 HANDLE_MSG(hWnd, WM_COMMAND, TAB1_OnCommand); 27 HANDLE_MSG(hWnd,WM_CLOSE, TAB1_OnClose); 28 } 29 return FALSE; 30 } 31 BOOL TAB1_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam) 32 { 33 InitLVColumn(hwnd); 34 InitComboBox(hwnd); 35 return TRUE; 36 } 37 void TAB1_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) 38 { 39 IsChecked(hwnd); //判斷勾選框是否被勾選 40 IsRadioChecked(hwnd); //RADIO控制項是否被選擇 41 switch(id) 42 { 43 case IDC_MAIL_TEST: 44 { 45 if(IsDlgButtonChecked(hwnd,IDC_RADIO_QQ)!=BST_CHECKED && IsDlgButtonChecked(hwnd,IDC_RADIO_163)!=BST_CHECKED) 46 { 47 MessageBox(hwnd,TEXT("請選擇發QQ郵箱或163信箱"),"",MB_OK); 48 return; 49 } 50 else 51 { 52 flag=0; 53 hThread=CreateThread(NULL,0,ThreadFunc,hwnd,0,0); 54 } 55 } 56 break; 57 case IDC_BUTTON_START: 58 { 59 if(IsDlgButtonChecked(hwnd,IDC_RADIO_QQ)!=BST_CHECKED && IsDlgButtonChecked(hwnd,IDC_RADIO_163)!=BST_CHECKED) 60 { 61 MessageBox(hwnd,TEXT("請選擇發QQ郵箱或163信箱"),"",MB_OK); 62 return; 63 } 64 else 65 { 66 flag=1; 67 hThread=CreateThread(NULL,0,ThreadFunc,hwnd,0,0); 68 } 69 } 70 break; 71 case IDC_BUTTON_PAUSE: 72 { 73 if(NULL!=hThread) 74 { 75 SuspendThread(hThread); 76 } 77 else 78 { 79 return; 80 } 81 } 82 break; 83 case IDC_BUTTON_RESUME: 84 { 85 if(NULL!=hThread) 86 { 87 ResumeThread(hThread); 88 } 89 else 90 { 91 return; 92 } 93 } 94 break; 95 default: 96 break; 97 } 98 } 99 void TAB1_OnClose(HWND hwnd) 100 { 101 EndDialog(hwnd, 0); 102 } 103 int InitLVColumn(HWND hwnd) //列表初始化設置,視圖選為報表視圖 104 { 105 LVCOLUMN lvColumn; 106 MyLVColumn MyColumn[2] = {{TEXT("編號"), 0x30, LVCFMT_CENTER},{TEXT("郵箱帳號"), 0x99, LVCFMT_CENTER}}; 107 lvColumn.mask = LVCF_TEXT|LVCF_FMT|LVCF_WIDTH|LVCF_SUBITEM; 108 DWORD dwStyle =ListView_GetExtendedListViewStyle(GetDlgItem(hwnd, IDC_LIST)); //得到列表當前拓展風格 109 dwStyle |= LVS_EX_FULLROWSELECT; //選中某行使整行高亮(只適用與report風格的listctrl) 110 dwStyle |= LVS_EX_GRIDLINES; //網格線(只適用與report風格的listctrl) 111 // dwStyle |= LVS_EX_CHECKBOXES; //item前生成checkbox控制項 112 ListView_SetExtendedListViewStyle(GetDlgItem(hwnd, IDC_LIST),dwStyle); //設置列表擴展風格 113 for(int i = 0; i < 2; i++) 114 { 115 lvColumn.pszText = MyColumn[i].szColumnName; 116 lvColumn.cx = MyColumn[i].cx; 117 lvColumn.fmt = MyColumn[i].fmt; 118 SendDlgItemMessage(hwnd, IDC_LIST, LVM_INSERTCOLUMN, i, (LPARAM)&lvColumn); 119 } 120 121 return 0; 122 } 123 int InitComboBox(HWND hwnd)//視窗控制項初始化設置 124 { 125 HWND hwndCombo=GetDlgItem(hwnd,IDC_COMBO_SLEEPTIME); 126 ComboBox_InsertString(hwndCombo,-1,TEXT("0")); 127 ComboBox_InsertString(hwndCombo,-1,TEXT("1")); 128 ComboBox_InsertString(hwndCombo,-1,TEXT("2")); 129 ComboBox_InsertString(hwndCombo,-1,TEXT("5")); 130 ComboBox_InsertString(hwndCombo,-1,TEXT("10")); 131 ComboBox_InsertString(hwndCombo,-1,TEXT("20")); 132 ComboBox_SetText(hwndCombo,TEXT("0")); 133 SetDlgItemText(hwnd,IDC_EDIT_MAILADD,TEXT("[email protected]")); 134 ComboBox_InsertString(GetDlgItem(hwnd,IDC_COMBO_SMTP),0,TEXT("smtp.qq.com")); 135 ComboBox_InsertString(GetDlgItem(hwnd,IDC_COMBO_SMTP),1,TEXT("smtp.163.com")); 136 ComboBox_SetText(GetDlgItem(hwnd,IDC_COMBO_SMTP),TEXT("smtp.qq.com")); 137 SetDlgItemText(hwnd,IDC_EDIT_MAILPORT,TEXT("25")); 138 SetDlgItemText(hwnd,IDC_EDIT_USERNAME,TEXT("")); 139 140 return 1; 141 } 142 int IsChecked(HWND hwnd) //checkbox未選中的設置為只讀 143 { 144 if(IsDlgButtonChecked(hwnd,IDC_CHECK_QUNFA)!=BST_CHECKED) 145 { 146 EnableWindow(GetDlgItem(hwnd, IDC_BUTTON_START), false); 147 EnableWindow(GetDlgItem(hwnd, IDC_BUTTON_RESUME), false); 148 EnableWindow(GetDlgItem(hwnd, IDC_BUTTON_PAUSE), false); 149 return 0; 150 } 151 else 152 { 153 EnableWindow(GetDlgItem(hwnd, IDC_BUTTON_START), true); 154 EnableWindow(GetDlgItem(hwnd, IDC_BUTTON_RESUME), true); 155 EnableWindow(GetDlgItem(hwnd, IDC_BUTTON_PAUSE), true); 156 return 1; 157 } 158 return 0; 159 } 160 int IsRadioChecked(HWND hwnd) //RADIO控制項被選中,則設置相應的SMTP 地址 161 { 162 if(IsDlgButtonChecked(hwnd,IDC_RADIO_QQ)==BST_CHECKED) 163 { 164 ComboBox_SetText(GetDlgItem(hwnd,IDC_COMBO_SMTP),TEXT("smtp.qq.com")); 165 return 1; 166 } 167 if(IsDlgButtonChecked(hwnd,IDC_RADIO_163)==BST_CHECKED) 168 { 169 ComboBox_SetText(GetDlgItem(hwnd,IDC_COMBO_SMTP),TEXT("smtp.163.com")); 170 return 2; 171 } 172 return 0; 173 } 174 TCHAR* readText1(HWND hwnd) //讀取文件--郵件發送內容 175 { 176 int nLen = 0; 177 FILE *pF = fopen(titlePath , "r"); //打開文件 178 fseek(pF, 0, SEEK_END); //文件指針移到文件尾 179 nLen = ftell(pF); //得到當前指針位置, 即是文件的長度 180 rewind(pF); //文件指針恢復到文件頭位置 181 pTitle = (char*) malloc(sizeof(char)*nLen+1);//動態申請空間, 為保存字元串結尾標誌\0, 多申請一個字元的空間 182 if(!pTitle) 183 { 184 MessageBox(hwnd,TEXT("記憶體不夠!"),"錯誤",MB_ICONWARNING); 185 exit(0); 186 } 187 nLen = fread(pTitle, sizeof(char), nLen, pF); 188 pTitle[nLen] = '\0'; //添加字元串結尾標誌 189 if(IsDlgButtonChecked(hwnd,IDC_CHECK_TITLE)==BST_CHECKED) //是否勾選在郵件標題 加入系統當前時間 190 { 191 SYSTEMTIME stLocal; 192 GetLocalTime(&stLocal); //得到系統當前時間 193 TCHAR strTime[256]; 194 ZeroMemory(strTime,sizeof(strTime)/sizeof(TCHAR)); 195 wsprintf(strTime,"%04u-%02u-%02u %02u:%02u:%02u",stLocal.wYear,stLocal.wMonth,stLocal.wDay,stLocal.wHour,stLocal.wMinute,stLocal.wSecond); 196 strcat(pTitle,strTime); //在標題後加入系統時間 197 } 198 fclose(pF); //關閉文件 199 TCHAR* pText = NULL; 200 pF = fopen(mtPath , "r"); //打開文件 201 fseek(pF, 0, SEEK_END); 202 nLen = ftell(pF); 203 rewind(pF); 204 pText = (char*) malloc(sizeof(char)*nLen+1); //動態申請空間, 為保存字元串結尾標誌\0, 多申請一個字元的空間 205 if(!pText) 206 { 207 MessageBox(hwnd,TEXT("記憶體不夠!"),"錯誤",MB_ICONWARNING); 208 exit(0); 209 } 210 nLen = fread(pText, sizeof(char), nLen, pF); 211 pText[nLen] = '\0'; //添加字元串結尾標誌 212 fclose(pF); //關閉文件 213 TCHAR chText[MAXSTRING]; 214 TCHAR* encText=base64_encode(pText,strlen(pText)); 215 strcpy(chText,encText); //BASE64加密結果 216 free(encText); //釋放指針 217 free(pText); //釋放空間 218 return chText; 219 } 220 DWORD WINAPI ThreadFunc(LPVOID lpParam)//發郵件線程 221 { 222 HWND hwnd=(HWND)lpParam; 223 TCHAR userName[256]; //用戶帳號 224 TCHAR userPassWord[256]; //用戶密碼 225 GetDlgItemText(hwnd,IDC_EDIT_USERNAME,userName,sizeof(userName)/sizeof(TCHAR)); 226 GetDlgItemText(hwnd,IDC_EDIT_USERPASSWORD,userPassWord,sizeof(userPassWord)/sizeof(TCHAR)); 227 TCHAR *name=userName; 228 int i = 0; 229 int j = strlen(name); 230 TCHAR *encName = base64_encode(name, j); //給用戶名base64加密編碼 231 ZeroMemory(userName,sizeof(userName)/sizeof(TCHAR)); 232 wsprintf(userName,"%s\n", encName); //在加編碼後加入回車符 233 TCHAR *passWord=userPassWord; 234 int k = strlen(passWord); 235 TCHAR *encPassWord = base64_encode(passWord, k); //給用戶密碼base64加密編碼 236 // int len = strlen(enc); 237 // TCHAR *dec = base64_decode(enc, len); //反編 238 ZeroMemory(userPassWord,sizeof(userPassWord)/sizeof(TCHAR)); 239 wsprintf(userPassWord,"%s\n", encPassWord); 240 /*ZeroMemory(userName,sizeof(userName)/sizeof(TCHAR)); 241 wsprintf(userName,"\ndecoded : %s", dec); 242 MessageBox(hwnd,userName,"",MB_OK);*/ //反編譯用戶名,如果需要,可以把用戶名密碼反編後發到指定郵箱。 243 free(encName); //釋放指針 244 free(encPassWord); 245 //free(dec); 246 if(1==flag) //全局標記,點擊群發還是測試,1為群發,0為測試 247 { 248 HANDLE wFile; 249 int szId; 250 TCHAR ch; 251 TCHAR szState[256]; 252 strcpy(sendListPath,tcRunPath); 253 strcat(sendListPath,"\\SendList.txt"); //拼接全路徑及文件名 254 TCHAR *sFileName=sendListPath; 255 FILE *fp=fopen(sFileName,"r"); 256 if(fp==NULL) 257 { 258 return FALSE; //打開文件失敗,則返回,不讀取 259 } 260 fseek(fp, 0, SEEK_END); 261 int length = ftell(fp); //length為0,則是空的 262 rewind(fp); //把指針移迴文件頭部 還可以用 fseek(fp, 0, SEEK_SET);效果一樣 263 if(length==0) //判斷文件如果為空,則關閉文件,返回, 264 { 265 fclose(fp); //要關閉打開的文件,不然退出時,無法保存 266 return FALSE; 267 } 268 while(!feof(fp)) 269 { 270 fscanf(fp,"%s\r\n",szState); 271 SocketQ(hwnd,userName,userPassWord,szState); 272 TCHAR sTime[256]; 273 unsigned long iTime; 274 ComboBox_GetText(GetDlgItem(hwnd,IDC_COMBO_SLEEPTIME),sTime,sizeof(sTime)/sizeof(TCHAR)); 275 iTime=atoi(sTime); 276 iTime=iTime*1000; 277 Sleep(iTime); 278 } 279 fclose(fp); 280 } 281 else 282 { 283 Socket(hwnd,userName,userPassWord); 284 } 285 CloseHandle(hThread); 286 return 0; 287 } 288 void SocketQ(HWND hwnd,TCHAR userName[],TCHAR userPassWord[],TCHAR szState[])//傳入加密的用戶名跟密碼連接163 289 { 290 /******************************************************************* 291 使用Socket的程式在使用Socket之前必須調用WSAStartup函數。 292 該函數的第一個參數指明程式請求使用的Socket版本, 293 其中高位位元組指明副版本、低位位元組指明主版本; 294 操作系統利用第二個參數返回請求的Socket的版本信息。 295 當一個應用程式調用WSAStartup函數時,操作系統根據請求的Socket版本來搜索相應的Socket庫, 296 然後綁定找到的Socket庫到該應用程式中。 297 以後應用程式就可以調用所請求的Socket庫中的其它Socket函數了。 298 該函數執行成功後返回0。 299 *****************************************************************/ 300 TCHAR* pText; 301 pText = readText1(hwnd); 302 int WSA_return; 303 WSADATA wsaData; 304 WSA_return=WSAStartup(MAKEWORD(2,0),&wsaData); //初始化Socket庫 305 SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//創建SOCKET 306 hostent* host = NULL; 307 SOCKADDR_IN sa; 308 sa.sin_family=AF_INET; //設置電線連接伺服器端的埠 309 TCHAR cPort[100]; 310 GetDlgItemText(hwnd,IDC_EDIT_MAILPORT,cPort,sizeof(cPort)/sizeof(TCHAR)); 311 int iPort=atoi(cPort); 312 sa.sin_port = htons(iPort); 313 //sa.sin_addr.S_un.S_addr = inet_addr("123.58.178.203");//可以寫死IP地址 314 HOSTENT *host_entry; //存放主機功能變數名稱,如smtp.qq.com 315 TCHAR host_name[256]=""; 316 ZeroMemory(host_name,sizeof(host_name)/sizeof(TCHAR)); 317 ComboBox_GetText(GetDlgItem(hwnd,IDC_COMBO_SMTP),host_name,sizeof(host_name)/sizeof(TCHAR)); 318 TCHAR str_ipAdd[256]; 319 if(WSA_return==0) 320 { 321 host_entry=gethostbyname(host_name); // 要解析的功能變數名稱或主機名 322 if(host_entry!=NULL) 323 { 324 wsprintf(str_ipAdd,"%d.%d.%d.%d", 325 (host_entry->h_addr_list[0][0]&0x00ff), 326 (host_entry->h_addr_list[0][1]&0x00ff), 327 (host_entry->h_addr_list[0][2]&0x00ff), 328 (host_entry->h_addr_list[0][3]&0x00ff)); 329 330 } 331 } 332 sa.sin_addr.S_un.S_addr = inet_addr(str_ipAdd); //得到功能變數名稱IP地址 333 if(connect(sock,(SOCKADDR *)&sa,sizeof(sa))==SOCKET_ERROR) 334 { 335 ShowError(); 336 return; 337 } 338 TCHAR buffer[256]; //對話過程 339 ZeroMemory(buffer,sizeof(buffer)/sizeof(TCHAR)); 340 int iRet=recv(sock,buffer,256,0); //接收問候語 341 if(SOCKET_ERROR==iRet) 342 { 343 ShowError(); 344 return; 345 } 346 TCHAR Hello[] = "HELO SMTP\r\n"; //註意不能忘了末尾的回車 347 send(sock,Hello,lstrlen(Hello),0); 348 ZeroMemory(buffer,sizeof(buffer)/sizeof(TCHAR)); 349 iRet=recv(sock,buffer,256,0); 350 if(SOCKET_ERROR==iRet) 351 { 352 ShowError(); 353 return; 354 } 355 TCHAR Ehlo[] = "EHLO SMTP\r\n"; 356 send(sock,Ehlo,lstrlen(Ehlo),0); 357 ZeroMemory(buffer,sizeof(buffer)/sizeof(TCHAR)); 358 iRet=recv(sock,buffer,256,0); 359 if(SOCKET_ERROR==iRet) 360 { 361 ShowError(); 362 return; 363 } 364 TCHAR login[] = "AUTH LOGIN\r\n"; //登陸命令 365 send(sock,login,lstrlen(login),0); 366 ZeroMemory(buffer,sizeof(buffer)/sizeof(TCHAR)); 367 iRet=recv(sock,buffer,256,0); 368 if(SOCKET_ERROR==iRet) 369 { 370 ShowError(); 371 return; 372 } 373 if(IsDlgButtonChecked(hwnd,IDC_RADIO_QQ)==BST_CHECKED) 374 { 375 strcat(userName,"\r\n"); 376 send(sock,userName,lstrlen(userName),0); //發送加密的用戶名 377 ZeroMemory(buffer,sizeof(buffer)/sizeof(TCHAR)); 378 iRet=recv(sock,buffer,256,0); 379 if(SOCKET_ERROR==iRet) 380 { 381 ShowError(); 382 return; 383 } 384 strcat(userPassWord,"\r\n"); 385 send(sock,userPassWord,lstrlen(userPassWord),0); //發送加密的密碼 386 ZeroMemory(buffer,sizeof(buffer)/sizeof(TCHAR)); 387 iRet=recv(sock,buffer,256,0); 388 if(SOCKET_ERROR==iRet) 389 { 390 ShowError(); 391 return; 392 } 393 } 394 if(IsDlgButtonChecked(hwnd,IDC_RADIO_163)==BST_CHECKED) 395 { 396 send(sock,userName,lstrlen(userName),0); //發送加密的用戶名 397 ZeroMemory(buffer,sizeof(buffer)/sizeof(TCHAR)); 398 iRet=recv(sock,buffer,256,0); 399 if(SOCKET_ERROR==iRet) 400 { 401 ShowError(); 402 return; 403 } 404 send(sock,userPassWord,lstrlen(userPassWord),