图片-精准获客

邮件发送,通过 C++来实现 SMTP 发送邮件,并且支持使用 SSL 的 465 端口进行发送

前言

C++实现SMTP邮件发送,支持通过SSL的465端口进行发送,涵盖附件添加、一次向多人发送、抄送等功能。

在此仅运用了特定库(用于支持SSL的465端口),其余部分为原生C++,可在Windows/Linux系统中运行。

网上多数为初始的支持25端口的明文发送方式,在此介绍一下SSL的实现思路。

实现思路

借助编程和SSL技术,运用SMTP协议。

运用了C++的多态语言特性,包括重载和虚函数。

文中给出了mail.h、mail.cpp以及main.cpp部分测试代码。

Linux安装

sudo apt -dev

Windows下需自行下载安装。

SMTP协议简介

SMTP协议的定义如下:

1. SMTP是一种由TCP协议支持的应用层协议,能够提供可靠且有效的电子邮件传输服务。

2. SMTP建立在TCP之上,是一种主要用于在传输系统之间传输邮件信息,并提供与来信相关通知的邮件服务。

3. SMTP独立于特定的传输子系统,仅需要可靠有序的数据流信道支持。

4. SMTP的重要特性之一是能够跨越网络传输邮件,即“SMTP邮件中继”。

5. SMTP是一个相对简单的基于文本的协议。

SMTP基本命令

SMTP基本命令包含以下几个:HELO、EHLO、MAIL、RCPT、DATA、AUTH LOGIN和QUIT。

1. HELO——发件方向收件方问候,其后跟随发件人的服务器地址或标识。收件方回答OK时表明自身身份。问候和确认过程表明两台机器能够进行通信,同时状态参量被重置,缓冲区被清空。

EHLO——申明身份,表示自身身份需要验证,需注意此部分需要进行验证,确认是用户还是其他情况,否则会出错。

2. MAIL——此命令用于开始传送邮件,其后跟随发件方邮件地址(返回邮件地址)。它也用于当邮件无法送达时,发送失败通知。为保证邮件成功发送,发件方的地址应被对方或中间转发方同意接收。此命令会清空有关缓冲区,为新的邮件做好准备。

3. RCPT——该命令告知收件方收件人的邮箱。当存在多个收件人时,需多次使用该命令RCPT TO,每次仅能指明一人。若接收方服务器不同意转发此地址的邮件,必须报550错误代码通知发件方。若服务器同意转发,它会更改邮件发送路径,将最初的目的地(该服务器)替换为下一个服务器。

4. DATA——收件方将该命令之后的数据作为发送的数据。数据被添加至数据缓冲区中,以单独一行是“.”的行结束数据。结束行对于接收方同时意味着立即开始缓冲区内的数据传送,传送结束后清空缓冲区。若传送被接收,接收方回复OK。

5. QUIT——SMTP要求接收方必须回答OK,然后中断传输;在收到此命令并回答OK前,收件方不得中断连接,即便传输出现错误。发件方在发出此命令并收到OK答复前,也不得中断连接。

6. AUTH LOGIN——登录邮箱,此部分通常需采用加密方式。

头文件mail.h

#pragma once

#include

#include

#include

#include

#ifndef WIN32

#include

#endif

class SmtpBase

{

protected:

struct EmailInfo

{

std::string smtpServer; //SMTP服务器

std::string serverPort; //SMTP服务器端口

std::string charset; //电子邮件字符集

std::string sender; //发件人姓名

std::string senderEmail; //发件人邮箱

std::string password; //发件人密码

std::string recipient; //收件人姓名

std::string recipientEmail; //收件人邮箱

std::map recvList; //收件人列表

std::string subject; //邮件主题

std::string message; //邮件内容

std::map ccEmail; //抄送列表

std::vector attachment; //附件

};

public:

virtual ~SmtpBase() {}

/**

* @brief 简单发送文本邮件

* @param from 发送者的帐号

* @param passs 发送者密码

* @param to 收件人

* @param subject 主题

* @param strMessage 邮件内容

*/

virtual int SendEmail(const std::string& from, const std::string& passs, const std::string& to, const std::string& subject, const std::string& strMessage) = 0;

/**

* @brief 发送邮件,包括附件以及抄送人和多个收件人

* @param from 发送者的帐号

* @param passs 发送者密码

* @param vecTo 收件人列表

* @param subject 主题

* @param strMessage 邮件内容

* @param attachment 附件列表 附件可以是绝对路径,默认是可执行程序目录下

* @param ccList 抄送列表

*/

virtual int SendEmail(const std::string& from, const std::string& passs, const std::vector& vecTo,

const std::string& subject, const std::string& strMessage, const std::vector& attachment,const std::vector& ccList) = 0;

std::string GetLastError()

{

return m_lastErrorMsg;

}

virtual int Read(void* buf, int num) = 0;

virtual int Write(const void* buf, int num) = 0;

virtual int Connect() = 0;

virtual int DisConnect() = 0;

protected:

std::string m_lastErrorMsg;

};

class SmtpEmail : public SmtpBase

{

public:

SmtpEmail(const std::string& emailHost, const std::string& port);

~SmtpEmail();

int SendEmail(const std::string& from, const std::string& passs, const std::string& to, const std::string& subject, const std::string& strMessage);

int SendEmail(const std::string& from, const std::string& passs, const std::vector& vecTo,

const std::string& subject, const std::string& strMessage, const std::vector& attachment, const std::vector& ccList);

protected:

int Read(void* buf, int num);

int Write(const void* buf, int num);

int Connect();

int DisConnect();

virtual std::string GetEmailBody(const EmailInfo &info);

private:

//int SMTPSSLComunicate(SSL *connection, const EmailInfo &info);

int SMTPComunicate(const EmailInfo &info);

protected:

addrinfo* m_addrinfo;

int m_socketfd;

std::string m_host;

std::string m_port;

bool m_isConnected;

};

class SimpleSmtpEmail : public SmtpEmail

{

public:

using SmtpEmail::SmtpEmail;

virtual std::string GetEmailBody(const EmailInfo &info);

};

class SslSmtpEmail : public SmtpEmail

{

public:

using SmtpEmail::SmtpEmail;

~SslSmtpEmail();

int Connect();

int DisConnect();

protected:

int Read(void* buf, int num);

int Write(const void* buf, int num);

private:

SSL_CTX *m_ctx;

SSL *m_ssl;

};

class SimpleSslSmtpEmail : public SslSmtpEmail

{

public:

using SslSmtpEmail::SslSmtpEmail;

virtual std::string GetEmailBody(const EmailInfo &info);

}

实现文件mail.cpp

#ifdef WIN32

#include

#include

#pragma comment(lib, “ws2_32.lib”)

#else

#include

#include

#include

#include

#define INVALID_SOCKET -1

#endif

template

std::string join(T& vecData, const std::string& delim)

{

if (vecData.size() <= 0)

{

return std::string();

}

std::stringstream ss;

for (auto& item : vecData)

{

ss << delim << item ;

}

return ss.str().substr(delim.length());

}

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” },

{ “rtf”, “application/rtf” },

{ “sxw”, “application/vnd.sun.xml.writer” },

{ “txt”, “text/plain” },

{ “xls”, “application/vnd.ms-excel” },

{ “xlsx”, “application/vnd.openxmlformats-officedocument.spreadsheetml.sheet” },

{ “pdf”, “application/pdf” },

{ “ppt”, “application/vnd.ms-powerpoint” },

{ “pps”, “application/vnd.ms-powerpoint” },

{ “pptx”, “application/vnd.openxmlformats-officedocument.presentationml.presentation” },

{ “wmf”, “image/x-wmf” },

{ “atom”, “application/atom+xml” },

{ “xml”, “application/xml” },

{ “json”, “application/json” },

{ “js”, “application/javascript” },

{ “ogg”, “application/ogg” },

{ “ps”, “application/postscript” },

{ “woff”, “application/x-woff” },

{ “xhtml”,”application/xhtml+xml” },

{ “xht”, “application/xhtml+xml” },

{ “zip”, “application/zip” },

{ “gz”, “application/x-gzip” },

{ “rar”, “application/rar” },

{ “rm”, “application/vnd.rn-realmedia” },

{ “rmvb”, “application/vnd.rn-realmedia-vbr” },

{ “swf”, “application/x-shockwave-flash” },

{ “au”, “audio/basic” },

{ “snd”, “audio/basic” },

{ “mid”, “audio/mid” },

{ “rmi”, “audio/mid” },

{ “mp3”, “audio/mpeg” },

{ “aif”, “audio/x-aiff” },

{ “aifc”, “audio/x-aiff” },

{ “aiff”, “audio/x-aiff” },

{ “m3u”, “audio/x-mpegurl” },

{ “ra”, “audio/vnd.rn-realaudio” },

{ “ram”, “audio/vnd.rn-realaudio” },

{ “wav”, “audio/x-wave” },

{ “wma”, “audio/x-ms-wma” },

{ “m4a”, “audio/x-m4a” },

{ “bmp”, “image/bmp” },

{ “gif”, “image/gif” },

{ “jpe”, “image/jpeg” },

{ “jpeg”, “image/jpeg” },

{ “jpg”, “image/jpeg” },

{ “jfif”, “image/jpeg” },

{ “png”, “image/png” },

{ “svg”, “image/svg+xml” },

{ “tif”, “image/tiff” },

{ “tiff”, “image/tiff” },

{ “ico”, “image/vnd.microsoft.icon” },

{ “css”, “text/css” },

{ “bas”, “text/plain” },

{ “c”, “text/plain” },

{ “h”, “text/plain” },

{ “rtx”, “text/richt

© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容