编写SMTP协议邮箱发信(QQ邮箱为例)
語言:C/C++ 編程軟件:VS2015 字符集:ASCII碼 主要使用:Winsock套接字庫 了解E-Mail協議:http://blog.csdn.net/aaron133/article/details/78365503 POP3郵箱收信(163郵箱為例):http://blog.csdn.net/aaron133/article/details/78413701
說明:這里拿QQ郵箱做為例子,其他126、163郵箱也一樣可以,大同小異。
首先你要知道QQ提供的用于管理郵箱SMTP服務器監聽端口和服務器域名或IP地址。
一、如何查詢QQ的SMTP服務器:
QQ提供的SMTP服務器:http://service.mail.qq.com/cgi-bin/help?subtype=1&&id=28&&no=167
從上面可以知道:
SMTP服務器:smtp.qq.com
監聽端口號:465、587.(使用25端口也行)
二、打開QQ郵箱的SMTP/POP3服務:
打開QQ郵箱-->設置-->賬戶-->找到以下選項:
POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服務
點擊開啟“POP3/SMTP服務”選項.
這時,QQ會提供一個字符串密鑰(如:QKBE?KQQW UDVC BJAB),這個密鑰充當著登錄密碼的作用.
如果你獲取密鑰后,修改了QQ密碼,那么密鑰會無效,那就要重新獲取.
如果你早已打開了該SMTP服務,但沒有密鑰,關閉重新打開服務.
得到密鑰:QKBE?KQQW UDVC BJAB ?實際使用密鑰時:qkbekqqwudvcbjab
三、上傳QQ賬戶和密鑰時,要轉換成“Base64編碼”再上傳給QQ的SMTP服務器:
(關于Base64編碼的概念:http://blog.csdn.net/aaron133/article/details/78352525)
使用以下的EncodeBase64函數即可將它們轉換成Base64編碼:
struct Base64Date6 ? ? { ? ?unsigned int d4 : 6; ? ? ?unsigned int d3 : 6; ? ?unsigned int d2 : 6; ? ?unsigned int d1 : 6; ? ? }; ? ? //轉換為Base64編碼函數 void EncodeBase64(char *dbuf, char *buf128, int len) { //參數1:接收新Base64編碼的緩沖區 參數2:要轉換的字符串緩沖區 參數3:要轉換的字符串長度struct Base64Date6 *ddd = NULL; int i = 0; char buf[256] = { 0 }; char *tmp = NULL; char cc = '\0'; memset(buf, 0, 256); strcpy_s(buf, 256, buf128); for (i = 1; i <= len / 3; i++) { tmp = buf + (i - 1) * 3; cc = tmp[2]; tmp[2] = tmp[0]; tmp[0] = cc; ddd = (struct Base64Date6 *)tmp; dbuf[(i - 1) * 4 + 0] = ConvertToBase64((unsigned int)ddd->d1); dbuf[(i - 1) * 4 + 1] = ConvertToBase64((unsigned int)ddd->d2); dbuf[(i - 1) * 4 + 2] = ConvertToBase64((unsigned int)ddd->d3); dbuf[(i - 1) * 4 + 3] = ConvertToBase64((unsigned int)ddd->d4); } if (len % 3 == 1) { tmp = buf + (i - 1) * 3; cc = tmp[2]; tmp[2] = tmp[0]; tmp[0] = cc; ddd = (struct Base64Date6 *)tmp; dbuf[(i - 1) * 4 + 0] = ConvertToBase64((unsigned int)ddd->d1); dbuf[(i - 1) * 4 + 1] = ConvertToBase64((unsigned int)ddd->d2); dbuf[(i - 1) * 4 + 2] = '='; dbuf[(i - 1) * 4 + 3] = '='; } if (len % 3 == 2) { tmp = buf + (i - 1) * 3; cc = tmp[2]; tmp[2] = tmp[0]; tmp[0] = cc; ddd = (struct Base64Date6 *)tmp; dbuf[(i - 1) * 4 + 0] = ConvertToBase64((unsigned int)ddd->d1); dbuf[(i - 1) * 4 + 1] = ConvertToBase64((unsigned int)ddd->d2); dbuf[(i - 1) * 4 + 2] = ConvertToBase64((unsigned int)ddd->d3); dbuf[(i - 1) * 4 + 3] = '='; } return; } //輔助計算的函數 char ConvertToBase64(char uc) { if (uc < 26) { return 'A' + uc; } if (uc < 52) { return 'a' + (uc - 26); } if (uc < 62) { return '0' + (uc - 52); } if (uc == 62) { return '+'; } return '/'; }
四、開始編寫:
通信步驟:
1、連接QQ的SMTP服務器 ?//2開始,每一個命令都要接收一個服務器響應碼
2、編輯郵件內容和標題格式:
? ?From:<發件人>\r\n(只是用于顯示)
? ?To:<收件人>\r\n(以;分割,只是用于顯示)
? ?Subject:主題\r\n\r\n"
? ?內容
3、發送EHLO命令標明身份
4、發送STARTTLS命令標明使用安全傳輸層協議(TLS)
5、發送AUTH LOGIN命令使用郵箱登錄
6、上傳QQ賬號和郵箱密鑰(Base64編碼)
7、發送MAIL FROM命令指定發件人,就是當前QQ郵箱.
8、發送RCPT TO命令指定一個或多個收件人
9、發送DATA命令準備開始發送郵件內容
10、發送內容,內容以\r\n.\r\n結束
11、發送QUIT命令退出
頭文件:
#pragma once #include <Windows.h> #include <stdio.h> #include <stdlib.h> #include <iostream> using namespace std; #pragma comment(lib, "Ws2_32.lib")源文件:
#include "頭文件" //將要發送的郵件內容 (這里的From和To只用于在郵件上顯示的) char EmailContents[] = "From:<3093575@qq.com>\r\n" //這里只是說明發件人(QQ會檢查,標記為垃圾郵件而發送失敗) "To:<109333576@qq.com>;<519194462@qq.com>\r\n" //這里只是說明收件人(可以亂填的) "Subject:第一封測試郵件\r\n\r\n" //郵件標題 "Hello World, Hello Email!"; //郵件內容 //上面的EncodeBase64函數這里就不列出來了 //上面的ConvertToBase64函數這里就不列出來了 int main() { system("color 4e"); char buf[1500]; char login[128]; char pass[128]; ZeroMemory(buf, 1500); ZeroMemory(login, 128); ZeroMemory(pass, 128); //加載Winsock庫 WSADATA WSAData; WSAStartup(MAKEWORD(2, 2), &WSAData); //創建TCP套接字 SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0); SOCKADDR_IN dest; //端口25 dest.sin_port = htons(25);//587也可以 dest.sin_family = AF_INET; //獲取smtp.qq.com服務器域名所代表的IP地址 hostent* hptr = gethostbyname("smtp.qq.com"); memcpy(&dest.sin_addr.S_un.S_addr, hptr->h_addr_list[0], hptr->h_length); //連接騰訊的郵件SMTP服務器 int ok = connect(sockfd, (SOCKADDR*)&dest, sizeof(SOCKADDR)); if (ok != 0) exit(0); //用于向服務器標明用戶身份,可以為發件人的服務器域名或者主機名 sprintf_s(buf, 1500, "EHLO Aaron-PC\r\n"); send(sockfd, buf, strlen(buf), 0); //接收服務器響應 ZeroMemory(buf, 1500); recv(sockfd, buf, 1500, 0); cout << "QQ SMTP Server Say: \r\n" << buf << endl; //開啟安全傳輸層協議(TLS) //這里的STARTTLS空格的后面要加一些字符才行,這里不是很懂,但這就可以了. sprintf_s(buf, 1500, "STARTTLS a\r\n"); send(sockfd, buf, strlen(buf), 0); //接收服務器響應 ZeroMemory(buf, 1500); recv(sockfd, buf, 1500, 0); cout << "QQ SMTP Server Say: \r\n" << buf << endl; //郵箱認證,發送該命令后依次發送郵箱賬號和密碼(賬號密碼均使用Base64編碼) sprintf_s(buf, 1500, "AUTH LOGIN\r\n"); send(sockfd, buf, strlen(buf), 0); //接收服務器響應 ZeroMemory(buf, 1500); recv(sockfd, buf, 1500, 0); cout << "Auth Login Receive:\r\n " << buf << endl; //發送QQ賬號 ZeroMemory(buf, 1500); sprintf_s(buf, 1500, "3093575@qq.com");//你的郵箱賬號 //將QQ賬號轉換為Base64編碼再發送 EncodeBase64(login, buf, strlen(buf)); sprintf_s(buf, 1500, "%s\r\n", login); send(sockfd, buf, strlen(buf), 0); cout << "Base64 UserName: " << buf << endl; //接收服務器響應 ZeroMemory(buf, 1500); recv(sockfd, buf, 1500, 0); cout << "User Login Receive: \r\n" << buf << endl; //發送密鑰(相當于QQ密碼,在上面的步驟得到) sprintf_s(buf, 1500, "qkbekqqwudvcbjab"); //將密鑰轉換為Base64編碼再發送 EncodeBase64(pass, buf, strlen(buf)); sprintf_s(buf, 1500, "%s\r\n", pass); send(sockfd, buf, strlen(buf), 0); cout << "Base64 Password:\r\n " << buf << endl; //接收服務器響應 ZeroMemory(buf, 1500); recv(sockfd, buf, 1500, 0); cout << "Send Password Receive:\r\n " << buf << endl; //發送MAIL FROM命令指定發件人 ZeroMemory(buf, 1500); sprintf_s(buf, 1500, "MAIL FROM: <3093575@qq.com>\r\n"); send(sockfd, buf, strlen(buf), 0); //接收服務器響應 ZeroMemory(buf, 1500); recv(sockfd, buf, 1500, 0); cout << "Set Mail From Receive:\r\n " << buf << endl; //發送一個或多個RCPT TO命令指定收件人 sprintf_s(buf, 1500, "RCPT TO:<%s>\r\n", "109333576@qq.com"); //109333576@qq.com為收件人1 send(sockfd, buf, strlen(buf), 0); //接收服務器響應 ZeroMemory(buf, 1500); recv(sockfd, buf, 1500, 0); cout << "Tell Sendto Receive: \r\n" << buf << endl; sprintf_s(buf, 1500, "RCPT TO:<%s>\r\n", "509333576@qq.com"); //509333576@qq.com為收件人2 send(sockfd, buf, strlen(buf), 0); //接收服務器響應 ZeroMemory(buf, 1500); recv(sockfd, buf, 1500, 0); cout << "Tell Sendto Receive: \r\n" << buf << endl; //發送一個DATA命令表示準備開始發送郵件內容 sprintf_s(buf, 1500, "DATA\r\n"); send(sockfd, buf, strlen(buf), 0); //接收服務器響應 ZeroMemory(buf, 1500); recv(sockfd, buf, 1500, 0); cout << "Send Mail Prepare Receive: \r\n" << buf << endl; //發送郵件內容,格式:以\r\n.\r\n作為結束標記 sprintf_s(buf, 1500, "%s\r\n.\r\n", EmailContents); //郵件的內容 send(sockfd, buf, strlen(buf), 0); //接收服務器響應 ZeroMemory(buf, 1500); recv(sockfd, buf, 1500, 0); cout << "Send Mail Receive: \r\n" << buf << endl; //使用QUIT命令退出 sprintf_s(buf, 1500, "QUIT\r\n"); send(sockfd, buf, strlen(buf), 0); ZeroMemory(buf, 1500); recv(sockfd, buf, 1500, 0); cout << "Quit Receive: " << buf << endl; //清理工作 closesocket(sockfd); WSACleanup(); getchar(); return 0; }補充說明:想要知道其中細節的問題,需要學習SMTP協議,例如SMTP命令以及SMTP服務器三位數字響應碼
缺點:
1、360會報告有第三方軟件在使用郵箱發件.
2、明文傳輸賬號和密碼,有被人分析程序和抓包得到賬號密碼的風險。
與QQ的SMTP服務器交流過程:
測試發送結果:(我發送到了一個163郵箱、自己的QQ郵箱中)
總結
以上是生活随笔為你收集整理的编写SMTP协议邮箱发信(QQ邮箱为例)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Centos7安装Torque
- 下一篇: 您需要售后返修管理软件的N个理由