QT5 使用163郵箱傳送郵件
最近在用QT寫一點東西,想傳送個郵件。查了一些資料,發現沒有官方的庫,好多前輩都是推薦使用sendemailapi,但是這個網站現在已經不提供下載了,在網上也沒有找到可以免費下載的這個庫的地方。
借鑑的幾篇文章如下
Qt5.5 使用smtp發郵件的各種坑
所以研究了一下smtp的原理,自己寫了一個簡單的smtp類,跟大家分享一下。
先說一下實現的功能:QT5.5(MSVC_x64) 使用163郵箱 向 qq郵箱 和 163郵箱 傳送郵件(其餘郵箱我沒有測試,也沒有寫接收郵件的功能)
先說一下前期的實驗工作,後面我會貼原始碼,只關注程式的童鞋可以直接向後翻。
1.在OSI協議中,SMTP屬於應用層,所使用的傳輸層協議是TCP。
2.登入163郵箱,設定開啟SMTP。
忘記授權碼的童鞋可以重置一下,記住這個授權碼,後面要用。
假設郵箱是[email protected] ,授權碼是BBBBBB,收件人的郵箱是[email protected]。
3.使用windows自帶的Telnet來進行資料測試:(這一部分主要借鑑於 Qt5.5 使用smtp發郵件的各種坑)
telnet不是內部或外部命令的解決方案
首先開啟cmd.
- 輸入 telnet smtp.163.com 25 回車
會返回220 163.com Anti-spam GT for Coremail System (163com[20141201]) - 輸入 HELO smtp.163.com 回車
如果返回250 OK 表示伺服器準備就緒,可以進行下一步了. - 輸入 AUTH LOGIN 回車
這是指定登入的模式,這句應該是一般模式.
返回334 dXNlcm5hbWU6就可以進行下一步了.
注:登入這部分採用 base64加密 ,dXNlcm5hbWU6 解碼之後為username:
base64 線上解碼編碼 - 輸入 經過base64加密的你的賬戶名,比如你的郵箱是[email protected],然後進入base64 線上解碼編碼,將[email protected]加密 ,將加密後的使用者名稱輸入到到命令列回車
返回334 UGFzc3dvcmQ6 - 輸入 你的base64加密過的密碼,方法同上.
返回235 Authentication successful,表示驗證通過,可以進行下一步了. - 輸入 mail from:[email protected] 這裡寫你的郵箱
返回250 Mail OK. - 輸入 rcpt to:[email protected] 這裡寫收件人的郵箱
返回250 Mail OK. - 輸入 data,表示開始傳送資料
返回354 End data with . (要以英文的 . 截止資料) - 輸入 from:[email protected]
伺服器無返回. - 輸入 to:[email protected]
伺服器無返回. - 輸入 subject:test 回車 (“test”為郵件主題)
伺服器無返回. - 輸入 此處什麼也不用寫,直接回車換行,作為主題與正文的分界
伺服器無返回. - 輸入 This is a test mail. 回車 (“This is a test mail.” 為郵件正文)
伺服器無返回. - 輸入 . 一個英文句號,表示資料傳送完畢
返回 250 Mail OK queued as smtp14 即為傳送成功.(現在就可以去查收一下郵件了) - 輸入 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;
}