1. 程式人生 > >QT5 使用163郵箱傳送郵件

QT5 使用163郵箱傳送郵件

最近在用QT寫一點東西,想傳送個郵件。查了一些資料,發現沒有官方的庫,好多前輩都是推薦使用sendemailapi,但是這個網站現在已經不提供下載了,在網上也沒有找到可以免費下載的這個庫的地方。
借鑑的幾篇文章如下
Qt5.5 使用smtp發郵件的各種坑
所以研究了一下smtp的原理,自己寫了一個簡單的smtp類,跟大家分享一下。
先說一下實現的功能:QT5.5(MSVC_x64) 使用163郵箱 向 qq郵箱 和 163郵箱 傳送郵件(其餘郵箱我沒有測試,也沒有寫接收郵件的功能)
先說一下前期的實驗工作,後面我會貼原始碼,只關注程式的童鞋可以直接向後翻。

1.在OSI協議中,SMTP屬於應用層,所使用的傳輸層協議是TCP。

2.登入163郵箱,設定開啟SMTP。
進入POP3設定

開啟SMTP服務

開啟客戶端授權

忘記授權碼的童鞋可以重置一下,記住這個授權碼,後面要用。
假設郵箱是[email protected] ,授權碼是BBBBBB,收件人的郵箱是[email protected]

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加密的你的賬戶名,比如你的郵箱是[email protected],然後進入base64 線上解碼編碼,將[email protected]加密 ,將加密後的使用者名稱輸入到到命令列回車
    返回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:[email protected]
    伺服器無返回.
  10. 輸入 to:[email protected]
    伺服器無返回.
  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
    測試結果如圖

這裡寫圖片描述
但是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("[email protected]","BBBBBB");
    smtp.send("[email protected]","測試郵件","這是一封測試郵件^_^");
    return 0;
}