4nti.g0d.71
جمعه 07 تیر 1392, 15:37 عصر
سلام. من میخواستم از طریق پروتکل smtp یک ایمیل بفرستم.برای این کار چطور باید mail server مناسب را پیدا کنم؟
در ضمن ببخشید اگه یکم این پست بی ربط هست چون نتونستم جای بهتری پیدا کنم.
حامد مصافی
شنبه 08 تیر 1392, 19:47 عصر
من از این روش استفاده کردم.
باید از یک سرویسدهنده با امکان smtp client مانند جیمیل استفاده کنید.
فایل email.cpp
#include "email.h"
#include <QRegExp>
#include <QTextCodec>
#include <QDebug>
#include <QObject>
#include <QDateTime>
#include <QFileInfo>
SmtpAuthData::Data::Data()
{
enableSsl = false;
}
SmtpAuthData::SmtpAuthData()
{
id = -1;
}
void SmtpAuthData::rewriteData(const Data &newData)
{
data = newData;
}
bool SmtpAuthData::isEmpty() const
{
return (id == -1) ? true : false ;
}
QByteArray toBaseAndChunk(const QByteArray &ba)
{
const char alphabet[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef"
"ghijklmn" "opqrstuv" "wxyz0123" "456789+/";
const char padchar = '=';
int padlen = 0;
int baseSize = ba.size();
int counter = 0;
const int CRITICAL_SYMBOL = 76;
const char *underlayindData = ba.data();
const int INSERTED_SYMBOLS = ((baseSize * 4) / 3 + 3) / 38; // ( ((baseSize * 4) / 3 + 3) / 76 * 2)
qDebug() << "Inserted symbols -> " << INSERTED_SYMBOLS;
QByteArray tmp((baseSize * 4) / 3 + 3 + INSERTED_SYMBOLS + 3, Qt::Uninitialized);
int i = 0;
char *out = tmp.data();
while (i < baseSize) {
int chunk = 0;
chunk |= int(uchar(underlayindData[i++])) << 16;
if (i == baseSize) {
padlen = 2;
} else {
chunk |= int(uchar(underlayindData[i++])) << 8;
if (i == baseSize) padlen = 1;
else chunk |= int(uchar(underlayindData[i++]));
}
int j = (chunk & 0x00fc0000) >> 18;
int k = (chunk & 0x0003f000) >> 12;
int l = (chunk & 0x00000fc0) >> 6;
int m = (chunk & 0x0000003f);
if (counter == CRITICAL_SYMBOL)
{
counter = 0;
*out++ = '\r';
*out++ = '\n';
}
*out++ = alphabet[j];
++counter;
if (counter == CRITICAL_SYMBOL)
{
counter = 0;
*out++ = '\r';
*out++ = '\n';
}
*out++ = alphabet[k];
++counter;
if (padlen > 1)
{
if (counter == CRITICAL_SYMBOL)
{
counter = 0;
*out++ = '\r';
*out++ = '\n';
}
*out++ = padchar;
++counter;
}
else
{
if (counter == CRITICAL_SYMBOL)
{
counter = 0;
*out++ = '\r';
*out++ = '\n';
}
*out++ = alphabet[l];
++counter;
}
if (padlen > 0)
{
if (counter == CRITICAL_SYMBOL)
{
counter = 0;
*out++ = '\r';
*out++ = '\n';
}
*out++ = padchar;
++counter;
}
else
{
if (counter == CRITICAL_SYMBOL)
{
counter = 0;
*out++ = '\r';
*out++ = '\n';
}
*out++ = alphabet[m];
++counter;
}
}
tmp.truncate(out - tmp.data());
return tmp;
}
EMail::EMail(const SmtpAuthData &smtpAuthData)
: FILE_SEPARATOR("----------A4D921C2D10D666")
{
_smtpData.rewriteData(smtpAuthData.get_SmtpAuth()) ;
_blockSize = 0;
filesCount = 0;
recipientsExist = false;
_encoding = "windows-1251";
QTextCodec::setCodecForCStrings(QTextCodec::codecF orName("Windows-1251"));
QTextCodec::setCodecForTr(QTextCodec::codecForName ("Windows-1251"));
// init text stream
_stream.setDevice(&_sslSocket);
connect(&_sslSocket, SIGNAL(error(QAbstractSocket::SocketError )),
this, SLOT(error_happens(QAbstractSocket::SocketError )));
connect(&_sslSocket, SIGNAL(sslErrors(QList<QSslError>)),
this, SLOT(sslError_happens(QList<QSslError>)));
connect(&_sslSocket, SIGNAL(readyRead()), this, SLOT(on_read()));
}
void EMail::setSmtpAuth(const SmtpAuthData &smtpAuthData)
{
_smtpData.rewriteData(smtpAuthData.get_SmtpAuth()) ;
}
void EMail::setEncoding(QString encode)
{
// put your coding there and don't
// forget add new enum and comboBox for coding
if (encode == "windows-1251")
{
qDebug() << "choosed win encoding";
_encoding = "windows-1251";
QTextCodec::setCodecForCStrings(QTextCodec::codecF orName("Windows-1251"));
QTextCodec::setCodecForTr(QTextCodec::codecForName ("Windows-1251"));
_stream.setCodec("Windows-1251");
return;
}
else if (encode == "utf-8")
{
qDebug() << "choosed utf-8 encoding";
_encoding = "utf-8";
QTextCodec::setCodecForCStrings(QTextCodec::codecF orName("UTF-8"));
_stream.setCodec("UTF-8");
return;
}
else if (encode == "macintosh")
{
qDebug() << "choosed mac encoding";
_encoding = "macintosh";
QTextCodec::setCodecForCStrings(QTextCodec::codecF orName("Apple Roman"));
_stream.setCodec("Apple Roman");
return;
}
else if (encode == "koi8-u")
{
qDebug() << "choosed koi8-u encoding";
_encoding = "koi8-u";
QTextCodec::setCodecForCStrings(QTextCodec::codecF orName("KOI8-U"));
_stream.setCodec("KOI8-U");
return;
}
else if (encode == "koi8-r")
{
qDebug() << "choosed koi8-r encoding";
_encoding = "koi8-r";
QTextCodec::setCodecForCStrings(QTextCodec::codecF orName("KOI8-R"));
_stream.setCodec("KOI8-R");
return;
}
else
{
qDebug() << "not such encoding in void SmtpAuthData::set_encoding()";
_encoding = "windows-1251";
return;
}
}
void EMail::setSslEncrypting(bool enable)
{
const SmtpAuthData::Data &smtpAuth =
_smtpData.get_SmtpAuth();
SmtpAuthData::Data newData = smtpAuth;
newData.enableSsl = enable;
_smtpData.rewriteData(newData);
}
bool EMail::isEnabledSsl() const
{
const SmtpAuthData::Data &smtpAuth =
_smtpData.get_SmtpAuth();
return smtpAuth.enableSsl;
}
void EMail::setSubject(QString subj)
{
subject = subj;
}
// FIX:: upgrade
void EMail::setText(QString text)
{
qDebug() << "Email at -> " << _smtpData.get_SmtpAuth().email;
// if no including files we send only text mail
if (!filesCount)
this->_body = text;
// else add files to mail
else
{
this->_body.clear();
// prepend plain text
this->_body += QString("--%1\r\n"
"Content-Type: text/plain; charset=%2\r\n"
"Content-Transfer-Encoding: 8bit\r\n\r\n"
"%3\r\n\r\n"
"--%4").arg(FILE_SEPARATOR, _encoding, text, FILE_SEPARATOR);
// prepend encoded files
for (int i = 0; i < filesCount; ++i)
{
QString fileName = extractFileName(_attachementFilesList.at(i));
qDebug() << "After extract";
this->_body += "\r\n";
this->_body += QString(
"Content-Type: application/octet-stream; name=\"%1\"\r\n"
"Content-transfer-encoding: base64\r\n"
"Content-Disposition: attachment; filename=\"%2\"\r\n\r\n"
).arg(fileName, fileName);
this->_body += p_FilesContent[i] + "\r\n";
this->_body += QString("--%1").arg(FILE_SEPARATOR);
}
this->_body += "--";
}
// set header for letter
set_header();
}
void EMail::set_header()
{
_header.clear();
const SmtpAuthData::Data &smtpAuth =
_smtpData.get_SmtpAuth();
_header = "Date: " + QDateTime::currentDateTime().toString("dd.MM.yyyy, hh:mm:ss \r\n");
_header += "From: =?" + _encoding + "?B?" + encodeToBase64(smtpAuth.name) +
"?= <" + smtpAuth.email + ">\r\n";
_header += "X_Mailer: Mail Client 1.0\r\n";
_header += "Reply-To: =?" + _encoding + "B?" +
encodeToBase64(smtpAuth.name) + "?= <" + smtpAuth.email + ">\r\n";
_header += "X-Priority: 3 (Normal)\r\n";
_header += "Message-ID: <172562218." + QDateTime::currentDateTime()
.toString("yyyyMMddhhmmss@%1>\r\n").arg(_smtpItself.mid(5));
_header += "To: ";
QStringList mailTo_List;
for (int i = 0; i < _receiversList.count(); ++i)
{
mailTo_List.append("=?" + _encoding + "?B?" + encodeToBase64(_receiversList.at(i).first) +
"?= <" + _receiversList.at(i).second + ">");
}
if (_receiversList.count() > 1)
_header += mailTo_List.join(", ") + "\r\n";
else
_header += mailTo_List.at(0) + "\r\n";
if (!_blindReceiversList.isEmpty())
{
_header += "Bcc: ";
QStringList mailBcc_List;
for (int i = 0; i < _blindReceiversList.count(); ++i)
{
mailBcc_List.append("=?" + _encoding + "?B?" + encodeToBase64(_blindReceiversList.at(i).first) +
"?= <" + _blindReceiversList.at(i).second + ">");
}
if (_blindReceiversList.count() > 1)
_header += mailBcc_List.join(", ") + "\r\n";
else
_header += mailBcc_List.at(0) + "\r\n";
}
_header += "Subject: =?" + _encoding + "?B?" + encodeToBase64(subject) + "?=\r\n";
_header += "MIME-Version: 1.0\r\n";
if (_attachementFilesList.isEmpty())
{
_header += "Content-Type: text/plain; charset=" + _encoding + "\r\n";
_header += "Content-Transfer-Encoding: 8bit\r\n";
}
else
_header += QString("Content-Type: multipart/mixed; boundary=\"%1\"\r\n")
.arg(FILE_SEPARATOR);
}
void EMail::setReceivers(QString receivers)
{
_receiversList.clear();
QStringList emailGroupList(receivers.split(",", QString::SkipEmptyParts));
if (emailGroupList.empty())
{
emit sendingProcessState("Receiver list not valid");
qDebug() << "Receiver list not valid";
return;
}
for (int i = 0; i < emailGroupList.count(); ++i)
{
QStringList list;
list << emailGroupList.at(i).split(QRegExp("<|>|\"| "), QString::SkipEmptyParts);
if (list.count() > 1)
_receiversList.append(qMakePair(list.at(0), list.at(1)));
else if (list.count() == 1)
_receiversList.append(qMakePair(QString(), list.at(0)));
else
qDebug() << "an error ocured empty list!"
<< "in void Letter::set_receivers(QString receivers()";
}
}
void EMail::setBlindCopyReceivers(QString bl_receivers)
{
_blindReceiversList.clear();
QStringList emailGroupList(bl_receivers.split(",", QString::SkipEmptyParts));
if (emailGroupList.empty())
{
emit sendingProcessState(tr("blind carbon copy not valid"));
return;
}
for (int i = 0; i < emailGroupList.count(); ++i)
{
QStringList list;
list << emailGroupList.at(i).split(QRegExp("<|>|\"| "), QString::SkipEmptyParts);
if (list.count() > 1)
_blindReceiversList.append(qMakePair(list.at(0), list.at(1)));
else if (list.count() == 1)
_blindReceiversList.append(qMakePair(QString(), list.at(0)));
else
qDebug() << "an error ocured empty list!"
<< "in void Letter::set_blindCopyReceivers(QString bl_receivers)";
}
}
void EMail::setAttachement(const QStringList &list)
{
//attachementFilesList = list;
filesCount = list.count();
p_FilesContent = new QByteArray [filesCount];
_attachementFilesList.clear();
for (int i = 0; i < filesCount; ++i)
{
QString attachedFileName = list.at(i);
QFile file(attachedFileName);
if (!file.open(QIODevice::ReadOnly))
{
emit sendingProcessState(tr("Error: attached file %1 isn't opened")
.arg(extractFileName(attachedFileName)));
qDebug() << "file don't open -> " << attachedFileName;
continue;
}
_attachementFilesList.append(attachedFileName);
p_FilesContent[i] = toBaseAndChunk(file.readAll());
}
}
QString EMail::encodeToBase64(QString line)
{
QByteArray encodedArray;
encodedArray.append(line);
return encodedArray.toBase64();
}
QByteArray& EMail::chunk_split(QByteArray &fileContent, int chunklen)
{
int counter = chunklen;
while (counter < fileContent.count())
{
fileContent.insert(counter, "\r\n");
counter += chunklen;
}
return fileContent;
}
QString EMail::extractFileName(const QString &fullName)
{
return QFileInfo(fullName).fileName();
}
void EMail::send()
{
QStringList list;
list = _smtpData.get_email().split("@", QString::SkipEmptyParts);
_smtpItself = QString("smtp.") + list.at(1);
bool ok;
int port = _smtpData.get_port().toInt(&ok);
if (!ok)
port = 587;
// establish new connection
establishConnectionToSocket(port);
}
void EMail::run()
{
send();
}
void EMail::establishConnectionToSocket(int port)
{
// abort previous sending
_sslSocket.abort();
if (isEnabledSsl())
{
qDebug() << "SSL enabled";
_sslSocket.connectToHostEncrypted(_smtpItself, port);
connect(&_sslSocket, SIGNAL(encrypted()), this, SLOT(ready()));
}
else
_sslSocket.connectToHost(_smtpItself, port);
Request = RequestState_Init;
}
void EMail::ready()
{
qDebug() << "Hand shake succeed!!!";
}
void EMail::send_request(QString line)
{
_blockSize = 0;
QDataStream out(&_sslSocket);
out.setVersion(QDataStream::Qt_4_0);
switch (Request)
{
case RequestState_Init :
{
if (line.at(0) != '2')
{
qDebug() << "Servers answer not 220";
emit sendingProcessState(tr("Error: server initiating"));
_sslSocket.close();
break;
}
_stream << "EHLO user\r\n";
_stream.flush();
Request = RequestState_AUTH;
break;
}
case RequestState_AUTH :
{
static bool first_attemp = false;
if (line.at(0) != '2')
{
// if server doesn't support EHLO mode we
// will try old HELO mode
if (!first_attemp)
{
_stream << "HELO user\r\n";
_stream.flush();
first_attemp = true;
Request = RequestState_AUTH;
break;
}
qDebug() << "Servers answer not 250";
emit sendingProcessState(tr("Error: Server not answered"));
_sslSocket.close();
break;
}
_stream << "AUTH LOGIN\r\n";
_stream.flush();
Request = RequestState_AutorizeLogin;
break;
}
case RequestState_AutorizeLogin :
{
if (line.at(0) != '3')
{
qDebug() << "Servers answer not 334";
emit sendingProcessState(tr("Error: AUTH fail"));
_sslSocket.close();
break;
}
const SmtpAuthData::Data &smtpAuth =
_smtpData.get_SmtpAuth();
_stream << encodeToBase64(smtpAuth.login) << "\r\n";
_stream.flush();
Request = RequestState_AutorizePass;
break;
}
case RequestState_AutorizePass :
{
if (line.at(0) != '3')
{
qDebug() << "Servers answer not 334, bad login";
emit sendingProcessState(tr("Error: Login not valid"));
_sslSocket.close();
break;
}
const SmtpAuthData::Data &smtpAuth =
_smtpData.get_SmtpAuth();
_stream << encodeToBase64(smtpAuth.password) << "\r\n";
_stream.flush();
Request = RequestState_From;
break;
}
case RequestState_From :
{
if (line.at(0) != '2')
{
qDebug() << "Servers ansver not 235, bad pass";
emit sendingProcessState(tr("Error: Password not valid"));
_sslSocket.close();
break;
}
const SmtpAuthData::Data &smtpAuth =
_smtpData.get_SmtpAuth();
_stream << QString("MAIL FROM: <%1> SIZE=%2\r\n")
.arg(smtpAuth.email, QString::number(_header.size() + _body.size() + 4));
qDebug() << _header.size();
_stream.flush();
Request = RequestState_To;
break;
}
case RequestState_BlindCopy :
{
if (!recipientsExist)
{
qDebug() << "Servers answer not 250";
emit sendingProcessState(tr("Error: Not one of receivers does not exists"));
_sslSocket.close();
break;
}
if (_blindReceiversList.isEmpty())
{
Request = RequestState_Data;
send_request(line);
break;
}
static int currentItem = 0;
if (line.at(0) != '2' && !currentItem)
{
qDebug() << "Adress for blind copy not valid";
emit sendingProcessState(tr("Error: Adress for blind copy not valid"));
}
_stream << QString("RCPT TO: <%1>\r\n")
.arg(_blindReceiversList.at(currentItem).second);
qDebug() << "Emails to -> " << _blindReceiversList.at(currentItem).second;
_stream.flush();
if (currentItem >= _blindReceiversList.count() - 1)
{
currentItem = 0;
recipientsExist = false;
Request = RequestState_Data;
break;
}
++currentItem;
break;
}
case RequestState_Data :
{
if (line.at(0) != '2')
{
qDebug() << "Adresses for blind copy not valid in case RequestState_Data: ";
emit sendingProcessState(tr("Error: All adresses for blind copy not valid"));
}
_stream << "DATA\r\n";
_stream.flush();
Request = RequestState_Mail;
break;
}
case RequestState_Mail :
{
if (line.at(0) != '3')
{
qDebug() << "Servers ansver not 354 = ";
emit sendingProcessState(tr("Error: Server abort DATA command"));
_sslSocket.close();
break;
}
_stream << _header << "\r\n";
_stream << _body << "\r\n.\r\n";
_stream.flush();
Request = RequestState_Quit;
break;
}
case RequestState_Quit :
{
if (line.at(0) != '2')
{
qDebug() << "Servers ansver not 250";
emit sendingProcessState(tr("Error: Server abort mail sending"));
_sslSocket.close();
break;
}
_stream << "QUIT";
_stream.flush();
// close connection
_sslSocket.close();
emit sendingProcessState(tr("Letter successful sended"), 3);
Request = RequestState_AfterEnd;
break;
}
default :
{
qDebug() << "In default case!!!";
qDebug() << line;
_sslSocket.close();
break;
}
}
}
void EMail::addMoreRecipients(const QString &serverSays)
{
static int currentItem = 0;
if (serverSays.at(0) != '2' && !currentItem)
{
qDebug() << "Servers answer not 250";
emit sendingProcessState(tr("Error: Server abort FROM command"));
_sslSocket.close();
return;
}
else if (serverSays.at(0) == '2' && currentItem)
recipientsExist = true;
if (currentItem >= _receiversList.count())
{
currentItem = 0;
Request = RequestState_BlindCopy;
send_request(serverSays);
return;
}
_stream << QString("RCPT TO: <%1>\r\n")
.arg(_receiversList.at(currentItem).second);
qDebug() << "Emails to -> " << _receiversList.at(currentItem).second;
_stream.flush();
++currentItem;
return;
}
void EMail::on_read()
{
qDebug() << "Ready read -> " << _sslSocket.bytesAvailable();
QDataStream in(&_sslSocket);
in.setVersion(QDataStream::Qt_4_0);
if (_blockSize == 0)
{
if (_sslSocket.bytesAvailable() < (int)sizeof(quint16))
return;
_blockSize = _sslSocket.bytesAvailable();
}
qDebug() << "Block size -> " << _blockSize;
if (_sslSocket.bytesAvailable() < _blockSize)
return;
QString serverRequest;
while (_sslSocket.canReadLine())
{
serverRequest = _sslSocket.readLine();
if (serverRequest.at(3) == ' ')
break;
}
// if we need to add recipients
if (Request == RequestState_To)
addMoreRecipients(serverRequest);
else
send_request(serverRequest);
qDebug() << "Server request -> " << serverRequest;
}
void EMail::error_happens(QAbstractSocket::SocketError socketError)
{
emit sendingProcessState(tr("Помилка: %1")
.arg(_sslSocket.errorString()));
qDebug() << _sslSocket.errorString();
}
void EMail::sslError_happens(const QList<QSslError> &sslErrors)
{
foreach (QSslError error, sslErrors)
qDebug() << error.errorString();
}
EMail::~EMail()
{
_sslSocket.close();
}
فایل email.h:
#ifndef EMAIL_H
#define EMAIL_H
#include <QStringList>
#include <QPair>
#include <stdexcept>
#include <QSslSocket>
#include <QThread>
typedef QList <QPair <QString, QString> > ReceiversList;
class SmtpAuthData
{
public:
struct Data
{
Data();
QString email;
QString login;
QString name;
QString password;
QString port;
bool enableSsl;
};
private:
Data data;
int id;
public:
SmtpAuthData();
// set allmost all data in smtpAuth
void rewriteData(const Data& newData);
// return smtpAuthData
const Data& get_SmtpAuth() const { return data; }
const QString& get_email() const { return data.email; }
const QString& get_name() const { return data.name; }
const QString& get_port() const { return data.port; }
int get_id() const { return id; }
void set_id(int rowId) { id = rowId; }
bool isEmpty() const;
};
class EMail : public QThread
{
Q_OBJECT
QString _header;
QString _body;
QString subject;
QString _encoding;
ReceiversList _receiversList;
ReceiversList _blindReceiversList;
QStringList _attachementFilesList;
QString _smtpItself;
SmtpAuthData _smtpData;
// socket for ssl encrypted connection
QSslSocket _sslSocket;
// stream that operate of protocol
QTextStream _stream;
quint16 _blockSize;
public:
EMail(const SmtpAuthData &smtpAuthData);
~EMail();
void setSmtpAuth(const SmtpAuthData &smtpAuthData);
// set encoding
void setEncoding(QString encode);
// enable or disable ssl encrypting
void setSslEncrypting(bool enable);
const QString& get_encoding() const { return _encoding; }
// set letter text
void setText(QString _body);
void setSubject(QString subj);
// add attachement to file
void setAttachement(const QStringList &list = QStringList());
// get letter text
QString text() { return _body; }
// set receivers
void setReceivers(QString receivers);
// set blind copy receivers
void setBlindCopyReceivers(QString bl_receivers = QString());
// send Letter
void send();
void run();
private:
const QString FILE_SEPARATOR;
enum RequestState { RequestState_Init, RequestState_AUTH, RequestState_AutorizeLogin,
RequestState_AutorizePass,
RequestState_From, RequestState_To, RequestState_BlindCopy,
RequestState_Data,
RequestState_Mail, RequestState_Quit, RequestState_AfterEnd} Request;
QString encodeToBase64(QString line);
void on_connect();
void send_request(QString line);
void set_header();
QByteArray& chunk_split(QByteArray &fileContent, int chunklen = 76);
QString extractFileName(const QString &fullName);
void addMoreRecipients(const QString &serverSays);
void establishConnectionToSocket(int port);
bool isEnabledSsl() const;
QByteArray *p_FilesContent;
int filesCount;
bool recipientsExist;
private slots:
void error_happens(QAbstractSocket::SocketError socketError);
void sslError_happens(const QList<QSslError> &sslErrors);
void on_read();
void ready();
signals:
void sendingProcessState(QString stateString, int duration = 1);};
#endif // EMAIL_H
نحوه استفاده :
SmtpAuthData authData;
SmtpAuthData::Data data;
data.email = "my_name@gmail.com";
data.login = "my_name@gmail.com";
data.password = "***";
data.port = "465";
data.enableSsl = true;
authData.rewriteData(data);
EMail letter(authData);
QString receivers = QString::fromUtf8("reciver@gmail.com");
letter.setEncoding("utf-8");
letter.setReceivers(receivers);
letter.setSubject("subject");
letter.setText("body");
letter.send();
4nti.g0d.71
دوشنبه 10 تیر 1392, 15:58 عصر
ممنونم ازتون. ولی من مشکلی در نحوه ی ارسال و اسفاده از این پروتکل ندارم.فقط خواستم بدونم چجوری اون client smtp رو پیدا کنیم که باهاش ارتباط برقرار کنیم؟
vBulletin® v4.2.5, Copyright ©2000-1404, Jelsoft Enterprises Ltd.