支持发送多人,抄送多人,支持发送附件
邮件协议简单介绍
SMTP
SMTP (Simple Mail Transfer Protocol),即简单邮件传输协议,默认端口是25,通过SSL协议加密之后的默认端口是465。正如名字所暗示的那样,它其实是一个非常简单的传输协议,最初是无需身份认证,而且发件人的邮箱地址是可以由发信方任意声明的,利用这个特性可以伪造任意发件人。它是用于从源地址到目的地址传输邮件的协议,通过它来控制邮件的中转方式。SMTP 协议属于 TCP/IP 协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。SMTP是一个 “推” 的协议,它不允许根据需要从远程服务器上 “拉” 来消息。
SMTP 认证:简单地说就是要求必须在提供了账户名和密码之后才可以登录 SMTP 服务器,这就使得那些垃圾邮件的散播者无可乘之机。增加 SMTP 认证的目的是为了使用户避免受到垃圾邮件的侵扰。
POP
POP(Post Office Protocol)邮局通讯协议,POP是互联网上的一种通讯协议,主要功能是用在接收电子邮件时。当我们寄信给另外一个人时,对方当时多半不会在线上,所以邮件服务器必须为收信者保存这封信,直到收信者来检查这封信件。当收信人收信的时候,必须通过POP通讯协定,才能取得邮件。
POP3是Post Office Protocol 3的简称,即邮局协议的第3个版本,是TCP/IP协议族中的一员,默认端口是110,通过SSL协议加密之后的默认端口是995。POP3协议主要用于支持使用客户端远程管理在服务器上的电子邮件。它规定怎样将个人计算机连接到Internet的邮件服务器和下载电子邮件的电子协议。它是因特网电子邮件的第一个离线协议标准,POP3允许用户从服务器上把邮件存储到本地主机(即自己的计算机)上,但是对邮件的操作并不会反馈到邮箱服务器上。
IMAP
IMAP (Internet Mail Access Protocol),即交互式邮件存取协议,是一个应用层协议,默认端口是143,通过SSL协议加密之后的默认端口是993。用来从本地邮件客户端,如Outlook Express、Foxmail、Mozilla Thunderbird等访问远程服务器上的邮件。它和POP3类似邮件访问标准协议类似。不同的是,开启了IMAP后,您在电子邮件客户端收取的邮件仍然保留在服务器上,同时在客户端上的操作都会反馈到服务器上,如:删除邮件,标记已读等,服务器上的邮件也会做相应的动作。同时,IMAP像POP3那样提供了方便的邮件下载服务,让用户能进行离线阅读。IMAP提供的摘要浏览功能可以让你在阅读完所有的邮件到达时间、主题、发件人、大小等信息后才作出是否下载的决定。此外,IMAP 更好地支持了从多个不同设备中随时访问新邮件。所以无论从浏览器登录邮箱或者客户端软件登录邮箱,看到的邮件以及状态都是一致的。也就是说,IMAP提供了比POP3更为强大的功能。
SMTP协议的定义:
1、SMTP 是一种TCP协议支持的提供可靠且有效电子邮件传输的应用层协议;
2、SMTP 是建立在 TCP上的一种邮件服务,主要用于传输系统之间的邮件信息并提供来信有关的通知;
3、SMTP 独立于特定的传输子系统,且只需要可靠有序的数据流信道支持;
4、SMTP 重要特性之一是其能跨越网络传输邮件,即“ SMTP 邮件中继”;
5、SMTP是一个相对简单的基于文本的协议。
SSL和TLS的概念与区别
什么是SSL?
SSL(Secure Socket Layer,安全套接字层),为Netscape所研发,用以保障在Internet上数据传输之安全,利用数据加密(Encryption)技术,可确保数据在网络上之传输过程中不会被截取。当前版本为3.0。它已被广泛地用于Web浏览器与服务器之间的身份认证和加密数据传输。
SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。
SSL协议可分为两层: SSL记录协议(SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。
SSL握手协议(SSL Handshake Protocol):它建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。
什么是TLS?
TLS(Transport Layer Security,传输层安全协议),用于两个应用程序之间提供保密性和数据完整性。
TLS 1.0是IETF(Internet Engineering Task Force,Internet工程任务组)制定的一种新的协议,它建立在SSL 3.0协议规范之上,是SSL 3.0的后续版本,可以理解为SSL 3.1(可简单理解为同一事物不同阶段的不同称呼),它是写入了 RFC 的。
该协议由两层组成: TLS 记录协议(TLS Record)和 TLS 握手协议(TLS Handshake)。较低的层为 TLS 记录协议,位于某个可靠的传输协议(例如 TCP)上面。
SSL和TLS的主要区别?
TLS的主要目标是使SSL更安全,并使协议的规范更精确和完善。另外,TLS版本号也与SSL的不同。
邮件传送基本流程:
邮件传送主要包括3个阶段: 建立连接 、 邮件传送 和 终止连接 。
SMTP基本流程包括以下几个命令:HELO﹑EHLO、MAIL﹑RCPT﹑DATA、AUTH LOGIN和QUIT
建立连接阶段:
1、当SMTP客户端每隔一定时间对邮件缓存扫描一次,如发现有邮件,就使用SMTP的熟知端口号25与接收方的邮件服务器的SMTP服务器建立TCP连接。
2、接收方SMTP服务器发出“220 Service ready"告诉客户端它已经准备好接收邮件。若服务器未就绪,它就发送代码421(服务器不可用)。
3、客户发送HELO报文命令,并使用它的域名地址标志自己。目的是:用来把客户的域名通知服务器,值得注意的是, 在TCP的连接建立阶段,发送方和接收方都是通过它们的IP地址来告诉对方的 。(HELO报文是最初的,用户名和密码都不加密。现在改为EHLO,用户名和密码都进行base64编码发送)。
4、服务器响应代码250(请求命令完成)或根据情况的其他一些代码。
5、AUTH LOGIN–登录邮箱,这一部分一般要用base64加密。
6、服务器响应代码235(请求命令完成)或根据情况的其他一些代码。
邮件传送阶段:
在SMTP客户与服务器之间建立连接后,发件人就可以与一个或多个收件人交换单个的报文了。若收件人超过一个,则下面步骤3和步骤4将重复进行。
1、客户发送MAIL FROM报,这个命令用来开始传送邮件,它的后面跟随发件方邮件地址(返回邮件地址)。它也用来当邮件无法送达时,发送失败通知。为保证邮件的成功发送,发件方的地址应是被对方或中间转发方同意接受的。这个命令会清空有关的缓冲区,为新的邮件做准备。
2、服务器响应代码250(请求命令完成)或其他适当的代码。
3、RCPT –这个命令告诉收件方收件人的邮箱。当有多个收件人时,需要多次使用该命令RCPT
4、TO,每次只能指明一个人。如果接收方服务器不同意转发这个地址的邮件,它必须报550错误代码通知发件方。如果服务器同意转发,它要更改邮件发送路径,把最开始的目的地(该服务器)换成下一个服务器。
5、服务器响应代码250或其他适当的代码。
6、DATA–收件方把该命令之后的数据作为发送的数据。数据被加入数据缓冲区中,以单独一行是”.”的行结束数据。结束行对于接收方同时意味立即开始缓冲区内的数据传送,传送结束后清空缓冲区。DATA命令表示要开始传送邮件的内容了。
7、如果传送接受,接收方回复OK,服务器响应代码"354 Start mail input: end with <CRLF>.<CRLF>"或其他适当的报文(如421 服务器不可用,500 命令无法识别)。
8、客户用连续的行发送报文的内容。每一行的行结束时输入 <CRLF><CRLF> ,即回车换行回车换行,表示邮件内容换行,发送的附件内容也在此命令中。最后一行的行结束时输入 <CRLF>.<CRLF> ,即回车换行.回车换行,表示邮件内容结束。
9、服务器响应代码(250 请求命令完成)或其他适当的代码。
值得注意的是:虽然SMTP使用TCP连接试图使邮件的传送可靠,但它并不能保证不丢失邮件。也就是说,使用SMTP传送邮件只能说可以可靠地传送接收方的邮件服务器,在往后的情况就不知道了。接收方的邮件服务器也许会出故障,使收到的服务器全部丢失(在收件人读取信件之前)。
终止连接阶段:
在报文传送成功后,客户就终止连接。包括如下步骤:
1、QUIT–SMTP要求接收放必须回答OK,然后中断传输;在收到这个命令并回答OK前,收件方不得中断连接,即使传输出现错误。发件方在发出这个命令并收到OK答复前,也不得中断连接
2、服务器响应221(服务关闭)或其他代码。
代码实现
头文件
#pragma once
#include <string>
#include <vector>
#define WITH_OPENSSL 1
#if WITH_OPENSSL
#include <openssl/ossl_typ.h>
#endif
class EmailAccess
{
public:
EmailAccess();
EmailAccess(const std::string& strhost, int iport);
~EmailAccess();
private:
//
std::string m_strHost;
int m_iPort = 0;
//
#if WITH_OPENSSL
SSL_CTX* m_ctx = nullptr;
SSL* m_ssl = nullptr;
#endif
//
std::vector<std::string> m_vetTolist;
std::vector<std::string> m_vetCclist;
std::vector<std::string> m_vetAttachlist;
public:
private:
int InitNetwork(void);
//
const char* GetMimeType(const char* pFileExt);
static bool ReadFileContent(const char* pflnm, std::string& stout);
static const std::string Base64Encode(char const* psrc, unsigned srclen);
int RecvData(char* pbuf, int len);
int SendData(const char* pbuf, int len);
public:
int EmailConnect(void);
void EmailDisconnect(void);
void SetToList(const std::vector<std::string>& tolist);
void SetCcList(const std::vector<std::string>& cclist);
void SetAttachmentList(const std::vector<std::string>& attachlist);
int SendEmail(const std::string& strfrom, const std::string& strpswd, const std::string& strto, const std::string& strsubj, const std::string& strbody);
//
int SendTestEmail(const std::string& strto, const std::string& strcode);
};
源文件
#include "EmailAccess.h"
#include <sstream>
#include <filesystem>
#include <WinSock2.h>
#include <WS2tcpip.h>
#if WITH_OPENSSL
#include <openssl/ssl.h>
#endif
#include <random>
#include <fstream>
#include <sstream>
#include "LogView.h"
#pragma comment(lib, "ws2_32.lib")
#if WITH_OPENSSL
#pragma comment(lib, "libcrypto.lib")
#pragma comment(lib, "libssl.lib")
#endif
SOCKET m_sckEmail = INVALID_SOCKET;
addrinfo* otAddrInfo = nullptr;
const char MimeTypes[][2][128] =
{
{ "***", "application/octet-stream" },
{ "csv", "text/csv" },
{ "tsv", "text/tab-separated-values" },
{ "tab", "text/tab-separated-values" },
{ "html", "text/html" },
{ "htm", "text/html" },
{ "doc", "application/msword" },
{ "docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document" },
{ "ods", "application/x-vnd.oasis.opendocument.spreadsheet" },
{ "odt", "application/vnd.oasis.opendocument.text" },
C++实现SMTP邮件发送及SSL/TLS支持

最低0.47元/天 解锁文章
30

被折叠的 条评论
为什么被折叠?



