要做一個監測軟件,出問題時需要發送一封郵件,所以最近就在網上找了下qt5怎麼發郵件,下面貼出方法(代碼部分是網上找的一個,自己測試可以使用,直接拷過去就可以了)。
基本原理就是使用telnet通過smtp協議來發送郵件。先簡單說下telnet和smtp。
Telnet協議是TCP/IP協議族中的一員,是Internet遠程登陸服務的標準協議和主要方式。smtp(simple mail transfer protocol)則是簡單的郵件傳輸協議。(具體還是自己去找下度娘吧)
然後就是先熟悉一下telnet怎麼發送郵件了首先需要打開電腦的telnet功能,先進入到控制面板界面,點擊下圖(左)中紅框部分,然後在下右圖中勾選telnet客戶端,點擊確定,稍等一下就可以了。
接下來是嘗試在telnet中發送郵件:
1.使用telnet連接郵箱服務器,名稱的格式基本都是smtp.xxx.com,例如:qq郵箱爲smtp.qq.com,163郵箱爲smtp.163.com,然後端口爲25,如下左圖
2.連接上之後會打印上右圖第一行,然後輸入helo sis,這句只是打招呼,收到250回覆之後再輸入auth login,收到334回覆即可輸入用戶名,這裏需要輸入base64格式數據,即需要把你的郵箱先base64編碼再輸入進來,密碼也是一樣。(如果是qq郵箱需要先到郵箱-->設置裏面打開smtp功能並使用授權碼當做密碼登陸)
3.登陸完成之後即可開始發送郵件了,如下圖mail from會顯示在收件人的郵件裏面,rcpt to爲收件人的郵箱地址,如果要向多個人同時發郵件可使用rcpt to多個郵箱(看到網上這麼寫的,我並沒有試過同時向多個人發郵件)寫完數據之後以“回車 . 回車”結束,最後回覆250 ok即發送成功(下圖中有3此報錯,其實我連同下面第4次輸入的都是同一個郵箱,這裏不太明白爲什麼會報錯)
qt中的實現思路也是如此,下面貼上代碼:
先是smtp.c文件:
#include "smtp.h"
Smtp::Smtp(QString smtphost, QString smtpusername, QString smtppass)
{
this->smtphost = smtphost;
this->smtpusername = smtpusername;
this->smtppass = smtppass;
}
bool Smtp::Send( const QString &to, const QString &subject, const QString &body )
{
qDebug()<<"####"<<Q_FUNC_INFO;
bool res = false;
int waittime = 5 * 1000;
this->from = smtpusername;
rcpt = to;
ErrorMSG.clear();
Timeout = waittime;
linesend = 0;
isconnect = false;
QString tmp = "=?utf-8?B?"+ QByteArray().append(subject).toBase64()+"?=";
message.append("Subject:" + tmp + "\n");
message.append("To: " + to + "\n");
message.append("From: "+smtpusername+" <" + smtpusername + ">\n");
message.append("Content-Type: text/html; charset=UTF8;\n"); /* or txt */
message.append("Content-transfer-encoding: 7BIT\n\n\n\n");
message.append(body);
message.replace( tr( "\n" ), tr( "\r\n" ) );
message.replace( tr( "\r\n.\r\n" ),tr( "\r\n..\r\n" ) );
smtpsocket = new QTcpSocket(this);
connect( this, SIGNAL(SendLine()), this ,SLOT(PutSendLine()));
if (smtphost.size() > 0)
{
smtpsocket->connectToHost(smtphost,25);
} else {
smtpsocket->connectToHost("localhost",25);
}
if (smtpsocket->waitForConnected(Timeout))
{
if (smtpsocket->waitForReadyRead(Timeout))
{
isconnect = true;
return ReadLiner();
}
}
else
{
ErrorCloseAll();
}
return res;
}
bool Smtp::ReadLiner()
{
bool res = false;
if (isconnect)
{
QTextCodec *codecx;
codecx = QTextCodec::codecForMib(106);
t = new QTextStream( smtpsocket );
t->setCodec(codecx);
int loops = 0;
while (!t->atEnd())
{
loops++;
response = t->readLine();
}
if (response.size() > 0)
{
RemoteServerName = response;
mailstatus = response.left(3);
if (mailstatus == "220")
{
response="";
linesend = 1;
res = true;
}
}
else
{
ErrorCloseAll();
}
}
return res;
}
Smtp::~Smtp()
{
delete smtpsocket;
delete t;
}
/* LINE SENDER */
bool Smtp::PutSendLine()
{
static bool res = true;
int current = linesend;
switch(current)
{
case 1:
response = SendLineAndGrab("ehlo localhost");
if (response.size() > 0)
{
ErrorMSG.append(response);
linesend = 2;
emit SendLine();
}
else
{
res=false;
}
response ="";
break;
case 2:
response = SendLineAndGrab("AUTH LOGIN");
if (response.size() > 0)
{
ErrorMSG.append(response);
linesend = 3;
emit SendLine();
}
else
{
res= false;
}
response ="";
break;
case 3:
response = SendLineAndGrab(encodeBase64(smtpusername)); /* username send */
if (response.size() > 0)
{
ErrorMSG.append(response);
if (response.contains("334", Qt::CaseInsensitive))
{
linesend = 4;
emit SendLine();
}
}
else
{
res=false;
}
response ="";
break;
case 4:
response = SendLineAndGrab(encodeBase64(smtppass)); /* pass send */
if (response.size() > 0)
{
ErrorMSG.append(response);
if (response.contains("235", Qt::CaseInsensitive))
{
linesend = 5;
emit SendLine();
}
else
{
res= false;
}
}
else
{
res= false;
}
response ="";
break;
case 5:
response = SendLineAndGrab(tr("MAIL FROM: %1").arg(smtpusername));
if (response.size() > 0)
{
linesend = 6;
emit SendLine();
}
break;
case 6:
response = SendLineAndGrab("RCPT TO: "+rcpt);
if (response.size() > 0)
{
ErrorMSG.append(response);
response ="";
response = SendLineAndGrab("DATA");
if (!response.contains("not", Qt::CaseInsensitive))
{
ErrorMSG.append(response);
response ="";
linesend = 7;
emit SendLine();
}
}
response ="";
break;
case 7:
response = SendLineAndGrab(message+"\r\n.");
if (response.size() && response.contains("ok", Qt::CaseInsensitive) )
{
ErrorMSG.append(response);
linesend = 8;
emit SendLine();
}
response ="";
break;
case 8:
SendLineAndGrab("QUIT");
break;
default:
break;
}
return res;
}
/* SENDER AND RECIVER */
QString Smtp::SendLineAndGrab(QString senddata)
{
QString incommingData = "";
if (isconnect)
{
int current = linesend;
int loops = 0;
*t << senddata << "\r\n";
t->flush();
if (senddata != "QUIT") {
if (smtpsocket->waitForReadyRead(Timeout))
{
while (!t->atEnd())
{
loops++;
QString opera = t->readLine()+"\n";
incommingData = opera + incommingData;
}
}
} else
{
delete smtpsocket;
delete t;
isconnect = false;
return incommingData;
}
}
else
{
ErrorCloseAll();
}
return incommingData;
}
QString Smtp::encodeBase64( QString xml )
{
QByteArray text;
text.append(xml);
return text.toBase64();
}
QString Smtp::decodeBase64( QString xml )
{
QByteArray xcode("");;
xcode.append(xml);
QByteArray precode(QByteArray::fromBase64(xcode));
QString notetxt = precode.data();
return notetxt;
}
int Smtp::dateswap(QString form, uint unixtime )
{
QDateTime fromunix;
fromunix.setTime_t(unixtime);
QString numeric = fromunix.toString((const QString)form);
bool ok;
return (int)numeric.toFloat(&ok);
}
QString Smtp::TimeStampMail()
{
/* mail rtf Date format! http://www.faqs.org/rfcs/rfc788.html */
QDateTime timer1( QDateTime::currentDateTime() );
uint unixtime = timer1.toTime_t();
QDateTime fromunix;
fromunix.setTime_t(unixtime);
QStringList RTFdays = QStringList() << "giorno_NULL" << "Mon" << "Tue" << "Wed" << "Thu" << "Fri" << "Sat" << "Sun";
QStringList RTFmonth = QStringList() << "mese_NULL" << "Jan" << "Feb" << "Mar" << "Apr" << "May" << "Jun" << "Jul" << "Aug" << "Sep" << "Oct" << "Nov" << "Dec";
QDate timeroad(dateswap("yyyy",unixtime),dateswap("M",unixtime),dateswap("d",unixtime));
QStringList rtfd_line;
rtfd_line.clear();
rtfd_line.append("Date: ");
rtfd_line.append(RTFdays.at(timeroad.dayOfWeek()));
rtfd_line.append(", ");
rtfd_line.append(QString::number(dateswap("d",unixtime)));
rtfd_line.append(" ");
rtfd_line.append(RTFmonth.at(dateswap("M",unixtime)));
rtfd_line.append(" ");
rtfd_line.append(QString::number(dateswap("yyyy",unixtime)));
rtfd_line.append(" ");
rtfd_line.append(fromunix.toString("hh:mm:ss"));
rtfd_line.append(" +0100");
return QString(rtfd_line.join(""));
}
void Smtp::ErrorCloseAll()
{
delete t;
smtpsocket->close();
}
接下來smtp.h
#ifndef SMTP_H
#define SMTP_H
#include<QtCore>
#include<QObject>
#include<QCoreApplication>
#include <QTcpSocket>
#include <QString>
#include <QTextStream>
#include <QDebug>
#include <QAbstractSocket>
#include <QDateTime>
#include <QDate>
#include <QLocale>
#include <QObject>
#include <QTcpSocket>
class Smtp:public QObject
{
Q_OBJECT
public:
Smtp(QString smtphost,QString smtpusername,QString smtppass);
~Smtp();
bool Send( const QString &to,const QString &subject, const QString &body );
int linesend;
QStringList ErrorMSG;
bool ReadLiner();
void ErrorCloseAll();
signals:
void status( const QString &);
void SendLine();
public slots:
bool PutSendLine();
private:
bool isconnect;
QString smtphost;
QString smtpusername;
QString smtppass;
QString message;
QString output;
QString RemoteServerName;
QString mailstatus;
QTextStream *t;
QTcpSocket *smtpsocket;
QString from;
QString rcpt;
QString response;
QString SendLineAndGrab(QString senddata);
int Timeout;
QString encodeBase64( QString xml );
QString decodeBase64( QString xml );
int dateswap(QString form, uint unixtime );
QString TimeStampMail();
};
#endif // SMTP_H
另外還有需要注意的地方:
1.如果郵件中出現中文亂碼,那麼可以在文件的前面加上代碼就可以了
#pragma execution_character_set("utf-8")
2.點pro文件中需要加入network模塊
3.如果郵箱中需要換行使用<br>而不是\r\n