欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

QT5 使用163邮箱发送邮件

程序员文章站 2022-07-08 14:54:48
...

最近在用QT写一点东西,想发送个邮件。查了一些资料,发现没有官方的库,好多前辈都是推荐使用sendemailapi,但是这个网站现在已经不提供下载了,在网上也没有找到可以免费下载的这个库的地方。
借鉴的几篇文章如下
Qt5.5 使用smtp发邮件的各种坑
所以研究了一下smtp的原理,自己写了一个简单的smtp类,跟大家分享一下。
先说一下实现的功能:QT5.5(MSVC_x64) 使用163邮箱 向 qq邮箱 和 163邮箱 发送邮件(其余邮箱我没有测试,也没有写接收邮件的功能)
先说一下前期的实验工作,后面我会贴源码,只关注程序的童鞋可以直接向后翻。

1.在OSI协议中,SMTP属于应用层,所使用的传输层协议是TCP。

2.登录163邮箱,设置开启SMTP。
QT5 使用163邮箱发送邮件

QT5 使用163邮箱发送邮件

QT5 使用163邮箱发送邮件

忘记授权码的童鞋可以重置一下,记住这个授权码,后面要用。
假设邮箱是aaa@qq.com ,授权码是BBBBBB,收件人的邮箱是aaa@qq.com

3.使用windows自带的Telnet来进行数据测试:(这一部分主要借鉴于 Qt5.5 使用smtp发邮件的各种坑)
telnet不是内部或外部命令的解决方案

首先打开cmd.

  1. 输入 telnet smtp.163.com 25 回车
    会返回220 163.com Anti-spam GT for Coremail System (163com[20141201])
  2. 输入 HELO smtp.163.com 回车
    如果返回250 OK 表示服务器准备就绪,可以进行下一步了.
  3. 输入 AUTH LOGIN 回车
    这是指定登录的模式,这句应该是一般模式.
    返回334 dXNlcm5hbWU6就可以进行下一步了.
    注:登录这部分采用 base64加密 ,dXNlcm5hbWU6 解码之后为username:
    base64 在线解码编码
  4. 输入 经过base64加密的你的账户名,比如你的邮箱是aaa@qq.com,然后进入base64 在线解码编码,将aaa@qq.com加密 ,将加密后的用户名输入到到命令行回车
    返回334 UGFzc3dvcmQ6,UGFzc3dvcmQ6解码之后为Password:
  5. 输入 你的base64加密过的密码,方法同上.
    返回235 Authentication successful,表示验证通过,可以进行下一步了.
  6. 输入 mail from:[email protected] 这里写你的邮箱
    返回250 Mail OK.
  7. 输入 rcpt to:[email protected] 这里写收件人的邮箱
    返回250 Mail OK.
  8. 输入 data,表示开始传送数据
    返回354 End data with . (要以英文的 . 截止数据)
  9. 输入 from:aaa@qq.com
    服务器无返回.
  10. 输入 to:aaa@qq.com
    服务器无返回.
  11. 输入 subject:test 回车 (“test”为邮件主题)
    服务器无返回.
  12. 输入 此处什么也不用写,直接回车换行,作为主题与正文的分界
    服务器无返回.
  13. 输入 This is a test mail. 回车 (“This is a test mail.” 为邮件正文)
    服务器无返回.
  14. 输入 . 一个英文句号,表示数据传送完毕
    返回 250 Mail OK queued as smtp14 即为发送成功.(现在就可以去查收一下邮件了)
  15. 输入 quit
    返回 221 Bye
    QT5 使用163邮箱发送邮件

QT5 使用163邮箱发送邮件
但是CMD中输入中文会乱码, 这个问题不用担心,程序中是可以发送中文的。(可能是编码方式的问题)

好了,到这里准备工作已经结束了,程序分为以下几个部分。
1. TCP客户端与smtp.163.com:25 进行连接和数据通信
2. 数据加密问题,将用户名和密码使用base64加密,使用 QByteArray.toBase64()
3. 解决汉字乱码问题,借鉴了这篇文章中的方法2 str.toLocal8Bit()
QT使用QTcpSocket和QTcpServer通信是出现乱码的问题
建立mailtest的QT工程
mailtest.pro

SOURCES += \
    main.cpp \
    smtp.cpp

HEADERS += \
    smtp.h
QT += network

添加Smtp class
smtp.h

#ifndef SMTP_H
#define SMTP_H
#include<QByteArray>
#include<QString>
#include<QTcpSocket>

class Smtp
{
public:
    Smtp(QByteArray username,QByteArray password);
    ~Smtp();
    void send(QByteArray recvaddr,QString subject,QString content);
private:
    QTcpSocket * clientsocket;
    QByteArray username;
    QByteArray password;
    QByteArray recvaddr;
    QByteArray mailfrom = "mail from:<";
    QByteArray rcptto = "rcpt to:<";
    QByteArray prefrom = "from:";
    QByteArray preto = "to:";
    QByteArray presubject ="subject:";
    QString subject;                //主题
    QString content;                //发送内容
    QByteArray recvdata;            //接收到的数据
};

#endif // SMTP_H

smtp.cpp

#include "smtp.h"
#include<qDebug>

Smtp::Smtp(QByteArray username,QByteArray password)
{
    if(username.contains("@163"))
    {
        this->username = username;
        this->password = password;
    }
    else
        qDebug()<<"NOT 163";
}

void Smtp::send(QByteArray recvaddr,QString subject,QString content)
{
    this->recvaddr = recvaddr;
    this->subject = subject;
    this->content = content;
    QByteArray usernametmp = this->username;
    QByteArray recvaddrtmp = this->recvaddr;

    clientsocket=new QTcpSocket();
    this->clientsocket->connectToHost("smtp.163.com",25,QTcpSocket::ReadWrite);
    this->clientsocket->waitForConnected(1000);
    this->clientsocket->waitForReadyRead(1000);
    recvdata = clientsocket->readAll();
    qDebug()<<recvdata;


    this->clientsocket->write("HELO smtp.163.com\r\n");
    this->clientsocket->waitForReadyRead(1000);
    recvdata = clientsocket->readAll();
    qDebug()<<recvdata;

    this->clientsocket->write("AUTH LOGIN\r\n");
    this->clientsocket->waitForReadyRead(1000);
    recvdata = clientsocket->readAll();
    qDebug()<<recvdata;

    this->clientsocket->write(username.toBase64().append("\r\n"));
    this->clientsocket->waitForReadyRead(1000);
    recvdata = clientsocket->readAll();
    qDebug()<<recvdata;

    this->clientsocket->write(password.toBase64().append("\r\n"));
    this->clientsocket->waitForReadyRead(1000);
    recvdata = clientsocket->readAll();
    qDebug()<<recvdata;

    this->clientsocket->write(mailfrom.append(usernametmp.append(">\r\n")));
    this->clientsocket->waitForReadyRead(1000);
    recvdata = clientsocket->readAll();
    qDebug()<<recvdata;

    this->clientsocket->write(rcptto.append(recvaddrtmp.append(">\r\n")));
    this->clientsocket->waitForReadyRead(1000);
    recvdata = clientsocket->readAll();
    qDebug()<<recvdata;

    this->clientsocket->write("data\r\n");
    this->clientsocket->waitForReadyRead(1000);
    recvdata = clientsocket->readAll();
    qDebug()<<recvdata;


    usernametmp = this->username;
    recvaddrtmp = this->recvaddr;

    this->clientsocket->write(prefrom.append(usernametmp.append("\r\n")));
    this->clientsocket->write(preto.append(recvaddrtmp.append("\r\n")));
    this->clientsocket->write(presubject.append(subject.toLocal8Bit().append("\r\n")));
    this->clientsocket->write("\r\n");
    this->clientsocket->write(content.toLocal8Bit().append("\r\n"));
    this->clientsocket->write(".\r\n");
    this->clientsocket->waitForReadyRead(1000);
    recvdata = clientsocket->readAll();
    qDebug()<<recvdata;

    this->clientsocket->write("quit\r\n");
    this->clientsocket->waitForReadyRead(1000);
    recvdata = clientsocket->readAll();
    qDebug()<<recvdata;
}

Smtp::~Smtp()
{
    delete this->clientsocket;
}

main.cpp

#include<smtp.h>

int main()
{
    Smtp smtp("aaa@qq.com","BBBBBB");
    smtp.send("aaa@qq.com","测试邮件","这是一封测试邮件^_^");
    return 0;
}