1. 程式人生 > 實用技巧 >郵件客戶端

郵件客戶端

計算機網路課程設計 郵件客戶端

1. 參考部落格

2. 前期準備

  • 基於實現的環境為Windows 7,主要是因為Windows 10的Telnet服務端已經被砍掉了,看了別人的部落格說是Win10可以安裝環境,本人僅作課設用,故在虛擬機器上實現,有興趣的可以自行摸索。
  • 首先開啟在Windows環境中,開啟控制面板->程式,開啟Telnet客戶端和服務端。

  • 然後執行services.msc命令,不會自行百度,開啟Telnet服務,設為自動執行,你可能會遇到一些bug,開啟不了,主要是依賴的問題,自行百度解決。

3. 用命令列的方式進行實現(接收到郵件說明成功)

4. 程式碼實現(Codeblocks環境)

#include <iostream>
#include <string>
#include <WinSock2.h>
#include <stdio.h>
#include <cstdlib>
#include <cstring>
#include <algorithm>

using namespace std;

string base64_encode(string str){  //base64加密演算法
	string base64_table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	int str_len = str.length();
	string res="";
	//注意這裡str_len/3*3
	//通過字元的ascii二進位制位運算組合成base64編碼二進位制
	for (int strp=0; strp<str_len/3*3; strp+=3){
		res+=base64_table[str[strp]>>2];
		res+=base64_table[(str[strp]&0x3)<<4 | (str[strp+1])>>4];
		res+=base64_table[(str[strp+1]&0xf)<<2 | (str[strp+2])>>6];
		res+=base64_table[(str[strp+2])&0x3f];
		//cout<<res<<endl;
	}
	if (str_len%3==1){
		int pos=str_len/3 * 3;
		res += base64_table[str[pos]>>2];
		res += base64_table[(str[pos]&0x3)<<4];
		res += "=";	res += "=";
	}else if (str_len%3==2){
		int pos=str_len/3 * 3;
		res += base64_table[str[pos]>>2];
		res += base64_table[(str[pos]&0x3)<<4 | (str[pos+1])>>4];
		res += base64_table[(str[pos+1]&0xf)<<2];
		res += "=";
	}
	return res;
}

int main()
{
    char buff[500]; //收到recv函式返回的結果
    string message;
    string info;
    string subject;


    WSADATA wsaData;
    WORD wVersionRequested = MAKEWORD(2, 2);
    //WSAStarup,即WSA(Windows SocKNDs Asynchronous,Windows套接字非同步)的啟動命令
    int err = WSAStartup(wVersionRequested, &wsaData);
    if ( err != 0 )
    {
        return 0;
    }

    if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 )
    {
        printf("初始化失敗!");
        WSACleanup( );
        return 0;
    }
    SOCKET sockClient; //客戶端的套接字
    sockClient = socket(AF_INET, SOCK_STREAM, 0); //建立socket物件

    HOSTENT* pHostent;//hostent是host entry的縮寫,該結構記錄主機的資訊,包括主機名、別名、地址型別、地址長度和地址列表

    pHostent = gethostbyname("smtp.qq.com"); //得到有關於域名的資訊,連結到qq郵箱伺服器

    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(25); //連線埠25
    err = connect(sockClient, (SOCKADDR*)&addrServer, sizeof(SOCKADDR)); //向伺服器傳送請求
    buff[recv(sockClient, buff, 500, 0)] = '\0';
    //printf("%s",buff);
    /*
    登入郵件伺服器
    */
    cout <<"歡迎登陸QQ郵箱簡易版\n";
    string qq,password;
    cout << "請輸入你的QQ郵箱號碼:\n";
    cin>>qq;
    cout << "請輸入你的郵箱授權碼:\n";
    cin >>password;
    cout << "登陸認證成功,您可以傳送郵件了:\n";
    message = "helo qq\r\n";
    send(sockClient, message.c_str(), message.length(), 0); //傳送ehlo命令
    buff[recv(sockClient, buff, 500, 0)] = '\0';   //接收返回值

    message = "auth login\r\n";
    send(sockClient, message.c_str(), message.length(), 0);
    buff[recv(sockClient, buff, 500, 0)] = '\0';

    /*
    傳送base64加密的使用者名稱、密碼
    */
    message = base64_encode(qq) + "\r\n";
    send(sockClient, message.c_str(), message.length(), 0);
    buff[recv(sockClient, buff, 500, 0)] = '\0';

  
    message = base64_encode(password) + "\r\n";
    send(sockClient, message.c_str(), message.length(), 0);
    buff[recv(sockClient, buff, 500, 0)] = '\0';
    /*
    使用 MAIL 命令指定傳送者
    使用 RCPT 命令指定接收者,可以重複使用RCPT指定多個接收者
    */
    // password = "wewqzvbzcfqkdhee";
    string mail;

    cout << "請輸入收件人郵箱:\n";
    cin >> mail;
    message = "mail from:<" + qq + ">\r\n";
    send(sockClient, message.c_str(), message.length(), 0);
    buff[recv(sockClient, buff, 500, 0)] = '\0';


    message = "rcpt to:<";
    message.append(mail);
    message.append(">\r\n");
    send(sockClient, message.c_str(), message.length(), 0);
    buff[recv(sockClient, buff, 500, 0)] = '\0';
    /*
    使用 DATA 命令告訴伺服器要傳送郵件內容
    */

    message = "DATA\r\n";
    send(sockClient, message.c_str(), message.length(), 0);
    buff[recv(sockClient, buff, 500, 0)] = '\0';
    message = "From: " + qq + "\r\nTo: "+mail+"\r\nsubject:";
    cout<<"主題:";
    cin>>subject;
    message.append(subject);
    message.append("\r\n\r");
    cout<<"內容:";
    cin>>info;
    message.append(info);
    message.append("\r\n.\r\n");
    //cout<<message.c_str();
    send(sockClient, message.c_str(), message.length(), 0);
    buff[recv(sockClient, buff, 500, 0)] = '\0';
    message = "QUIT\r\n";
    send(sockClient, message.c_str(), message.length(), 0);
    buff[recv(sockClient, buff, 500, 0)] = '\0';
    cout << "郵件傳送成功!"<<endl;
    system("pause");
    return 0;
}

5. 如果遇到報錯:undefined reference to `__imp_WSAStartup’,請參考:我的另一篇部落格