计网课设----C++实现邮箱发送

该博客介绍了如何使用C++通过SMTP协议实现邮件发送,包括建立与邮箱服务器的连接,进行身份验证(如QQ邮箱和163邮箱),以及发送邮件的详细步骤。涉及到base64加密和命令行模拟交互,同时提供了C++代码示例。
摘要由CSDN通过智能技术生成

C++实现邮箱发送

​ 本电子邮件客户端实现本质上在于向邮箱服务器建立链接,从而进行一系列的身份校验,输入收件人邮箱以及要发送的信息等等。

​ 首先进行winsock的版本规定,建立套接字,并将本机的名称信息等与服务器端进行绑定,并选择一个端口进行数据的发送与接收。

​ 主流的邮箱主要有QQ邮箱,163邮箱。不同的邮箱有不同的host,QQ对应于smtp.qq.com ,163 邮箱对应于smtp.163.com。本程序设计两种邮箱均可进行发送。当要进行邮件发送的时候需要向服务器发送请求,在进行身份验证的时候需要使用用户邮箱的授权码以及用户名,并通过base64加密进行身份校验,以保证数据的安全性,并对数据进行压缩。

​ 需要注意的是,在发送邮件时,客户端对于传送的数据有着很严格的要求,主题的开头,标识等等,即使多一个空格也是不行的,这也是QQ邮箱发送使用ui界面的一个比较重要的原因。

  1. 使用命令行发送邮箱

    首先需要开启 telnet 客户端功能
    在这里插入图片描述
    ​ 选中 Telnet Client 服务选择开启。

在这里插入图片描述

命令行输入:

telnet smtp.163.com 25(163邮箱服务)

或者 telnet smtp.qq.com 25(QQ 邮箱服务),效果大致如下

(注: 25 为 smtp 的默认服务端口)

在这里插入图片描述

与服务器打招呼(hello 是任意的一句话,最好不要出现中文),之后会有下面输出

ehlo hello
开始认证

在这里插入图片描述

auth login

在这里插入图片描述

输入base64加密的用户名和授权码(授权码获取这里不赘述,在邮箱主页里获取),base64加密网站推荐—> 传送门
在这里插入图片描述
输入以下格式输入发件人,收件人的信息

在这里插入图片描述
输入 DATA,出现以上354回复

输入subject:标题,中间再空一行,接着输入正文,最后输入. 表示输入结束。
在这里插入图片描述
出现 250 的信息说明发送成功
在这里插入图片描述
大致输入如下所示

telnet smtp.qq.com 25

ehlo hello

auth login

base64(用户名)

base64(授权码)

mail from:ruerlen@qq.com

rcpt to:2927357751@qq.com

data

subject:nihao

你好

.

  1. 使用 c++ socket 连接服务器进行发送,要点便是通过与smtp服务器建立联系,模拟命令行与服务器进行交互

    base64 加密函数:

    // base64 加密函数
    string base64(string str)   //base64加密算法
    {
        string base64_table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        int str_len = str.length();
        string res="";
        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;
    }
    

    设置winsock版本,初始化套接字

     WSADATA wsaData;
        WORD wVersionRequested = MAKEWORD(2, 1); //版本2.1
        int err = WSAStartup(wVersionRequested, &wsaData);
        // cout << "WSAStartup:" << err << endl;
        SOCKET sockClient;
        sockClient = socket(AF_INET, SOCK_STREAM, 0);
    

    得到smtp服务器的网络字节序的ip地址并向服务器发送请求

    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)); //向服务器发送请求
    

    完整代码:

    #include <iostream>
    #include <string>
    #include <WinSock2.h> //适用平台 Windows
    using namespace std;
    #pragma comment(lib, "ws2_32.lib") /*链接ws2_32.lib动态链接库*/
    
    using namespace std;
    
    // base64 加密函数
    string base64(string str)   //base64加密算法
    {
        string base64_table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        int str_len = str.length();
        string res="";
        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;
        // telnet smtp.qq.com
        WSADATA wsaData;
        WORD wVersionRequested = MAKEWORD(2, 1); //版本2.1
        int err = WSAStartup(wVersionRequested, &wsaData);
        // cout << "WSAStartup:" << err << endl;
        SOCKET sockClient;
        sockClient = socket(AF_INET, SOCK_STREAM, 0);
        HOSTENT* pHostent;//主机的名称,地址信息等
        while(1)
        {
            int flag;
            cout<<"如果您是QQ邮箱请按1,163邮箱请按2"<<endl;
            cin>>flag;
            if(flag == 1)
            {
                pHostent = gethostbyname("smtp.qq.com"); //得到有关于域名的信息,链接到qq邮箱服务器
            }
            else
            {
                pHostent = gethostbyname("smtp.163.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)); //向服务器发送请求
            //cout << "connect:" << err << endl;
            buff[recv(sockClient, buff, 500, 0)] = '\0';
            // cout << "connect:" << buff << endl;
            // message = "ehlo qq.com\r\n";
            message = "ehlo hello\r\n";  // 先打个招呼
            send(sockClient, message.c_str(), message.length(), 0); //发送ehlo命令
            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;
            /*
            发送base64加密的用户名、密码
            */
            string Smail;
            cout<< "输入您的邮箱:";
            cin>>Smail;
            string name = Smail.substr(0,Smail.find("@"));
            //  cout<<name<<endl;
            message = base64(name) + "\r\n"; //base64 编码的用户名
            send(sockClient, message.c_str(), message.length(), 0);
            buff[recv(sockClient, buff, 500, 0)] = '\0';
            //cout << "usrname:" << buff << endl;
            string Swd;
            cout << "请输入您的授权码:";
            cin>>Swd;
            message = base64(Swd) + "\r\n";//base64 编码的密码
            send(sockClient, message.c_str(), message.length(), 0);
            buff[recv(sockClient, buff, 500, 0)] = '\0';
            cout << "password:" << buff << endl;
    
            string Rmail;
            cout << "输入收件人邮箱:";
            cin >> Rmail;
            message = "mail from:<"+Smail+">\r\n";
            // message = "MAIL FROM:<XXX@qq.com> \r\nRCPT TO:<XXX@163.com> \r\n";
    
    
            send(sockClient, message.c_str(), message.length(), 0);
            buff[recv(sockClient, buff, 500, 0)] = '\0';
    
            message = "rcpt to:<";
    
            message.append(Rmail);
            message.append(">\r\n");
            //cout << "message=" << message;
    
            send(sockClient, message.c_str(), message.length(), 0);
    
            buff[recv(sockClient, buff, 500, 0)] = '\0';
    
            message = "DATA\r\n";
            send(sockClient, message.c_str(), message.length(), 0);
            buff[recv(sockClient, buff, 500, 0)] = '\0';
            message = "From: "+Smail+"\r\nTo: "+Rmail+"\r\nsubject:";
            cout<<"主题:";
            cin>>subject;
            message.append(subject);
            message.append("\r\n\r\n");
            cout<<"内容:";
            cin>>info;
            message.append(info);
            message.append("\r\n.\r\n");
    
            send(sockClient, message.c_str(), message.length(), 0);
            buff[recv(sockClient, buff, 500, 0)] = '\0';
            cout<<" 发送成功!"<<endl;
            cout<<buff;
            message = "QUIT\r\n";
            send(sockClient, message.c_str(), message.length(), 0);
            buff[recv(sockClient, buff, 500, 0)] = '\0';
            char mes;
            cout<<"输入Q退出,R再来一封邮件"<<endl;
            cin>>mes;
            if(mes == 'Q')
            {
                break;
            }
        }
        // cout << "QUIT:" << buff << endl;
        cout << "退出成功!"<<endl;
        system("pause");
    }
    

    运行效果如下:
    在这里插入图片描述
    对方可以收到邮件
    在这里插入图片描述

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值