C++实现邮件群发的方法
本篇章节讲解C++实现邮件群发的方法。分享给大家供大家参考。具体如下: 如果你已经有采集来的QQ号,请复制到SendList.txt 替换内容即可 这是我学习后VC编程中涉及到多线程,socket,及一些WINDOWS API的宗合应用 一、SMTP设置 1、SMTP设置中,收件箱地址:填写邮箱地址为帐号测试邮箱,可以填写你自己的邮箱作为接收测试。打星号为必填。邮箱帐号及密码,是即将用于群发的帐号和密码 二、邮件内容 1、填写邮件标题,邮件内容可以为纯文本,也可以是HTML代码,附件目前只支持TXT文本。 三、收件箱 1、收件箱中顺序生成QQ邮箱,请不要超过6位数QQ号,位数过大,生成时间过长,容易造成假死。 版本更新说明: 1、可增加多个附件。 #include "stdafx.h" #include <windows.h> #include <windowsx.h> #include "Resource.h" #include "TabDlg1.h" #include "winsock2.h" #define MAXSTRING 10000 static int flag=0; //标记是否群发 TCHAR* pTitle = NULL; //指向标题文件内容的指针 HANDLE hThread=NULL; //线程返回句柄 long i=0; //列表控件“行”计数 static long sendNum=1; //发送邮件数量 #pragma comment(lib,"WSOCK32.LIB") extern TCHAR tcRunPath[MAX_PATH]; //程序当前路径目录 extern TCHAR shortPath[MAX_PATH]; //文件路径,TAB2中的全局变量 extern TCHAR titlePath[256]; //邮件标题文件路径 extern TCHAR mtPath[256]; //邮件内容文件路径 extern TCHAR sendListPath[MAX_PATH]; //发送列表文件路径 extern BOOL attach; //是否添加了附件 extern TCHAR file[MAXSTRING]; //附件部份代码 BOOL WINAPI TAB1_Proc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) { switch(uMsg) { HANDLE_MSG(hWnd,WM_INITDIALOG,TAB1_OnInitDialog); HANDLE_MSG(hWnd,WM_COMMAND,TAB1_OnCommand); HANDLE_MSG(hWnd,WM_CLOSE,TAB1_OnClose); } return FALSE; } BOOL TAB1_OnInitDialog(HWND hwnd,HWND hwndFocus,LPARAM lParam) { InitLVColumn(hwnd); InitComboBox(hwnd); return TRUE; } void TAB1_OnCommand(HWND hwnd,int id,HWND hwndCtl,UINT codeNotify) { IsChecked(hwnd); //判断勾选框是否被勾选 IsRadioChecked(hwnd); //RADIO控件是否被选择 switch(id) { case IDC_MAIL_TEST: { if(IsDlgButtonChecked(hwnd,IDC_RADIO_QQ)!=BST_CHECKED && IsDlgButtonChecked(hwnd,IDC_RADIO_163)!=BST_CHECKED) { MessageBox(hwnd,TEXT("请选择发QQ邮箱或163信箱"),"",MB_OK); return; } else { flag=0; hThread=CreateThread(NULL,ThreadFunc,hwnd,0); } } break; case IDC_BUTTON_START: { if(IsDlgButtonChecked(hwnd,MB_OK); return; } else { flag=1; hThread=CreateThread(NULL,0); } } break; case IDC_BUTTON_PAUSE: { if(NULL!=hThread) { SuspendThread(hThread); } else { return; } } break; case IDC_BUTTON_RESUME: { if(NULL!=hThread) { ResumeThread(hThread); } else { return; } } break; default: break; } } void TAB1_OnClose(HWND hwnd) { EndDialog(hwnd,0); } int InitLVColumn(HWND hwnd) //列表初始化设置,视图选为报表视图 { LVCOLUMN lvColumn; MyLVColumn MyColumn[2] = {{TEXT("编号"),0x30,LVCFMT_CENTER},{TEXT("邮箱帐号"),0x99,LVCFMT_CENTER}}; lvColumn.mask = LVCF_TEXT|LVCF_FMT|LVCF_WIDTH|LVCF_SUBITEM; DWORD dwStyle =ListView_GetExtendedListViewStyle(GetDlgItem(hwnd,IDC_LIST)); //得到列表当前拓展风格 dwStyle |= LVS_EX_FULLROWSELECT; //选中某行使整行高亮(只适用与report风格的listctrl) dwStyle |= LVS_EX_GRIDLINES; //网格线(只适用与report风格的listctrl) // dwStyle |= LVS_EX_CHECKBOXES; //item前生成checkbox控件 ListView_SetExtendedListViewStyle(GetDlgItem(hwnd,IDC_LIST),dwStyle); //设置列表扩展风格 for(int i = 0; i < 2; i++) { lvColumn.pszText = MyColumn[i].szColumnName; lvColumn.cx = MyColumn[i].cx; lvColumn.fmt = MyColumn[i].fmt; SendDlgItemMessage(hwnd,IDC_LIST,LVM_INSERTCOLUMN,i,(LPARAM)&lvColumn); } return 0; } int InitComboBox(HWND hwnd)//窗口控件初始化设置 { HWND hwndCombo=GetDlgItem(hwnd,IDC_COMBO_SLEEPTIME); ComboBox_InsertString(hwndCombo,-1,TEXT("0")); ComboBox_InsertString(hwndCombo,TEXT("1")); ComboBox_InsertString(hwndCombo,TEXT("2")); ComboBox_InsertString(hwndCombo,TEXT("5")); ComboBox_InsertString(hwndCombo,TEXT("10")); ComboBox_InsertString(hwndCombo,TEXT("20")); ComboBox_SetText(hwndCombo,TEXT("0")); SetDlgItemText(hwnd,IDC_EDIT_MAILADD,TEXT("12345678@qq.com")); ComboBox_InsertString(GetDlgItem(hwnd,IDC_COMBO_SMTP),TEXT("smtp.qq.com")); ComboBox_InsertString(GetDlgItem(hwnd,1,TEXT("smtp.163.com")); ComboBox_SetText(GetDlgItem(hwnd,TEXT("smtp.qq.com")); SetDlgItemText(hwnd,IDC_EDIT_MAILPORT,TEXT("25")); SetDlgItemText(hwnd,IDC_EDIT_USERNAME,TEXT("")); return 1; } int IsChecked(HWND hwnd) //checkbox未选中的设置为只读 { if(IsDlgButtonChecked(hwnd,IDC_CHECK_QUNFA)!=BST_CHECKED) { EnableWindow(GetDlgItem(hwnd,IDC_BUTTON_START),false); EnableWindow(GetDlgItem(hwnd,IDC_BUTTON_RESUME),IDC_BUTTON_PAUSE),false); return 0; } else { EnableWindow(GetDlgItem(hwnd,true); EnableWindow(GetDlgItem(hwnd,true); return 1; } return 0; } int IsRadioChecked(HWND hwnd) //RADIO控件被选中,则设置相应的SMTP 地址 { if(IsDlgButtonChecked(hwnd,IDC_RADIO_QQ)==BST_CHECKED) { ComboBox_SetText(GetDlgItem(hwnd,TEXT("smtp.qq.com")); return 1; } if(IsDlgButtonChecked(hwnd,IDC_RADIO_163)==BST_CHECKED) { ComboBox_SetText(GetDlgItem(hwnd,TEXT("smtp.163.com")); return 2; } return 0; } TCHAR* readText1(HWND hwnd) //读取文件--邮件发送内容 { int nLen = 0; FILE *pF = fopen(titlePath,"r"); //打开文件 fseek(pF,SEEK_END); //文件指针移到文件尾 nLen = ftell(pF); //得到当前指针位置,即是文件的长度 rewind(pF); //文件指针恢复到文件头位置 pTitle = (char*) malloc(sizeof(char)*nLen+1);//动态申请空间,为保存字符串结尾标志 ,多申请一个字符的空间 if(!pTitle) { MessageBox(hwnd,TEXT("内存不够!"),"错误",MB_ICONWARNING); exit(0); } nLen = fread(pTitle,sizeof(char),nLen,pF); pTitle[nLen] = ' '; //添加字符串结尾标志 if(IsDlgButtonChecked(hwnd,IDC_CHECK_TITLE)==BST_CHECKED) //是否勾选在邮件标题 加入系统当前时间 { SYSTEMTIME stLocal; GetLocalTime(&stLocal); //得到系统当前时间 TCHAR strTime[256]; ZeroMemory(strTime,sizeof(strTime)/sizeof(TCHAR)); wsprintf(strTime,"%04u-%02u-%02u %02u:%02u:%02u",stLocal.wYear,stLocal.wMonth,stLocal.wDay,stLocal.wHour,stLocal.wMinute,stLocal.wSecond); strcat(pTitle,strTime); //在标题后加入系统时间 } fclose(pF); //关闭文件 TCHAR* pText = NULL; pF = fopen(mtPath,SEEK_END); nLen = ftell(pF); rewind(pF); pText = (char*) malloc(sizeof(char)*nLen+1); //动态申请空间,多申请一个字符的空间 if(!pText) { MessageBox(hwnd,MB_ICONWARNING); exit(0); } nLen = fread(pText,pF); pText[nLen] = ' '; //添加字符串结尾标志 fclose(pF); //关闭文件 TCHAR chText[MAXSTRING]; TCHAR* encText=base64_encode(pText,strlen(pText)); strcpy(chText,encText); //BASE64加密结果 free(encText); //释放指针 free(pText); //释放空间 return chText; } DWORD WINAPI ThreadFunc(LPVOID lpParam)//发邮件线程 { HWND hwnd=(HWND)lpParam; TCHAR userName[256]; //用户帐号 TCHAR userPassWord[256]; //用户密码 GetDlgItemText(hwnd,userName,sizeof(userName)/sizeof(TCHAR)); GetDlgItemText(hwnd,IDC_EDIT_USERPASSWORD,userPassWord,sizeof(userPassWord)/sizeof(TCHAR)); TCHAR *name=userName; int i = 0; int j = strlen(name); TCHAR *encName = base64_encode(name,j); //给用户名base64加密编码 ZeroMemory(userName,sizeof(userName)/sizeof(TCHAR)); wsprintf(userName,"%sn",encName); //在加编码后加入回车符 TCHAR *passWord=userPassWord; int k = strlen(passWord); TCHAR *encPassWord = base64_encode(passWord,k); //给用户密码base64加密编码 // int len = strlen(enc); // TCHAR *dec = base64_decode(enc,len); //反编 ZeroMemory(userPassWord,sizeof(userPassWord)/sizeof(TCHAR)); wsprintf(userPassWord,encPassWord); /*ZeroMemory(userName,"ndecoded : %s",dec); MessageBox(hwnd,MB_OK);*/ //反编译用户名,如果需要,可以把用户名密码反编后发到指定邮箱。 free(encName); //释放指针 free(encPassWord); //free(dec); if(1==flag) //全局标记,点击群发还是测试,1为群发,0为测试 { HANDLE wFile; int szId; TCHAR ch; TCHAR szState[256]; strcpy(sendListPath,tcRunPath); strcat(sendListPath,"SendList.txt"); //拼接全路径及文件名 TCHAR *sFileName=sendListPath; FILE *fp=fopen(sFileName,"r"); if(fp==NULL) { return FALSE; //打开文件失败,则返回,不读取 } fseek(fp,SEEK_END); int length = ftell(fp); //length为0,则是空的 rewind(fp); //把指针移回文件头部 还可以用 fseek(fp,SEEK_SET);效果一样 if(length==0) //判断文件如果为空,则关闭文件,返回, { fclose(fp); //要关闭打开的文件,不然退出时,无法保存 return FALSE; } while(!feof(fp)) { fscanf(fp,"%srn",szState); SocketQ(hwnd,szState); TCHAR sTime[256]; unsigned long iTime; ComboBox_GetText(GetDlgItem(hwnd,IDC_COMBO_SLEEPTIME),sTime,sizeof(sTime)/sizeof(TCHAR)); iTime=atoi(sTime); iTime=iTime*1000; Sleep(iTime); } fclose(fp); } else { Socket(hwnd,userPassWord); } CloseHandle(hThread); return 0; } void SocketQ(HWND hwnd,TCHAR userName[],TCHAR userPassWord[],TCHAR szState[])//传入加密的用户名跟密码连接163 { /******************************************************************* 使用Socket的程序在使用Socket之前必须调用WSAStartup函数。 该函数的第一个参数指明程序请求使用的Socket版本, 其中高位字节指明副版本、低位字节指明主版本; 操作系统利用第二个参数返回请求的Socket的版本信息。 当一个应用程序调用WSAStartup函数时,操作系统根据请求的Socket版本来搜索相应的Socket库, 然后绑定找到的Socket库到该应用程序中。 以后应用程序就可以调用所请求的Socket库中的其它Socket函数了。 该函数执行成功后返回0。 *****************************************************************/ TCHAR* pText; pText = readText1(hwnd); int WSA_return; WSADATA wsaData; WSA_return=WSAStartup(MAKEWORD(2,0),&wsaData); //初始化Socket库 SOCKET sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//创建SOCKET hostent* host = NULL; SOCKADDR_IN sa; sa.sin_family=AF_INET; //设置电线连接服务器端的端口 TCHAR cPort[100]; GetDlgItemText(hwnd,cPort,sizeof(cPort)/sizeof(TCHAR)); int iPort=atoi(cPort); sa.sin_port = htons(iPort); //sa.sin_addr.S_un.S_addr = inet_addr("123.58.178.203");//可以写死IP地址 HOSTENT *host_entry; //存放主机域名,如smtp.qq.com TCHAR host_name[256]=""; ZeroMemory(host_name,sizeof(host_name)/sizeof(TCHAR)); ComboBox_GetText(GetDlgItem(hwnd,host_name,sizeof(host_name)/sizeof(TCHAR)); TCHAR str_ipAdd[256]; if(WSA_return==0) { host_entry=gethostbyname(host_name); // 要解析的域名或主机名 if(host_entry!=NULL) { wsprintf(str_ipAdd,"%d.%d.%d.%d",(host_entry->h_addr_list[0][0]&0x00ff),(host_entry->h_addr_list[0][1]&0x00ff),(host_entry->h_addr_list[0][2]&0x00ff),(host_entry->h_addr_list[0][3]&0x00ff)); } } sa.sin_addr.S_un.S_addr = inet_addr(str_ipAdd); //得到域名IP地址 if(connect(sock,(SOCKADDR *)&sa,sizeof(sa))==SOCKET_ERROR) { ShowError(); return; } TCHAR buffer[256]; //对话过程 ZeroMemory(buffer,sizeof(buffer)/sizeof(TCHAR)); int iRet=recv(sock,buffer,256,0); //接收问候语 if(SOCKET_ERROR==iRet) { ShowError(); return; } TCHAR Hello[] = "HELO SMTPrn"; //注意不能忘了末尾的回车 send(sock,Hello,lstrlen(Hello),0); ZeroMemory(buffer,sizeof(buffer)/sizeof(TCHAR)); iRet=recv(sock,0); if(SOCKET_ERROR==iRet) { ShowError(); return; } TCHAR Ehlo[] = "EHLO SMTPrn"; send(sock,Ehlo,lstrlen(Ehlo),0); if(SOCKET_ERROR==iRet) { ShowError(); return; } TCHAR login[] = "AUTH LOGINrn"; //登陆命令 send(sock,login,lstrlen(login),0); if(SOCKET_ERROR==iRet) { ShowError(); return; } if(IsDlgButtonChecked(hwnd,IDC_RADIO_QQ)==BST_CHECKED) { strcat(userName,"rn"); send(sock,lstrlen(userName),0); //发送加密的用户名 ZeroMemory(buffer,sizeof(buffer)/sizeof(TCHAR)); iRet=recv(sock,0); if(SOCKET_ERROR==iRet) { ShowError(); return; } strcat(userPassWord,lstrlen(userPassWord),0); //发送加密的密码 ZeroMemory(buffer,0); if(SOCKET_ERROR==iRet) { ShowError(); return; } } if(IsDlgButtonChecked(hwnd,IDC_RADIO_163)==BST_CHECKED) { send(sock,0); if(SOCKET_ERROR==iRet) { ShowError(); return; } send(sock,0); if(SOCKET_ERROR==iRet) { ShowError(); return; } } TCHAR userF[256]; TCHAR userL[256]; TCHAR temp[256]; GetDlgItemText(hwnd,userF,sizeof(userF)/sizeof(TCHAR)); ComboBox_GetText(GetDlgItem(hwnd,temp,sizeof(host_name)/sizeof(TCHAR)); strcat(userF,"@"); strncpy(userL,temp+5,sizeof(userL)); strcat(userF,userL); TCHAR mailFrom[256]; //MessageBox(hwnd,MB_OK); wsprintf(mailFrom,TEXT("MAIL FROM:<%s>rn"),userF); send(sock,mailFrom,lstrlen(mailFrom),0); ZeroMemory(buffer,0); if(SOCKET_ERROR==iRet) { ShowError(); return; } TCHAR mailTo[256]; wsprintf(mailTo,TEXT("RCPT TO:<%s>rn"),szState); send(sock,mailTo,lstrlen(mailTo),0); ZeroMemory(buffer,0); if(SOCKET_ERROR==iRet) { ShowError(); return; } TCHAR dataCommad[]="DATArn"; send(sock,dataCommad,lstrlen(dataCommad),0); if(SOCKET_ERROR==iRet) { ShowError(); return; } //下面是发送正文及附件部份 TCHAR data[50000]; TCHAR SetMailHead[1024]; //邮件头部信息 wsprintf(SetMailHead,TEXT("To:%srnFrom:%srnSubject: %srn" "Date:2012-8-24rnX-Mailer:Kevin's mailerrnMIME-Version:1.0rn" "Content-Type: multipart/mixed;rn" " boundary="----=_NextPart_5039E410_D41071F0_120ABDFB";rn" "This is a multi-part message in MIME format.rnrn" "------=_NextPart_5039E410_D41071F0_120ABDFBrn" "Content-Type: multipart/alternative;rn" " boundary="----=_NextPart_5039E410_D41071F0_53510C95";rnrn" "------=_NextPart_5039E410_D41071F0_53510C95rn" "Content-Type: text/plain;r charset="gb2312"rn" "Content-Transfer-Encoding: base64rnrn"),szState,pTitle); strcat(SetMailHead,pText); //邮件头部再加上正文文本内容 strcat(SetMailHead,TEXT("rnrn")); strcpy(data,SetMailHead); TCHAR SetMailHtml[1024]; //邮件HTML代码部份 wsprintf(SetMailHtml,TEXT("------=_NextPart_5039E410_D41071F0_53510C95rn" "Content-Type: text/html;rn" " charset="gb2312"rn" "Content-Transfer-Encoding: base64rnrn")); strcat(SetMailHtml,pText); //加入邮件内容 strcat(SetMailHtml,TEXT("rnrn------=_NextPart_5039E410_D41071F0_53510C95--rnrn")); strcat(data,SetMailHtml); if(TRUE==attach) //判断是否添加了附件路径 { strcat(data,file); //加入附件部份代码 strcat(data,TEXT("------=_NextPart_5039E410_D41071F0_120ABDFB--rn")); } send(sock,data,lstrlen(data),0); TCHAR cN[]="rn.rn"; //邮件结束标志 send(sock,cN,lstrlen(cN),0); if(SOCKET_ERROR==iRet) { ShowError(); return; } TCHAR cQuit[] = "QUITrn"; //退出命令 send(sock,cQuit,lstrlen(cQuit),0); TCHAR cNum[256]; if(SOCKET_ERROR==iRet) { ShowError(); return; } else { TCHAR str[256]; //输出已发送列表 wsprintf(str,"%i",sendNum); LVITEM lvItem; lvItem.mask = LVIF_TEXT; lvItem.iSubItem = 0; int ItemCount = ListView_GetItemCount(GetDlgItem(hwnd,IDC_LIST)); lvItem.iItem = ItemCount; lvItem.pszText = str; SendDlgItemMessage(hwnd,LVM_INSERTITEM,(LPARAM)&lvItem); ListView_SetItemText(GetDlgItem(hwnd,i++,szState); sendNum++; } free(pTitle); //释放空间 closesocket(sock); //关闭SOCKET WSACleanup(); return; } void Socket(HWND hwnd,TCHAR userPassWord[])//传入加密的用户名跟密码连接163 { TCHAR* pText; pText = readText1(hwnd); int WSA_return; WSADATA wsaData; WSA_return=WSAStartup(MAKEWORD(2,&wsaData);//初始化Socket库 SOCKET sock = socket(AF_INET,IPPROTO_TCP); hostent* host = NULL; SOCKADDR_IN sa; sa.sin_family=AF_INET; //设置电线连接服务器端的端口 TCHAR cPort[100]; GetDlgItemText(hwnd,sizeof(cPort)/sizeof(TCHAR)); int iPort=atoi(cPort); sa.sin_port = htons(iPort); HOSTENT *host_entry; TCHAR host_name[256]=""; ZeroMemory(host_name,sizeof(host_name)/sizeof(TCHAR)); TCHAR str_ipAdd[256]; if(WSA_return==0) { host_entry=gethostbyname(host_name); // 即要解析的域名或主机名 if(host_entry!=NULL) { wsprintf(str_ipAdd,(host_entry->h_addr_list[0][3]&0x00ff)); } } sa.sin_addr.S_un.S_addr = inet_addr(str_ipAdd); if(connect(sock,sizeof(sa))==SOCKET_ERROR) { ShowError(); return; } TCHAR buffer[256]; //对话过程 ZeroMemory(buffer,sizeof(buffer)/sizeof(TCHAR)); int iRet=recv(sock,0); //接收问候语 if(SOCKET_ERROR==iRet) { ShowError(); return; } TCHAR Hello[] = "HELO SMTPrn"; //注意不能忘了末尾的回车 send(sock,0); if(SOCKET_ERROR==iRet) { ShowError(); return; } TCHAR mailAdd[256]; GetDlgItemText(hwnd,mailAdd,sizeof(mailAdd)/sizeof(TCHAR)); TCHAR mailTo[256]; wsprintf(mailTo,mailAdd); send(sock,pText); //邮件头部再加上正文文本内容 strcat(SetMailHead,SetMailHead); TCHAR SetMailHtml[1024]; //邮件HTML代码部份 wsprintf(SetMailHtml,pText); //加入邮件内容 strcat(SetMailHtml,SetMailHtml); if(TRUE==attach) //判断是否添加了附件路径 { strcat(data,file); //加入附件部份代码 strcat(data,0); TCHAR cN[]="rn.rn"; //邮件结束标志 send(sock,0); if(SOCKET_ERROR==iRet) { ShowError(); return; } TCHAR cQuit[] = "QUITrn"; //退出命令 send(sock,0); TCHAR cNum[256]; if(SOCKET_ERROR==iRet) { ShowError(); return; } else { MessageBox(hwnd,TEXT("测试发送成功"),TEXT("恭喜"),MB_OK); } free(pTitle); //释放空间 closesocket(sock); //关闭SOCK WSACleanup(); return; } void ShowError() { TCHAR* lpMsgBuf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER| //自动分配消息缓冲区 FORMAT_MESSAGE_FROM_SYSTEM,//从系统获取信息 NULL,GetLastError(),//获取错误信息标识 MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),//使用系统缺省语言 (LPTSTR)&lpMsgBuf,//消息缓冲区 0,NULL); MessageBox(NULL,lpMsgBuf,MB_ICONERROR); } 希望本文所述对大家的C++程序设计有所帮助。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |