From 1d371bef97b1885e8c9e0403f9ae92aa5b6c3e4f Mon Sep 17 00:00:00 2001 From: feiyangqingyun Date: Thu, 21 Nov 2019 14:28:56 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=82=AE=E4=BB=B6=E5=8F=91?= =?UTF-8?q?=E9=80=81=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +- email/email.pro | 27 ++ email/frmemailtool.cpp | 104 ++++++ email/frmemailtool.h | 35 ++ email/frmemailtool.ui | 223 +++++++++++++ email/main.cpp | 31 ++ email/sendemail/emailaddress.cpp | 31 ++ email/sendemail/emailaddress.h | 28 ++ email/sendemail/mimeattachment.cpp | 17 + email/sendemail/mimeattachment.h | 20 ++ email/sendemail/mimecontentformatter.cpp | 51 +++ email/sendemail/mimecontentformatter.h | 23 ++ email/sendemail/mimefile.cpp | 23 ++ email/sendemail/mimefile.h | 21 ++ email/sendemail/mimehtml.cpp | 23 ++ email/sendemail/mimehtml.h | 21 ++ email/sendemail/mimeinlinefile.cpp | 15 + email/sendemail/mimeinlinefile.h | 18 ++ email/sendemail/mimemessage.cpp | 222 +++++++++++++ email/sendemail/mimemessage.h | 54 ++++ email/sendemail/mimemultipart.cpp | 67 ++++ email/sendemail/mimemultipart.h | 37 +++ email/sendemail/mimepart.cpp | 171 ++++++++++ email/sendemail/mimepart.h | 67 ++++ email/sendemail/mimetext.cpp | 28 ++ email/sendemail/mimetext.h | 22 ++ email/sendemail/quotedprintable.cpp | 43 +++ email/sendemail/quotedprintable.h | 19 ++ email/sendemail/sendemail.pri | 30 ++ email/sendemail/sendemailthread.cpp | 147 +++++++++ email/sendemail/sendemailthread.h | 44 +++ email/sendemail/smtpclient.cpp | 390 +++++++++++++++++++++++ email/sendemail/smtpclient.h | 103 ++++++ email/sendemail/smtpmime.h | 13 + 34 files changed, 2170 insertions(+), 1 deletion(-) create mode 100644 email/email.pro create mode 100644 email/frmemailtool.cpp create mode 100644 email/frmemailtool.h create mode 100644 email/frmemailtool.ui create mode 100644 email/main.cpp create mode 100644 email/sendemail/emailaddress.cpp create mode 100644 email/sendemail/emailaddress.h create mode 100644 email/sendemail/mimeattachment.cpp create mode 100644 email/sendemail/mimeattachment.h create mode 100644 email/sendemail/mimecontentformatter.cpp create mode 100644 email/sendemail/mimecontentformatter.h create mode 100644 email/sendemail/mimefile.cpp create mode 100644 email/sendemail/mimefile.h create mode 100644 email/sendemail/mimehtml.cpp create mode 100644 email/sendemail/mimehtml.h create mode 100644 email/sendemail/mimeinlinefile.cpp create mode 100644 email/sendemail/mimeinlinefile.h create mode 100644 email/sendemail/mimemessage.cpp create mode 100644 email/sendemail/mimemessage.h create mode 100644 email/sendemail/mimemultipart.cpp create mode 100644 email/sendemail/mimemultipart.h create mode 100644 email/sendemail/mimepart.cpp create mode 100644 email/sendemail/mimepart.h create mode 100644 email/sendemail/mimetext.cpp create mode 100644 email/sendemail/mimetext.h create mode 100644 email/sendemail/quotedprintable.cpp create mode 100644 email/sendemail/quotedprintable.h create mode 100644 email/sendemail/sendemail.pri create mode 100644 email/sendemail/sendemailthread.cpp create mode 100644 email/sendemail/sendemailthread.h create mode 100644 email/sendemail/smtpclient.cpp create mode 100644 email/sendemail/smtpclient.h create mode 100644 email/sendemail/smtpmime.h diff --git a/README.md b/README.md index 6b1ecaa..7d0cf14 100644 --- a/README.md +++ b/README.md @@ -26,4 +26,5 @@ | 23 | zhtopy | 汉字转拼音 | | 24 | qwtdemo | qwt的源码版本,无需插件,直接源码集成到你的项目即可 | | 25 | buttondefence | 通用按钮地图效果 | -| 25 | mouseline | 鼠标定位十字线 | \ No newline at end of file +| 26 | mouseline | 鼠标定位十字线 | +| 27 | email | 邮件发送工具 | \ No newline at end of file diff --git a/email/email.pro b/email/email.pro new file mode 100644 index 0000000..9fdad7e --- /dev/null +++ b/email/email.pro @@ -0,0 +1,27 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2016-09-29T13:23:25 +# +#------------------------------------------------- + +QT += core gui network sql xml + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = emailtool +TEMPLATE = app +MOC_DIR = temp/moc +RCC_DIR = temp/rcc +UI_DIR = temp/ui +OBJECTS_DIR = temp/obj +DESTDIR = bin + +CONFIG += warn_off +SOURCES += main.cpp +SOURCES += frmemailtool.cpp +HEADERS += frmemailtool.h +FORMS += frmemailtool.ui + +include ($$PWD/sendemail/sendemail.pri) +INCLUDEPATH += $$PWD +INCLUDEPATH += $$PWD/sendemail diff --git a/email/frmemailtool.cpp b/email/frmemailtool.cpp new file mode 100644 index 0000000..502ebe9 --- /dev/null +++ b/email/frmemailtool.cpp @@ -0,0 +1,104 @@ +#pragma execution_character_set("utf-8") + +#include "frmemailtool.h" +#include "ui_frmemailtool.h" +#include "qfiledialog.h" +#include "qmessagebox.h" +#include "sendemailthread.h" + +frmEmailTool::frmEmailTool(QWidget *parent) : QWidget(parent), ui(new Ui::frmEmailTool) +{ + ui->setupUi(this); + this->initForm(); +} + +frmEmailTool::~frmEmailTool() +{ + delete ui; +} + +void frmEmailTool::initForm() +{ + ui->cboxServer->setCurrentIndex(1); + connect(SendEmailThread::Instance(), SIGNAL(receiveEmailResult(QString)), + this, SLOT(receiveEmailResult(QString))); + SendEmailThread::Instance()->start(); +} + +void frmEmailTool::on_btnSend_clicked() +{ + if (!check()) { + return; + } + + SendEmailThread::Instance()->setEmialTitle(ui->txtTitle->text()); + SendEmailThread::Instance()->setSendEmailAddr(ui->txtSenderAddr->text()); + SendEmailThread::Instance()->setSendEmailPwd(ui->txtSenderPwd->text()); + SendEmailThread::Instance()->setReceiveEmailAddr(ui->txtReceiverAddr->text()); + + //设置好上述配置后,以后只要调用Append方法即可发送邮件 + SendEmailThread::Instance()->append(ui->txtContent->toHtml(), ui->txtFileName->text()); +} + +void frmEmailTool::on_btnSelect_clicked() +{ + QFileDialog dialog(this); + dialog.setFileMode(QFileDialog::ExistingFiles); + + if (dialog.exec()) { + ui->txtFileName->clear(); + QStringList files = dialog.selectedFiles(); + ui->txtFileName->setText(files.join(";")); + } +} + +bool frmEmailTool::check() +{ + if (ui->txtSenderAddr->text() == "") { + QMessageBox::critical(this, "错误", "用户名不能为空!"); + ui->txtSenderAddr->setFocus(); + return false; + } + + if (ui->txtSenderPwd->text() == "") { + QMessageBox::critical(this, "错误", "用户密码不能为空!"); + ui->txtSenderPwd->setFocus(); + return false; + } + + if (ui->txtSenderAddr->text() == "") { + QMessageBox::critical(this, "错误", "发件人不能为空!"); + ui->txtSenderAddr->setFocus(); + return false; + } + + if (ui->txtReceiverAddr->text() == "") { + QMessageBox::critical(this, "错误", "收件人不能为空!"); + ui->txtReceiverAddr->setFocus(); + return false; + } + + if (ui->txtTitle->text() == "") { + QMessageBox::critical(this, "错误", "邮件标题不能为空!"); + ui->txtTitle->setFocus(); + return false; + } + + return true; +} + +void frmEmailTool::on_cboxServer_currentIndexChanged(int index) +{ + if (index == 2) { + ui->cboxPort->setCurrentIndex(1); + ui->ckSSL->setChecked(true); + } else { + ui->cboxPort->setCurrentIndex(0); + ui->ckSSL->setChecked(false); + } +} + +void frmEmailTool::receiveEmailResult(QString result) +{ + QMessageBox::information(this, "提示", result); +} diff --git a/email/frmemailtool.h b/email/frmemailtool.h new file mode 100644 index 0000000..0d0916f --- /dev/null +++ b/email/frmemailtool.h @@ -0,0 +1,35 @@ +#ifndef FRMEMAILTOOL_H +#define FRMEMAILTOOL_H + +#include + +namespace Ui +{ +class frmEmailTool; +} + +class frmEmailTool : public QWidget +{ + Q_OBJECT + +public: + explicit frmEmailTool(QWidget *parent = 0); + ~frmEmailTool(); + +private: + Ui::frmEmailTool *ui; + +private: + bool check(); + +private slots: + void initForm(); + void receiveEmailResult(QString result); + +private slots: + void on_btnSend_clicked(); + void on_btnSelect_clicked(); + void on_cboxServer_currentIndexChanged(int index); +}; + +#endif // FRMEMAILTOOL_H diff --git a/email/frmemailtool.ui b/email/frmemailtool.ui new file mode 100644 index 0000000..05e5549 --- /dev/null +++ b/email/frmemailtool.ui @@ -0,0 +1,223 @@ + + + frmEmailTool + + + + 0 + 0 + 764 + 578 + + + + Form + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + 用户名: + + + + + + + feiyangqingyun@126.com + + + + + + + 密码: + + + + + + + + + + QLineEdit::Password + + + + + + + 服务器: + + + + + + + + smtp.163.com + + + + + smtp.126.com + + + + + smtp.qq.com + + + + + smt.sina.com + + + + + smtp.sohu.com + + + + + smtp.139.com + + + + + smtp.189.com + + + + + + + + 端口: + + + + + + + + 25 + + + + + 465 + + + + + 587 + + + + + + + + SSL + + + + + + + PointingHandCursor + + + 发送 + + + + + + + 标 题: + + + + + + + 附 件: + + + + + + + 正 文: + + + + + + + PointingHandCursor + + + 浏览 + + + + + + + + + + false + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'宋体'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:11pt;">1</span><span style=" font-family:'Times New Roman'; font-size:11pt;">、最短的爱情哲理小说:“</span><span style=" font-size:11pt;">你应该嫁给我啦?</span><span style=" font-family:'Times New Roman'; font-size:11pt;">” “ </span><span style=" font-size:11pt;">不</span><span style=" font-family:'Times New Roman'; font-size:11pt;">” </span><span style=" font-size:11pt;">于是他俩又继续幸福地生活在一起</span><span style=" font-family:'Times New Roman'; font-size:11pt;">!<br /></span><span style=" font-size:11pt;">2</span><span style=" font-family:'Times New Roman'; font-size:11pt;">、近年来中国最精彩的写实小说,全文八个字:</span><span style=" font-family:'Times New Roman'; font-size:16pt; font-weight:600; font-style:italic; color:#ff007f;">此地钱多人傻速来</span><span style=" font-family:'Times New Roman'; font-size:11pt;">  据说是发自杭州市宝石山下一出租房的汇款单上的简短附言,是该按摩女给家乡妹妹汇 款时随手涂鸦的,令无数专业作家汗颜!<br /></span><span style=" font-size:11pt;">3</span><span style=" font-family:'Times New Roman'; font-size:11pt;">、最短的幽默小说 《夜》 男:疼么?女:恩!男:算了?女:别!</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:11pt;">4</span><span style=" font-family:'Times New Roman'; font-size:11pt;">、最短的荒诞小说:有一个面包走在街上,它觉得自己很饿,就把自己吃了。<br /></span><span style=" font-size:11pt;">5</span><span style=" font-family:'Times New Roman'; font-size:11pt;">、世界最短言情小说:他死的那天,孩子出生了。<br /></span><span style=" font-size:11pt;">6</span><span style=" font-family:'Times New Roman'; font-size:11pt;">、世界最短武侠小说:</span><span style=" font-family:'Times New Roman'; font-size:11pt; font-weight:600; color:#00aa00;">高手被豆腐砸死了</span><span style=" font-family:'Times New Roman'; font-size:11pt;">。<br /></span><span style=" font-size:11pt;">7</span><span style=" font-family:'Times New Roman'; font-size:11pt;">、世界最短科幻小说:最后一个地球人坐在家里,突然响起了敲门声。<br /></span><span style=" font-size:11pt;">8</span><span style=" font-family:'Times New Roman'; font-size:11pt;">、世界最短悬疑小说:生,死,生。<br /></span><span style=" font-size:11pt;">9</span><span style=" font-family:'Times New Roman'; font-size:11pt;">、世界最短推理小说:他死了,一定曾经活过。 <br />1</span><span style=" font-size:11pt;">0</span><span style=" font-family:'Times New Roman'; font-size:11pt;">、世界最短恐怖小说:惊醒,身边躺着自己的尸体。</span></p></body></html> + + + + + + + 测试邮件 + + + + + + + 收件人: + + + + + + + feiyangqingyun@163.com;517216493@qq.com + + + + + + + + diff --git a/email/main.cpp b/email/main.cpp new file mode 100644 index 0000000..3741ddc --- /dev/null +++ b/email/main.cpp @@ -0,0 +1,31 @@ +#pragma execution_character_set("utf-8") + +#include "frmemailtool.h" +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + a.setFont(QFont("Microsoft Yahei", 9)); + +#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0)) +#if _MSC_VER + QTextCodec *codec = QTextCodec::codecForName("gbk"); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); +#endif + QTextCodec::setCodecForLocale(codec); + QTextCodec::setCodecForCStrings(codec); + QTextCodec::setCodecForTr(codec); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); + QTextCodec::setCodecForLocale(codec); +#endif + + frmEmailTool w; + w.setWindowTitle("邮件发送工具"); + w.show(); + + return a.exec(); +} diff --git a/email/sendemail/emailaddress.cpp b/email/sendemail/emailaddress.cpp new file mode 100644 index 0000000..808ce43 --- /dev/null +++ b/email/sendemail/emailaddress.cpp @@ -0,0 +1,31 @@ +#include "emailaddress.h" + +EmailAddress::EmailAddress(const QString &address, const QString &name) +{ + this->address = address; + this->name = name; +} + +EmailAddress::~EmailAddress() +{ +} + +void EmailAddress::setName(const QString &name) +{ + this->name = name; +} + +void EmailAddress::setAddress(const QString &address) +{ + this->address = address; +} + +const QString &EmailAddress::getName() const +{ + return name; +} + +const QString &EmailAddress::getAddress() const +{ + return address; +} diff --git a/email/sendemail/emailaddress.h b/email/sendemail/emailaddress.h new file mode 100644 index 0000000..0ea0e05 --- /dev/null +++ b/email/sendemail/emailaddress.h @@ -0,0 +1,28 @@ +#ifndef EMAILADDRESS_H +#define EMAILADDRESS_H + +#include + +class EmailAddress : public QObject +{ + Q_OBJECT +public: + + EmailAddress(); + EmailAddress(const QString &address, const QString &name = ""); + + ~EmailAddress(); + + void setName(const QString &name); + void setAddress(const QString &address); + + const QString &getName() const; + const QString &getAddress() const; + +private: + QString name; + QString address; + +}; + +#endif // EMAILADDRESS_H diff --git a/email/sendemail/mimeattachment.cpp b/email/sendemail/mimeattachment.cpp new file mode 100644 index 0000000..aae9c4c --- /dev/null +++ b/email/sendemail/mimeattachment.cpp @@ -0,0 +1,17 @@ +#include "mimeattachment.h" +#include + +MimeAttachment::MimeAttachment(QFile *file) + : MimeFile(file) +{ +} + +MimeAttachment::~MimeAttachment() +{ +} + +void MimeAttachment::prepare() +{ + this->header += "Content-disposition: attachment\r\n"; + MimeFile::prepare(); +} diff --git a/email/sendemail/mimeattachment.h b/email/sendemail/mimeattachment.h new file mode 100644 index 0000000..e9ea1fa --- /dev/null +++ b/email/sendemail/mimeattachment.h @@ -0,0 +1,20 @@ +#ifndef MIMEATTACHMENT_H +#define MIMEATTACHMENT_H + +#include +#include "mimepart.h" +#include "mimefile.h" + +class MimeAttachment : public MimeFile +{ + Q_OBJECT +public: + MimeAttachment(QFile *file); + ~MimeAttachment(); + +protected: + virtual void prepare(); + +}; + +#endif // MIMEATTACHMENT_H diff --git a/email/sendemail/mimecontentformatter.cpp b/email/sendemail/mimecontentformatter.cpp new file mode 100644 index 0000000..cadce81 --- /dev/null +++ b/email/sendemail/mimecontentformatter.cpp @@ -0,0 +1,51 @@ +#include "mimecontentformatter.h" + +MimeContentFormatter::MimeContentFormatter(int max_length) : + max_length(max_length) +{} + +QString MimeContentFormatter::format(const QString &content, bool quotedPrintable) const +{ + QString out; + + int chars = 0; + + for (int i = 0; i < content.length() ; ++i) { + chars++; + + if (!quotedPrintable) { + if (chars > max_length) { + out.append("\r\n"); + chars = 1; + } + } else { + if (content.at(i) == '\n') { // new line + out.append(content.at(i)); + chars = 0; + continue; + } + + if ((chars > max_length - 1) + || ((content.at(i) == '=') && (chars > max_length - 3))) { + out.append('='); + out.append("\r\n"); + chars = 1; + } + + } + + out.append(content.at(i)); + } + + return out; +} + +void MimeContentFormatter::setMaxLength(int l) +{ + max_length = l; +} + +int MimeContentFormatter::getMaxLength() const +{ + return max_length; +} diff --git a/email/sendemail/mimecontentformatter.h b/email/sendemail/mimecontentformatter.h new file mode 100644 index 0000000..8b24b9a --- /dev/null +++ b/email/sendemail/mimecontentformatter.h @@ -0,0 +1,23 @@ +#ifndef MIMECONTENTFORMATTER_H +#define MIMECONTENTFORMATTER_H + +#include +#include + +class MimeContentFormatter : public QObject +{ + Q_OBJECT +public: + MimeContentFormatter(int max_length = 76); + + void setMaxLength(int l); + int getMaxLength() const; + + QString format(const QString &content, bool quotedPrintable = false) const; + +protected: + int max_length; + +}; + +#endif // MIMECONTENTFORMATTER_H diff --git a/email/sendemail/mimefile.cpp b/email/sendemail/mimefile.cpp new file mode 100644 index 0000000..02648aa --- /dev/null +++ b/email/sendemail/mimefile.cpp @@ -0,0 +1,23 @@ +#include "mimefile.h" +#include + +MimeFile::MimeFile(QFile *file) +{ + this->file = file; + this->cType = "application/octet-stream"; + this->cName = QFileInfo(*file).fileName(); + this->cEncoding = Base64; +} + +MimeFile::~MimeFile() +{ + delete file; +} + +void MimeFile::prepare() +{ + file->open(QIODevice::ReadOnly); + this->content = file->readAll(); + file->close(); + MimePart::prepare(); +} diff --git a/email/sendemail/mimefile.h b/email/sendemail/mimefile.h new file mode 100644 index 0000000..e85e0c5 --- /dev/null +++ b/email/sendemail/mimefile.h @@ -0,0 +1,21 @@ +#ifndef MIMEFILE_H +#define MIMEFILE_H + +#include "mimepart.h" +#include + +class MimeFile : public MimePart +{ + Q_OBJECT +public: + + MimeFile(QFile *f); + ~MimeFile(); + +protected: + QFile *file; + virtual void prepare(); + +}; + +#endif // MIMEFILE_H diff --git a/email/sendemail/mimehtml.cpp b/email/sendemail/mimehtml.cpp new file mode 100644 index 0000000..2bde903 --- /dev/null +++ b/email/sendemail/mimehtml.cpp @@ -0,0 +1,23 @@ +#include "mimehtml.h" + +MimeHtml::MimeHtml(const QString &html) : MimeText(html) +{ + this->cType = "text/html"; +} + +MimeHtml::~MimeHtml() {} + +void MimeHtml::setHtml(const QString &html) +{ + this->text = html; +} + +const QString &MimeHtml::getHtml() const +{ + return text; +} + +void MimeHtml::prepare() +{ + MimeText::prepare(); +} diff --git a/email/sendemail/mimehtml.h b/email/sendemail/mimehtml.h new file mode 100644 index 0000000..111bb31 --- /dev/null +++ b/email/sendemail/mimehtml.h @@ -0,0 +1,21 @@ +#ifndef MIMEHTML_H +#define MIMEHTML_H + +#include "mimetext.h" + +class MimeHtml : public MimeText +{ + Q_OBJECT +public: + MimeHtml(const QString &html = ""); + ~MimeHtml(); + + void setHtml(const QString &html); + const QString &getHtml() const; + +protected: + virtual void prepare(); + +}; + +#endif // MIMEHTML_H diff --git a/email/sendemail/mimeinlinefile.cpp b/email/sendemail/mimeinlinefile.cpp new file mode 100644 index 0000000..f24be61 --- /dev/null +++ b/email/sendemail/mimeinlinefile.cpp @@ -0,0 +1,15 @@ +#include "mimeinlinefile.h" + +MimeInlineFile::MimeInlineFile(QFile *f) + : MimeFile(f) +{ +} + +MimeInlineFile::~MimeInlineFile() +{} + +void MimeInlineFile::prepare() +{ + this->header += "Content-Disposition: inline\r\n"; + MimeFile::prepare(); +} diff --git a/email/sendemail/mimeinlinefile.h b/email/sendemail/mimeinlinefile.h new file mode 100644 index 0000000..121af25 --- /dev/null +++ b/email/sendemail/mimeinlinefile.h @@ -0,0 +1,18 @@ +#ifndef MIMEINLINEFILE_H +#define MIMEINLINEFILE_H + +#include "mimefile.h" + +class MimeInlineFile : public MimeFile +{ +public: + + MimeInlineFile(QFile *f); + ~MimeInlineFile(); + +protected: + virtual void prepare(); + +}; + +#endif // MIMEINLINEFILE_H diff --git a/email/sendemail/mimemessage.cpp b/email/sendemail/mimemessage.cpp new file mode 100644 index 0000000..691bf74 --- /dev/null +++ b/email/sendemail/mimemessage.cpp @@ -0,0 +1,222 @@ +#include "mimemessage.h" + +#include +#include "quotedprintable.h" +#include + +MimeMessage::MimeMessage(bool createAutoMimeContent) : + hEncoding(MimePart::_8Bit) +{ + if (createAutoMimeContent) { + this->content = new MimeMultiPart(); + } +} + +MimeMessage::~MimeMessage() +{ +} + +MimePart &MimeMessage::getContent() +{ + return *content; +} + +void MimeMessage::setContent(MimePart *content) +{ + this->content = content; +} + +void MimeMessage::setSender(EmailAddress *e) +{ + this->sender = e; +} + +void MimeMessage::addRecipient(EmailAddress *rcpt, RecipientType type) +{ + switch (type) { + case To: + recipientsTo << rcpt; + break; + + case Cc: + recipientsCc << rcpt; + break; + + case Bcc: + recipientsBcc << rcpt; + break; + } +} + +void MimeMessage::addTo(EmailAddress *rcpt) +{ + this->recipientsTo << rcpt; +} + +void MimeMessage::addCc(EmailAddress *rcpt) +{ + this->recipientsCc << rcpt; +} + +void MimeMessage::addBcc(EmailAddress *rcpt) +{ + this->recipientsBcc << rcpt; +} + +void MimeMessage::setSubject(const QString &subject) +{ + this->subject = subject; +} + +void MimeMessage::addPart(MimePart *part) +{ + if (typeid(*content) == typeid(MimeMultiPart)) { + ((MimeMultiPart *) content)->addPart(part); + }; +} + +void MimeMessage::setHeaderEncoding(MimePart::Encoding hEnc) +{ + this->hEncoding = hEnc; +} + +const EmailAddress &MimeMessage::getSender() const +{ + return *sender; +} + +const QList &MimeMessage::getRecipients(RecipientType type) const +{ + switch (type) { + default: + case To: + return recipientsTo; + + case Cc: + return recipientsCc; + + case Bcc: + return recipientsBcc; + } +} + +const QString &MimeMessage::getSubject() const +{ + return subject; +} + +const QList &MimeMessage::getParts() const +{ + if (typeid(*content) == typeid(MimeMultiPart)) { + return ((MimeMultiPart *) content)->getParts(); + } else { + QList *res = new QList(); + res->append(content); + return *res; + } +} + +QString MimeMessage::toString() +{ + QString mime; + + mime = "From:"; + + if (sender->getName() != "") { + switch (hEncoding) { + case MimePart::Base64: + mime += " =?utf-8?B?" + QByteArray().append(sender->getName()).toBase64() + "?="; + break; + + case MimePart::QuotedPrintable: + mime += " =?utf-8?Q?" + QuotedPrintable::encode(QByteArray().append(sender->getName())).replace(' ', "_").replace(':', "=3A") + "?="; + break; + + default: + mime += " " + sender->getName(); + } + } + + mime += " <" + sender->getAddress() + ">\r\n"; + + mime += "To:"; + QList::iterator it; + int i; + + for (i = 0, it = recipientsTo.begin(); it != recipientsTo.end(); ++it, ++i) { + if (i != 0) { + mime += ","; + } + + if ((*it)->getName() != "") { + switch (hEncoding) { + case MimePart::Base64: + mime += " =?utf-8?B?" + QByteArray().append((*it)->getName()).toBase64() + "?="; + break; + + case MimePart::QuotedPrintable: + mime += " =?utf-8?Q?" + QuotedPrintable::encode(QByteArray().append((*it)->getName())).replace(' ', "_").replace(':', "=3A") + "?="; + break; + + default: + mime += " " + (*it)->getName(); + } + } + + mime += " <" + (*it)->getAddress() + ">"; + } + + mime += "\r\n"; + + if (recipientsCc.size() != 0) { + mime += "Cc:"; + } + + for (i = 0, it = recipientsCc.begin(); it != recipientsCc.end(); ++it, ++i) { + if (i != 0) { + mime += ","; + } + + if ((*it)->getName() != "") { + switch (hEncoding) { + case MimePart::Base64: + mime += " =?utf-8?B?" + QByteArray().append((*it)->getName()).toBase64() + "?="; + break; + + case MimePart::QuotedPrintable: + mime += " =?utf-8?Q?" + QuotedPrintable::encode(QByteArray().append((*it)->getName())).replace(' ', "_").replace(':', "=3A") + "?="; + break; + + default: + mime += " " + (*it)->getName(); + } + } + + mime += " <" + (*it)->getAddress() + ">"; + } + + if (recipientsCc.size() != 0) { + mime += "\r\n"; + } + + mime += "Subject: "; + + switch (hEncoding) { + case MimePart::Base64: + mime += "=?utf-8?B?" + QByteArray().append(subject).toBase64() + "?="; + break; + + case MimePart::QuotedPrintable: + mime += "=?utf-8?Q?" + QuotedPrintable::encode(QByteArray().append(subject)).replace(' ', "_").replace(':', "=3A") + "?="; + break; + + default: + mime += subject; + } + + mime += "\r\n"; + mime += "MIME-Version: 1.0\r\n"; + + mime += content->toString(); + return mime; +} diff --git a/email/sendemail/mimemessage.h b/email/sendemail/mimemessage.h new file mode 100644 index 0000000..569b596 --- /dev/null +++ b/email/sendemail/mimemessage.h @@ -0,0 +1,54 @@ +#ifndef MIMEMESSAGE_H +#define MIMEMESSAGE_H + +#include "mimepart.h" +#include "mimemultipart.h" +#include "emailaddress.h" +#include + +class MimeMessage : public QObject +{ +public: + + enum RecipientType { + To, // primary + Cc, // carbon copy + Bcc // blind carbon copy + }; + + + MimeMessage(bool createAutoMimeConent = true); + ~MimeMessage(); + + void setSender(EmailAddress *e); + void addRecipient(EmailAddress *rcpt, RecipientType type = To); + void addTo(EmailAddress *rcpt); + void addCc(EmailAddress *rcpt); + void addBcc(EmailAddress *rcpt); + void setSubject(const QString &subject); + void addPart(MimePart *part); + + void setHeaderEncoding(MimePart::Encoding); + + const EmailAddress &getSender() const; + const QList &getRecipients(RecipientType type = To) const; + const QString &getSubject() const; + const QList &getParts() const; + + MimePart &getContent(); + void setContent(MimePart *content); + + virtual QString toString(); + + +protected: + EmailAddress *sender; + QList recipientsTo, recipientsCc, recipientsBcc; + QString subject; + MimePart *content; + + MimePart::Encoding hEncoding; + +}; + +#endif // MIMEMESSAGE_H diff --git a/email/sendemail/mimemultipart.cpp b/email/sendemail/mimemultipart.cpp new file mode 100644 index 0000000..27196f7 --- /dev/null +++ b/email/sendemail/mimemultipart.cpp @@ -0,0 +1,67 @@ +#include "mimemultipart.h" +#include +#include + +const QString MULTI_PART_NAMES[] = { + "multipart/mixed", // Mixed + "multipart/digest", // Digest + "multipart/alternative", // Alternative + "multipart/related", // Related + "multipart/report", // Report + "multipart/signed", // Signed + "multipart/encrypted" // Encrypted +}; + +MimeMultiPart::MimeMultiPart(MultiPartType type) +{ + this->type = type; + this->cType = MULTI_PART_NAMES[this->type]; + this->cEncoding = _8Bit; + + QCryptographicHash md5(QCryptographicHash::Md5); + md5.addData(QByteArray().append(qrand())); + cBoundary = md5.result().toHex(); +} + +MimeMultiPart::~MimeMultiPart() +{ + +} + +void MimeMultiPart::addPart(MimePart *part) +{ + parts.append(part); +} + +const QList &MimeMultiPart::getParts() const +{ + return parts; +} + +void MimeMultiPart::prepare() +{ + QList::iterator it; + + content = ""; + + for (it = parts.begin(); it != parts.end(); it++) { + content += "--" + cBoundary + "\r\n"; + (*it)->prepare(); + content += (*it)->toString(); + }; + + content += "--" + cBoundary + "--\r\n"; + + MimePart::prepare(); +} + +void MimeMultiPart::setMimeType(const MultiPartType type) +{ + this->type = type; + this->cType = MULTI_PART_NAMES[type]; +} + +MimeMultiPart::MultiPartType MimeMultiPart::getMimeType() const +{ + return type; +} diff --git a/email/sendemail/mimemultipart.h b/email/sendemail/mimemultipart.h new file mode 100644 index 0000000..bc716ae --- /dev/null +++ b/email/sendemail/mimemultipart.h @@ -0,0 +1,37 @@ +#ifndef MIMEMULTIPART_H +#define MIMEMULTIPART_H + +#include "mimepart.h" + +class MimeMultiPart : public MimePart +{ + Q_OBJECT +public: + enum MultiPartType { + Mixed = 0, // RFC 2046, section 5.1.3 + Digest = 1, // RFC 2046, section 5.1.5 + Alternative = 2, // RFC 2046, section 5.1.4 + Related = 3, // RFC 2387 + Report = 4, // RFC 6522 + Signed = 5, // RFC 1847, section 2.1 + Encrypted = 6 // RFC 1847, section 2.2 + }; + + MimeMultiPart(const MultiPartType type = Related); + ~MimeMultiPart(); + + void setMimeType(const MultiPartType type); + MultiPartType getMimeType() const; + + const QList &getParts() const; + + void addPart(MimePart *part); + virtual void prepare(); + +protected: + QList parts; + MultiPartType type; + +}; + +#endif // MIMEMULTIPART_H diff --git a/email/sendemail/mimepart.cpp b/email/sendemail/mimepart.cpp new file mode 100644 index 0000000..e9d0f65 --- /dev/null +++ b/email/sendemail/mimepart.cpp @@ -0,0 +1,171 @@ +#include "mimepart.h" +#include "quotedprintable.h" + +MimePart::MimePart() +{ + cEncoding = _7Bit; + prepared = false; + cBoundary = ""; +} + +MimePart::~MimePart() +{ + return; +} + +void MimePart::setContent(const QByteArray &content) +{ + this->content = content; +} + +void MimePart::setHeader(const QString &header) +{ + this->header = header; +} + +void MimePart::addHeaderLine(const QString &line) +{ + this->header += line + "\r\n"; +} + +const QString &MimePart::getHeader() const +{ + return header; +} + +const QByteArray &MimePart::getContent() const +{ + return content; +} + +void MimePart::setContentId(const QString &cId) +{ + this->cId = cId; +} + +const QString &MimePart::getContentId() const +{ + return this->cId; +} + +void MimePart::setContentName(const QString &cName) +{ + this->cName = cName; +} + +const QString &MimePart::getContentName() const +{ + return this->cName; +} + +void MimePart::setContentType(const QString &cType) +{ + this->cType = cType; +} + +const QString &MimePart::getContentType() const +{ + return this->cType; +} + +void MimePart::setCharset(const QString &charset) +{ + this->cCharset = charset; +} + +const QString &MimePart::getCharset() const +{ + return this->cCharset; +} + +void MimePart::setEncoding(Encoding enc) +{ + this->cEncoding = enc; +} + +MimePart::Encoding MimePart::getEncoding() const +{ + return this->cEncoding; +} + +MimeContentFormatter &MimePart::getContentFormatter() +{ + return this->formatter; +} + +QString MimePart::toString() +{ + if (!prepared) { + prepare(); + } + + return mimeString; +} + +void MimePart::prepare() +{ + mimeString = QString(); + + mimeString.append("Content-Type: ").append(cType); + + if (cName != "") { + mimeString.append("; name=\"").append(cName).append("\""); + } + + if (cCharset != "") { + mimeString.append("; charset=").append(cCharset); + } + + if (cBoundary != "") { + mimeString.append("; boundary=").append(cBoundary); + } + + mimeString.append("\r\n"); + + mimeString.append("Content-Transfer-Encoding: "); + + switch (cEncoding) { + case _7Bit: + mimeString.append("7bit\r\n"); + break; + + case _8Bit: + mimeString.append("8bit\r\n"); + break; + + case Base64: + mimeString.append("base64\r\n"); + break; + + case QuotedPrintable: + mimeString.append("quoted-printable\r\n"); + break; + } + + if (cId != 0) { + mimeString.append("Content-ID: <").append(cId).append(">\r\n"); + } + + mimeString.append(header).append("\r\n"); + + switch (cEncoding) { + case _7Bit: + mimeString.append(QString(content).toLatin1()); + break; + + case _8Bit: + mimeString.append(content); + break; + + case Base64: + mimeString.append(formatter.format(content.toBase64())); + break; + + case QuotedPrintable: + mimeString.append(formatter.format(QuotedPrintable::encode(content), true)); + break; + } + + mimeString.append("\r\n"); + prepared = true; +} diff --git a/email/sendemail/mimepart.h b/email/sendemail/mimepart.h new file mode 100644 index 0000000..496f645 --- /dev/null +++ b/email/sendemail/mimepart.h @@ -0,0 +1,67 @@ +#ifndef MIMEPART_H +#define MIMEPART_H + +#include +#include "mimecontentformatter.h" + +class MimePart : public QObject +{ + Q_OBJECT +public: + enum Encoding { + _7Bit, + _8Bit, + Base64, + QuotedPrintable + }; + + MimePart(); + ~MimePart(); + + const QString &getHeader() const; + const QByteArray &getContent() const; + + void setContent(const QByteArray &content); + void setHeader(const QString &header); + + void addHeaderLine(const QString &line); + + void setContentId(const QString &cId); + const QString &getContentId() const; + + void setContentName(const QString &cName); + const QString &getContentName() const; + + void setContentType(const QString &cType); + const QString &getContentType() const; + + void setCharset(const QString &charset); + const QString &getCharset() const; + + void setEncoding(Encoding enc); + Encoding getEncoding() const; + + MimeContentFormatter &getContentFormatter(); + + virtual QString toString(); + virtual void prepare(); + +protected: + QString header; + QByteArray content; + + QString cId; + QString cName; + QString cType; + QString cCharset; + QString cBoundary; + Encoding cEncoding; + + QString mimeString; + bool prepared; + + MimeContentFormatter formatter; + +}; + +#endif // MIMEPART_H diff --git a/email/sendemail/mimetext.cpp b/email/sendemail/mimetext.cpp new file mode 100644 index 0000000..5269051 --- /dev/null +++ b/email/sendemail/mimetext.cpp @@ -0,0 +1,28 @@ +#include "mimetext.h" + +MimeText::MimeText(const QString &txt) +{ + this->text = txt; + this->cType = "text/plain"; + this->cCharset = "utf-8"; + this->cEncoding = _8Bit; +} + +MimeText::~MimeText() { } + +void MimeText::setText(const QString &text) +{ + this->text = text; +} + +const QString &MimeText::getText() const +{ + return text; +} + +void MimeText::prepare() +{ + this->content.clear(); + this->content.append(text); + MimePart::prepare(); +} diff --git a/email/sendemail/mimetext.h b/email/sendemail/mimetext.h new file mode 100644 index 0000000..f1e9fbc --- /dev/null +++ b/email/sendemail/mimetext.h @@ -0,0 +1,22 @@ +#ifndef MIMETEXT_H +#define MIMETEXT_H + +#include "mimepart.h" + +class MimeText : public MimePart +{ +public: + + MimeText(const QString &text = ""); + ~MimeText(); + + void setText(const QString &text); + const QString &getText() const; + +protected: + QString text; + void prepare(); + +}; + +#endif // MIMETEXT_H diff --git a/email/sendemail/quotedprintable.cpp b/email/sendemail/quotedprintable.cpp new file mode 100644 index 0000000..6d88fcc --- /dev/null +++ b/email/sendemail/quotedprintable.cpp @@ -0,0 +1,43 @@ +#include "quotedprintable.h" + +QString &QuotedPrintable::encode(const QByteArray &input) +{ + QString *output = new QString(); + + char byte; + const char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + + for (int i = 0; i < input.length() ; ++i) { + byte = input.at(i); + + if ((byte == 0x20) || ((byte >= 33) && (byte <= 126) && (byte != 61))) { + output->append(byte); + } else { + output->append('='); + output->append(hex[((byte >> 4) & 0x0F)]); + output->append(hex[(byte & 0x0F)]); + } + } + + return *output; +} + + +QByteArray &QuotedPrintable::decode(const QString &input) +{ + // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F + const int hexVal[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15}; + + QByteArray *output = new QByteArray(); + + for (int i = 0; i < input.length(); ++i) { + if (input.at(i).toLatin1() == '=') { + int index = ++i; + output->append((hexVal[input.at(index).toLatin1() - '0'] << 4) + hexVal[input.at(++i).toLatin1() - '0']); + } else { + output->append(input.at(i).toLatin1()); + } + } + + return *output; +} diff --git a/email/sendemail/quotedprintable.h b/email/sendemail/quotedprintable.h new file mode 100644 index 0000000..e295628 --- /dev/null +++ b/email/sendemail/quotedprintable.h @@ -0,0 +1,19 @@ +#ifndef QUOTEDPRINTABLE_H +#define QUOTEDPRINTABLE_H + +#include +#include + +class QuotedPrintable : public QObject +{ + Q_OBJECT +public: + + static QString &encode(const QByteArray &input); + static QByteArray &decode(const QString &input); + +private: + QuotedPrintable(); +}; + +#endif // QUOTEDPRINTABLE_H diff --git a/email/sendemail/sendemail.pri b/email/sendemail/sendemail.pri new file mode 100644 index 0000000..bb9bb07 --- /dev/null +++ b/email/sendemail/sendemail.pri @@ -0,0 +1,30 @@ +HEADERS += \ + $$PWD/emailaddress.h \ + $$PWD/mimeattachment.h \ + $$PWD/mimecontentformatter.h \ + $$PWD/mimefile.h \ + $$PWD/mimehtml.h \ + $$PWD/mimeinlinefile.h \ + $$PWD/mimemessage.h \ + $$PWD/mimemultipart.h \ + $$PWD/mimepart.h \ + $$PWD/mimetext.h \ + $$PWD/quotedprintable.h \ + $$PWD/smtpclient.h \ + $$PWD/smtpmime.h \ + $$PWD/sendemailthread.h + +SOURCES += \ + $$PWD/emailaddress.cpp \ + $$PWD/mimeattachment.cpp \ + $$PWD/mimecontentformatter.cpp \ + $$PWD/mimefile.cpp \ + $$PWD/mimehtml.cpp \ + $$PWD/mimeinlinefile.cpp \ + $$PWD/mimemessage.cpp \ + $$PWD/mimemultipart.cpp \ + $$PWD/mimepart.cpp \ + $$PWD/mimetext.cpp \ + $$PWD/quotedprintable.cpp \ + $$PWD/smtpclient.cpp \ + $$PWD/sendemailthread.cpp diff --git a/email/sendemail/sendemailthread.cpp b/email/sendemail/sendemailthread.cpp new file mode 100644 index 0000000..82c8468 --- /dev/null +++ b/email/sendemail/sendemailthread.cpp @@ -0,0 +1,147 @@ +#include "sendemailthread.h" +#include "sendemail/smtpmime.h" + +QScopedPointer SendEmailThread::self; +SendEmailThread *SendEmailThread::Instance() +{ + if (self.isNull()) { + static QMutex mutex; + QMutexLocker locker(&mutex); + if (self.isNull()) { + self.reset(new SendEmailThread); + } + } + + return self.data(); +} + +SendEmailThread::SendEmailThread(QObject *parent) : QThread(parent) +{ + stopped = false; + emialTitle = "邮件标题"; + sendEmailAddr = "feiyangqingyun@126.com"; + sendEmailPwd = "123456789"; + receiveEmailAddr = "feiyangqingyun@163.com;517216493@qq.com"; + contents.clear(); + fileNames.clear(); +} + +SendEmailThread::~SendEmailThread() +{ + this->stop(); + this->wait(1000); +} + +void SendEmailThread::run() +{ + while (!stopped) { + int count = contents.count(); + if (count > 0) { + mutex.lock(); + QString content = contents.takeFirst(); + QString fileName = fileNames.takeFirst(); + mutex.unlock(); + + QString result; + QStringList list = sendEmailAddr.split("@"); + QString tempSMTP = list.at(1).split(".").at(0); + int tempPort = 25; + + //QQ邮箱端口号为465,必须启用SSL协议. + if (tempSMTP.toUpper() == "QQ") { + tempPort = 465; + } + + SmtpClient smtp(QString("smtp.%1.com").arg(tempSMTP), tempPort, tempPort == 25 ? SmtpClient::TcpConnection : SmtpClient::SslConnection); + smtp.setUser(sendEmailAddr); + smtp.setPassword(sendEmailPwd); + + //构建邮件主题,包含发件人收件人附件等. + MimeMessage message; + message.setSender(new EmailAddress(sendEmailAddr)); + + //逐个添加收件人 + QStringList receiver = receiveEmailAddr.split(';'); + for (int i = 0; i < receiver.size(); i++) { + message.addRecipient(new EmailAddress(receiver.at(i))); + } + + //构建邮件标题 + message.setSubject(emialTitle); + + //构建邮件正文 + MimeHtml text; + text.setHtml(content); + message.addPart(&text); + + //构建附件-报警图像 + if (fileName.length() > 0) { + QStringList attas = fileName.split(";"); + foreach (QString tempAtta, attas) { + QFile *file = new QFile(tempAtta); + if (file->exists()) { + message.addPart(new MimeAttachment(file)); + } + } + } + + if (!smtp.connectToHost()) { + result = "邮件服务器连接失败"; + } else { + if (!smtp.login()) { + result = "邮件用户登录失败"; + } else { + if (!smtp.sendMail(message)) { + result = "邮件发送失败"; + } else { + result = "邮件发送成功"; + } + } + } + + smtp.quit(); + if (!result.isEmpty()) { + emit receiveEmailResult(result); + } + + msleep(1000); + } + + msleep(100); + } + + stopped = false; +} + +void SendEmailThread::stop() +{ + stopped = true; +} + +void SendEmailThread::setEmialTitle(const QString &emailTitle) +{ + this->emialTitle = emailTitle; +} + +void SendEmailThread::setSendEmailAddr(const QString &sendEmailAddr) +{ + this->sendEmailAddr = sendEmailAddr; +} + +void SendEmailThread::setSendEmailPwd(const QString &sendEmailPwd) +{ + this->sendEmailPwd = sendEmailPwd; +} + +void SendEmailThread::setReceiveEmailAddr(const QString &receiveEmailAddr) +{ + this->receiveEmailAddr = receiveEmailAddr; +} + +void SendEmailThread::append(const QString &content, const QString &fileName) +{ + mutex.lock(); + contents.append(content); + fileNames.append(fileName); + mutex.unlock(); +} diff --git a/email/sendemail/sendemailthread.h b/email/sendemail/sendemailthread.h new file mode 100644 index 0000000..c4ef347 --- /dev/null +++ b/email/sendemail/sendemailthread.h @@ -0,0 +1,44 @@ +#ifndef SENDEMAILTHREAD_H +#define SENDEMAILTHREAD_H + +#include +#include +#include + +class SendEmailThread : public QThread +{ + Q_OBJECT +public: + static SendEmailThread *Instance(); + explicit SendEmailThread(QObject *parent = 0); + ~SendEmailThread(); + +protected: + void run(); + +private: + static QScopedPointer self; + QMutex mutex; + volatile bool stopped; + + QString emialTitle; //邮件标题 + QString sendEmailAddr; //发件人邮箱 + QString sendEmailPwd; //发件人密码 + QString receiveEmailAddr; //收件人邮箱,可多个中间;隔开 + QStringList contents; //正文内容 + QStringList fileNames; //附件 + +signals: + void receiveEmailResult(const QString &result); + +public slots: + void stop(); + void setEmialTitle(const QString &emailTitle); + void setSendEmailAddr(const QString &sendEmailAddr); + void setSendEmailPwd(const QString &sendEmailPwd); + void setReceiveEmailAddr(const QString &receiveEmailAddr); + void append(const QString &content, const QString &fileName); + +}; + +#endif // SENDEMAILTHREAD_H diff --git a/email/sendemail/smtpclient.cpp b/email/sendemail/smtpclient.cpp new file mode 100644 index 0000000..17247d8 --- /dev/null +++ b/email/sendemail/smtpclient.cpp @@ -0,0 +1,390 @@ +#include "smtpclient.h" + +SmtpClient::SmtpClient(const QString &host, int port, ConnectionType connectionType) : + name("localhost"), + authMethod(AuthPlain), + connectionTimeout(5000), + responseTimeout(5000) +{ + setConnectionType(connectionType); + + this->host = host; + this->port = port; +} + +SmtpClient::~SmtpClient() {} + +void SmtpClient::setUser(const QString &user) +{ + this->user = user; +} + +void SmtpClient::setPassword(const QString &password) +{ + this->password = password; +} + +void SmtpClient::setAuthMethod(AuthMethod method) +{ + this->authMethod = method; +} + +void SmtpClient::setHost(QString &host) +{ + this->host = host; +} + +void SmtpClient::setPort(int port) +{ + this->port = port; +} + +void SmtpClient::setConnectionType(ConnectionType ct) +{ + this->connectionType = ct; + + switch (connectionType) { + case TcpConnection: + socket = new QTcpSocket(this); + break; +#ifdef ssl + case SslConnection: + case TlsConnection: + socket = new QSslSocket(this); +#endif + } +} + +const QString &SmtpClient::getHost() const +{ + return this->host; +} + +const QString &SmtpClient::getUser() const +{ + return this->user; +} + +const QString &SmtpClient::getPassword() const +{ + return this->password; +} + +SmtpClient::AuthMethod SmtpClient::getAuthMethod() const +{ + return this->authMethod; +} + +int SmtpClient::getPort() const +{ + return this->port; +} + +SmtpClient::ConnectionType SmtpClient::getConnectionType() const +{ + return connectionType; +} + +const QString &SmtpClient::getName() const +{ + return this->name; +} + +void SmtpClient::setName(const QString &name) +{ + this->name = name; +} + +const QString &SmtpClient::getResponseText() const +{ + return responseText; +} + +int SmtpClient::getResponseCode() const +{ + return responseCode; +} + +QTcpSocket *SmtpClient::getSocket() +{ + return socket; +} + +int SmtpClient::getConnectionTimeout() const +{ + return connectionTimeout; +} + +void SmtpClient::setConnectionTimeout(int msec) +{ + connectionTimeout = msec; +} + +int SmtpClient::getResponseTimeout() const +{ + return responseTimeout; +} + +void SmtpClient::setResponseTimeout(int msec) +{ + responseTimeout = msec; +} + +bool SmtpClient::connectToHost() +{ + switch (connectionType) { + case TlsConnection: + case TcpConnection: + socket->connectToHost(host, port); + break; +#ifdef ssl + case SslConnection: + ((QSslSocket *) socket)->connectToHostEncrypted(host, port); + break; +#endif + } + + if (!socket->waitForConnected(connectionTimeout)) { + emit smtpError(ConnectionTimeoutError); + return false; + } + + try { + // Wait for the server's response + waitForResponse(); + + // If the response code is not 220 (Service ready) + // means that is something wrong with the server + if (responseCode != 220) { + emit smtpError(ServerError); + return false; + } + + // Send a EHLO/HELO message to the server + // The client's first command must be EHLO/HELO + sendMessage("EHLO " + name); + + // Wait for the server's response + waitForResponse(); + + // The response code needs to be 250. + if (responseCode != 250) { + emit smtpError(ServerError); + return false; + } + + if (connectionType == TlsConnection) { + // send a request to start TLS handshake + sendMessage("STARTTLS"); + + // Wait for the server's response + waitForResponse(); + + // The response code needs to be 220. + if (responseCode != 220) { + emit smtpError(ServerError); + return false; + }; +#ifdef ssl + ((QSslSocket *) socket)->startClientEncryption(); + if (!((QSslSocket *) socket)->waitForEncrypted(connectionTimeout)) { + qDebug() << ((QSslSocket *) socket)->errorString(); + emit smtpError(ConnectionTimeoutError); + return false; + } +#endif + // Send ELHO one more time + sendMessage("EHLO " + name); + + // Wait for the server's response + waitForResponse(); + + // The response code needs to be 250. + if (responseCode != 250) { + emit smtpError(ServerError); + return false; + } + } + } catch (ResponseTimeoutException) { + return false; + } + + return true; +} + +bool SmtpClient::login() +{ + return login(user, password, authMethod); +} + +bool SmtpClient::login(const QString &user, const QString &password, AuthMethod method) +{ + try { + if (method == AuthPlain) { + // Sending command: AUTH PLAIN base64('\0' + username + '\0' + password) + sendMessage("AUTH PLAIN " + QByteArray().append((char) 0).append(user).append((char) 0).append(password).toBase64()); + + // Wait for the server's response + waitForResponse(); + + // If the response is not 235 then the authentication was faild + if (responseCode != 235) { + emit smtpError(AuthenticationFailedError); + return false; + } + } else if (method == AuthLogin) { + // Sending command: AUTH LOGIN + sendMessage("AUTH LOGIN"); + + // Wait for 334 response code + waitForResponse(); + + if (responseCode != 334) { + emit smtpError(AuthenticationFailedError); + return false; + } + + // Send the username in base64 + sendMessage(QByteArray().append(user).toBase64()); + + // Wait for 334 + waitForResponse(); + + if (responseCode != 334) { + emit smtpError(AuthenticationFailedError); + return false; + } + + // Send the password in base64 + sendMessage(QByteArray().append(password).toBase64()); + + // Wait for the server's responce + waitForResponse(); + + // If the response is not 235 then the authentication was faild + if (responseCode != 235) { + emit smtpError(AuthenticationFailedError); + return false; + } + } + } catch (ResponseTimeoutException e) { + // Responce Timeout exceeded + emit smtpError(AuthenticationFailedError); + return false; + } + + return true; +} + +bool SmtpClient::sendMail(MimeMessage &email) +{ + try { + // Send the MAIL command with the sender + sendMessage("MAIL FROM: <" + email.getSender().getAddress() + ">"); + + waitForResponse(); + + if (responseCode != 250) { + return false; + } + + // Send RCPT command for each recipient + QList::const_iterator it, itEnd; + + // To (primary recipients) + for (it = email.getRecipients().begin(), itEnd = email.getRecipients().end(); + it != itEnd; ++it) { + sendMessage("RCPT TO: <" + (*it)->getAddress() + ">"); + waitForResponse(); + + if (responseCode != 250) { + return false; + } + } + + // Cc (carbon copy) + for (it = email.getRecipients(MimeMessage::Cc).begin(), itEnd = email.getRecipients(MimeMessage::Cc).end(); + it != itEnd; ++it) { + sendMessage("RCPT TO: <" + (*it)->getAddress() + ">"); + waitForResponse(); + + if (responseCode != 250) { + return false; + } + } + + // Bcc (blind carbon copy) + for (it = email.getRecipients(MimeMessage::Bcc).begin(), itEnd = email.getRecipients(MimeMessage::Bcc).end(); + it != itEnd; ++it) { + sendMessage("RCPT TO: <" + (*it)->getAddress() + ">"); + waitForResponse(); + + if (responseCode != 250) { + return false; + } + } + + // Send DATA command + sendMessage("DATA"); + waitForResponse(); + + if (responseCode != 354) { + return false; + } + + sendMessage(email.toString()); + + // Send \r\n.\r\n to end the mail data + sendMessage("."); + + waitForResponse(); + + if (responseCode != 250) { + return false; + } + } catch (ResponseTimeoutException) { + return false; + } + + return true; +} + +void SmtpClient::quit() +{ + sendMessage("QUIT"); +} + +void SmtpClient::waitForResponse() throw (ResponseTimeoutException) +{ + do { + if (!socket->waitForReadyRead(responseTimeout)) { + emit smtpError(ResponseTimeoutError); + throw ResponseTimeoutException(); + } + + while (socket->canReadLine()) { + // Save the server's response + responseText = socket->readLine(); + + // Extract the respose code from the server's responce (first 3 digits) + responseCode = responseText.left(3).toInt(); + + if (responseCode / 100 == 4) { + emit smtpError(ServerError); + } + + if (responseCode / 100 == 5) { + emit smtpError(ClientError); + } + + if (responseText.at(3) == ' ') { + return; + } + } + } while (true); +} + +void SmtpClient::sendMessage(const QString &text) +{ + socket->write(text.toUtf8() + "\r\n"); +} diff --git a/email/sendemail/smtpclient.h b/email/sendemail/smtpclient.h new file mode 100644 index 0000000..1fa072e --- /dev/null +++ b/email/sendemail/smtpclient.h @@ -0,0 +1,103 @@ +#ifndef SMTPCLIENT_H +#define SMTPCLIENT_H + +#include +#include +#if (QT_VERSION > QT_VERSION_CHECK(5,0,0)) +#include +#endif +#include "mimemessage.h" + +class SmtpClient : public QObject +{ + Q_OBJECT +public: + enum AuthMethod { + AuthPlain, + AuthLogin + }; + + enum SmtpError { + ConnectionTimeoutError, + ResponseTimeoutError, + AuthenticationFailedError, + ServerError, // 4xx smtp error + ClientError // 5xx smtp error + }; + + enum ConnectionType { + TcpConnection, + SslConnection, + TlsConnection // STARTTLS + }; + + SmtpClient(const QString &host = "locahost", int port = 25, ConnectionType ct = TcpConnection); + + ~SmtpClient(); + + const QString &getHost() const; + void setHost(QString &host); + + int getPort() const; + void setPort(int port); + + const QString &getName() const; + void setName(const QString &name); + + ConnectionType getConnectionType() const; + void setConnectionType(ConnectionType ct); + + const QString &getUser() const; + void setUser(const QString &host); + + const QString &getPassword() const; + void setPassword(const QString &password); + + SmtpClient::AuthMethod getAuthMethod() const; + void setAuthMethod(AuthMethod method); + + const QString &getResponseText() const; + int getResponseCode() const; + + int getConnectionTimeout() const; + void setConnectionTimeout(int msec); + + int getResponseTimeout() const; + void setResponseTimeout(int msec); + + QTcpSocket *getSocket(); + + bool connectToHost(); + bool login(); + bool login(const QString &user, const QString &password, AuthMethod method = AuthLogin); + + bool sendMail(MimeMessage &email); + void quit(); + +protected: + QTcpSocket *socket; + QString host; + int port; + ConnectionType connectionType; + QString name; + + QString user; + QString password; + AuthMethod authMethod; + + int connectionTimeout; + int responseTimeout; + + QString responseText; + int responseCode; + + class ResponseTimeoutException {}; + void waitForResponse() throw (ResponseTimeoutException); + void sendMessage(const QString &text); + +signals: + void smtpError(SmtpError e); + +}; + +#endif // SMTPCLIENT_H diff --git a/email/sendemail/smtpmime.h b/email/sendemail/smtpmime.h new file mode 100644 index 0000000..fe782aa --- /dev/null +++ b/email/sendemail/smtpmime.h @@ -0,0 +1,13 @@ +#ifndef SMTPMIME_H +#define SMTPMIME_H + +#include "smtpclient.h" +#include "mimepart.h" +#include "mimehtml.h" +#include "mimeattachment.h" +#include "mimemessage.h" +#include "mimetext.h" +#include "mimeinlinefile.h" +#include "mimefile.h" + +#endif // SMTPMIME_H