Qt实现编写SMTP客户端的示例详解
音视频开发老舅 人气:0Qt编写的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安装路径下太久忘记,而在别的电脑上无法正常使用的情况。
加载全部内容