亲宝软件园·资讯

展开

Qt实现编写SMTP客户端的示例详解

音视频开发老舅 人气:0

Qt编写的SMTP客户端(库)

允许应用程序通过SMTP发送电子邮件(有文本,html,附件,内联文件等的MIME)。并支持SSL和SMTP身份验证。

Qt SMPT客户端支持

(1) 与SMTP服务器的TCP和SSL连接。

(2) SMTP验证(PLAIN和LOGIN方法)。

(3) 发送MIME电子邮件(给多个收件人)。

(4) 电子邮件中的纯文本和HTML(带有内联文件)内容。

(5) 多个附件和内联文件(用于HTML)。

(6) 不同的字符集(ascii,utf-8等)和编码方法(7位,8位,base64)。

(7) 错误处理。

示例1 -一封简单的(纯文本)电子邮件

#include <QtGui/QApplication>
#include "../src/SmtpMime"
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
 
    // 这是Qt项目的Smtpclient的第一个演示应用程序
 
    // 首先,我们需要创建一个Smtpclient对象
    // 我们将使用Gmail的smtp服务器(smtp.gmail.com,端口465,ssl)
 
    SmtpClient smtp("smtp.gmail.com", 465, SmtpClient::SslConnection);
 
    // 我们需要设置用户名(您的电子邮件地址)和密码
    // 为smtp认证。
 
    smtp.setUser("your_email_address@gmail.com");
    smtp.setPassword("your_password");
 
    // 现在我们创建一个MimeMessage对象。这是邮件。
 
    MimeMessage message;    
    message.setSender(EmailAddress("your_email_address@gmail.com", "Your Name"));
    message.addRecipient(EmailAddress("recipient@host.com", "Recipient's Name"));
    message.setSubject("SmtpClient for Qt - Demo");
 
    // 现在向电子邮件中添加一些文本。
    // 首先,我们创建一个Mimetext对象。
 
    MimeText text;
 
    text.setText("Hi,\nThis is a simple email message.\n");
 
    // 现在将其添加到邮件中
 
    message.addPart(&text);
 
    // 现在我们可以寄信了
 
    smtp.connectToHost();
    smtp.login();
    smtp.sendMail(message);
    smtp.quit();
 
}

示例2 -发送附件

#include <QtGui/QApplication>
#include "../src/SmtpMime"
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
 
    // 首先创建Smtpclient对象并设置用户和密码。
    SmtpClient smtp("smtp.gmail.com", 465, SmtpClient::SslConnection);
    smtp.setUser("your_email_address@gmail.com");
    smtp.setPassword("your_password");
 
    // 创建一个 MimeMessage
    MimeMessage message;
    message.setSender(EmailAddress("your_email_address@gmail.com", "Your Name"));
    message.addRecipient(EmailAddress("recipient@host.com", "Recipient's Name"));
    message.setSubject("SmtpClient for Qt - Demo");
 
    // 添加一些文本
    MimeText text;
    text.setText("Hi!\n This is an email with some attachments.");
    message.addPart(&text);
 
    // 现在我们创建附件对象
    QFile image("image1.jpg");
    MimeAttachment attachment(&image);
 
    // 可以设置文件类型。(默认是application/octet-stream)
    attachment.setContentType("image/jpg");
 
    // 现在将其添加到消息中
    message.addPart(&attachment);
 
    // 添加另一个附件
    QFile document("document.pdf")
    MimeAttachment documentAttachment(&document);
    message.addPart(&documentAttachment);
 
    // 现在我们可以寄信了
    smtp.connectToHost();
    smtp.login();
    smtp.sendMail(message);
    smtp.quit();
 
}

示例3 -带有嵌入图像的HTML电子邮件(内联文件)

#include <QtGui/QApplication>
#include "../src/SmtpMime"
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
 
    // 首先创建Smtpclient对象并设置用户和密码。
 
    SmtpClient smtp("smtp.gmail.com", 465, SmtpClient::SslConnection);
 
    smtp.setUser("your_email@gmail.com");
    smtp.setPassword("your_password");
 
    // 创建一个 MimeMessage
 
    MimeMessage message;
    message.setSender(EmailAddress("your_email_address@gmail.com", "Your Name"));
    message.addRecipient(EmailAddress("recipient@host.com", "Recipient's Name"));
    message.setSubject("SmtpClient for Qt - Example 3 - Html email with images");
 
 
    // 现在我们需要为HTML内容创建一个MimeHtml对象。
    MimeHtml html;
 
    html.setHtml("<h1> Hello! </h1>"
                 "<h2> This is the first image </h2>"
                 "<img src='cid:image1' />"
                 "<h2> This is the second image </h2>"
                 "<img src='cid:image2' />");
 
 
    // 为每个图像创建一个MimeInlineFile对象
    QFile imageFile1("image1.jpg");
    MimeInlineFile image1 (&imageFile1);
 
    // 必须设置唯一的内容id
    image1.setContentId("image1");
    image1.setContentType("image/jpg");
 
    QFile imageFile2("image2.jpg");
    MimeInlineFile image2 (&imageFile2);
    image2.setContentId("image2");
    image2.setContentType("image/jpg");
 
    message.addPart(&html);
    message.addPart(&image1);
    message.addPart(&image2);
 
    // 现在可以发送邮件了
 
    smtp.connectToHost();
    smtp.login();
    smtp.sendMail(message);
    smtp.quit();
}

使用方法

1. 我这里下载的版本是SmtpClient-for-Qt v2.0的,首先使用Qt打开SMTPEmail.pro文件,编译出SmtpMime2.dll动态库,编译动态库的原因是因为里面的demo运行时需要链接这个动态库。我编的是debug版的,你也可以编release的不过要放到对应的文件夹下。

如下图所示:

2. 再把步骤1中生成的SmtpMime2.dll文件拷贝到对应的debug或release目录下,我这里使用是debug的所以拷到debug文件下。

如下图所示:

3. 双击打开demo2.pro文件,修改成SmtpMime2.dll库的路径即可。注意 : 路径一定要对否则编译会报错

如下图所示:

4.最后编译+运行,就可以成功地把demo2跑起来了,其他demo的使用方法应该也类似。

如下图所示:

5. 当你点击发送邮件的时候可能会报错以下错误: qt.network.ssl: QSslSocket::connectToHostEncrypted: TLS initialization failed ,这个时候需要安装OpenSSL。

6. 安装OpenSSL

6.1 背景

Qt 使用QNetwork 模块,进行api请求时发生错误,错误信息:qt.network.ssl: QSslSocket::connectToHostEncrypted: TLS initialization failed

6.2 原因

当你用HTTP形式的时候,会发现没有问题,而使用HTTPS时,则会报错。如果对计算机网络有所了解的人,应该大致懂原因。因为HTTP 是超文本传输协议,信息是明文传输,存在安全风险的问题。HTTPS 则解决 HTTP 不安全的缺陷,在 TCP 和 HTTP 网络层之间加入了 SSL/TLS 安全协议,使得报文能够加密传输。

SSL/TLS 协议建立的详细流程:

Client

首先,由客户端向服务器发起加密通信请求,也就是 Client的请求。在这一步,客户端主要向服务器发送以下信息:

(1)客户端支持的 SSL/TLS 协议版本,如 TLS 1.2 版本。

(2)客户端生产的随机数( Client Random ),后面用于生产「会话秘钥」。

(3)客户端支持的密码套件列表,如 RSA 加密算法。

Sever

服务器收到客户端请求后,向客户端发出响应 。服务器回应的内容有如下内容:

(1)确认 SSL/ TLS 协议版本,如果浏览器不支持,则关闭加密通信。

(2)服务器生产的随机数( Server Random ),后面用于生产「会话秘钥」。

(3)确认的密码套件列表,如 RSA 加密算法。

(4)服务器的数字证书。

客户端回应

客户端收到服务器的回应之后,首先通过浏览器或者操作系统中的 CA 公钥,确认服务器的数字证书的真实性。如果证书没有问题,客户端会从数字证书中取出服务器的公钥,然后使用它加密报文,向服务器发送如下信息:

(1)一个随机数( pre-master key )。该随机数会被服务器公钥加密。

(2)加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信。

(3)客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时把之前所有内容的发生的数据做个摘要,用来供服务端校验。

上面第一项的随机数是整个握手阶段的第三个随机数,这样服务器和客户端就同时有三个随机数,接着就用双方协商的加密算法,各自生成本次通信的「会话秘钥」。

服务器的最后回应

服务器收到客户端的第三个随机数( pre-master key )之后,通过协商的加密算法,计算出本次通信的「会话秘钥」。然后,向客户端发生最后的信息:

(1)加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信。

(2)服务器握手结束通知,表示服务器的握手阶段已经结束。这一项同时把之前所有内容的发生的数据做个摘要,用来供客户端校验。

至此,整个 SSL/TLS 的握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的 HTTP 协议,只不过用「会话秘钥」加密内容。
回到qt.network.ssl: QSslSocket::connectToHostEncrypted: TLS initialization failed,那么这个报错,就是缺少加密的手段,也就是没有提供对HTTP加密的工具,从而无法进行HTTPS通信。

6.3 解决方案

那么原因清楚了,就应该知道,我们需要把加密这一步缺少的东西给补上。先说一点,Qt本身是支持ssl的,但是因为法律原因?没有自带对应的dll。

我们先使用这段代码打印当前Qt支持的ssl版本:

#include <QSslSocket>
#include <QDebug>
qDebug()<< QSslSocket::sslLibraryBuildVersionString();

使用网络需要加上Qt的网络模块,在pro文件里加上:

QT += network

我这里输出的是

"OpenSSL 1.1.1d 10 Sep 2019"

6.4 接下来就去下载OpenSSL,下载方式有两种:

(1). 下载OpenSSL源码,自行编译

https://www.openssl.org/source/

(2). 直接下载dll

Openssl下载网站: http://slproweb.com/products/Win32OpenSSL.html

我推荐第二个方法,省去自己编译的时间。

然后在这个网站找到对应的版本,比如我的版本是刚刚打印的1.1.1,同时,也要注意工程是32位还是64位,我这里选择的是Win64 OpenSSL v1.1.1n Light,至于EXE还是MSI都没差异。

6.5 安装的时候,我选择的是第二个,这样可以方便的进行dll文件的拷贝。

6.6 进入OpenSSL安装目录。bin目录下,拷贝这两个dll文件到工程的exe程序所在路径下。

6.7 比如我这里的路径,直接放到exe根路径下即可,然后程序即可正常运行。

6.8 填写好正确的邮箱和密码再次点击发送邮件,如果说提示"Authentification Failed"或者提示"Mail sending failed"可能是你填写的邮箱和密码错了.

6.9 下面是邮件发送成功的截图:

qq邮箱收到的邮件:

这里我也测试了一下,不同OpenSSL 版本的dll是否可以通用,发现高低版本都不行,必须得和Qt 打印出来的OpenSSL 版本一致才行。

另外,很多帖子都是说,把这两个dll文件放到E:\QT\5.12.3\mingw73_64\bin路径下,即Qt的安装路径下。这样也可以,但是我觉得不好,个人认为,尽量别去动Qt安装路径下的文件,保证不会被认为破坏开发环境,或者以后排错,不会导致当时自己把文件放到了Qt安装路径下太久忘记,而在别的电脑上无法正常使用的情况。

加载全部内容

相关教程
猜你喜欢
用户评论