邮件正文及其附件的发送的C++实现

 这段代码我花了整整一天来编写,如果转载,请注明出处,谢谢!

   前面的一篇文章已经讲了如何发送邮件正文,原理我就不再叙述了,要了解的同学请到这里查看!

   http://blog.csdn.net/lishuhuakai/article/details/27503503

   网上很多发送邮件附件的代码都不能用,所以我用心写了一个,直接封装成了一个类,需要的同学可以直接调用这个类来发送邮件,使用的是纯C++,不含MFC,请放心使用。(在VS2013下测试完美通过!)

   废话不多说,直接上代码!

   Smtp.h

#include <WinSock2.h>
#include <iostream>
#include <string>
#include <list>
using namespace std;

#pragma  comment(lib, "ws2_32.lib")	/*链接ws2_32.lib动态链接库*/
const int MAXLEN = 1024;
const int MAX_FILE_LEN = 6000;

static const char base64Char[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

struct FILEINFO /*用来记录文件的一些信息*/
{
	char fileName[128]; /*文件名称*/
	char filePath[256]; /*文件绝对路径*/
};

class CSmtp
{
public:
	CSmtp(void);
	CSmtp(
		int port,
		string srvDomain,	//smtp服务器域名
		string userName,	//用户名
		string password,	//密码
		string targetEmail, //目的邮件地址
		string emailTitle,  //主题
		string content       //内容
		);
public:
	~CSmtp(void);
public:
	int port;
public:
	string domain;
	string user;
	string pass;
	string targetAddr;
	string title;
	string content;
	/*为了方便添加文件,删除文件神马的,使用list容器最为方便,相信大家在数据结构里面都学过*/
	list <FILEINFO *> listFile;
	char *fileData;
public:
	char buff[MAXLEN + 1];
	int buffLen;
	SOCKET sockClient;	//客户端的套接字
public:
	SOCKET CreateConn(); /*创建连接*/

	BOOL Send(string &message);
	BOOL Recv();
	int GetStrLen(char* pString); //得到字符串的长度

	void FormatEmailHead(string &email);//格式化要发送的邮件头部
	int Login();
	BOOL SendEmailHead();		//发送邮件头部信息
	BOOL SendTextBody();	    //发送文本信息
	//BOOL SendAttachment();	    //发送附件
	BOOL SendAttachment_Ex();
	BOOL SendEnd();
	int SendEmail();
public:
	void AddAttachment(string &filePath); //添加附件
	void DeleteAttachment(string &filePath); //删除附件
	void DeleteAllAttachment(); //删除所有的附件
	int SendEmail_Ex();
	char* base64Encode(char const* origSigned, unsigned origLength);
};

Smtp.cpp

#include "Smtp.h"
#include <iostream>
#include <fstream>
using namespace std;

/*base64采用别人的编码,不过,这不是重点,重点是我完成了我的一个比较好的邮件发送客户端*/
char* CSmtp::base64Encode(char const* origSigned, unsigned origLength)
{
	unsigned char const* orig = (unsigned char const*)origSigned; // in case any input bytes have the MSB set
	if (orig == NULL) return NULL;

	unsigned const numOrig24BitValues = origLength / 3;
	bool havePadding = origLength > numOrig24BitValues * 3;
	bool havePadding2 = origLength == numOrig24BitValues * 3 + 2;
	unsigned const numResultBytes = 4 * (numOrig24BitValues + havePadding);
	char* result = new char[numResultBytes + 3]; // allow for trailing '/0'

	// Map each full group of 3 input bytes into 4 output base-64 characters:
	unsigned i;
	for (i = 0; i < numOrig24BitValues; ++i)
	{
		result[4 * i + 0] = base64Char[(orig[3 * i] >> 2) & 0x3F];
		result[4 * i + 1] = base64Char[(((orig[3 * i] & 0x3) << 4) | (orig[3 * i + 1] >> 4)) & 0x3F];
		result[4 * i + 2] = base64Char[((orig[3 * i + 1] << 2) | (orig[3 * i + 2] >> 6)) & 0x3F];
		result[4 * i + 3] = base64Char[orig[3 * i + 2] & 0x3F];
	}

	// Now, take padding into account.  (Note: i == numOrig24BitValues)
	if (havePadding)
	{
		result[4 * i + 0] = base64Char[(orig[3 * i] >> 2) & 0x3F];
		if (havePadding2)
		{
			result[4 * i + 1] = base64Char[(((orig[3 * i] & 0x3) << 4) | (orig[3 * i + 1] >> 4)) & 0x3F];
			result[4 * i + 2] = base64Char[(orig[3 * i + 1] << 2) & 0x3F];
		}
		else
		{
			result[4 * i + 1] = base64Char[((orig[3 * i] & 0x3) << 4) & 0x3F];
			result[4 * i + 2] = '=';
		}
		result[4 * i + 3] = '=';
	}

	result[numResultBytes] = '\0';
	return result;
}
CSmtp::CSmtp(void)
{
	this->content = "";
	this->port = 0;
	this->user = "";
	this->pass = "";
	this->targetAddr = "";
	this->title = "";
	this->domain = "";
	this->sockClient = 0;

}

CSmtp::~CSmtp(void)
{
	delete []fileData;
	closesocket(sockClient);
	WSACleanup();
}

CSmtp::CSmtp(
			 int port,
			 string srvDomain,
			 string userName,
			 string password,
			 string targetEmail,
			 string emailTitle,
			 string content
			 )
{
	this->content = content;
	this->port = port;
	this->user = userName;
	this->pass = password;
	this->targetAddr = targetEmail;
	this->title = emailTitle;
	this->domain = srvDomain;

	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	wVersionRequested = MAKEWORD(2, 1);
	err = WSAStartup(wVersionRequested, &wsaData);
	this->sockClient = CreateConn(); //创建连接
}

SOCKET CSmtp::CreateConn()
{
	//为建立socket对象做准备,初始化环境
	SOCKET sockClient = socket(AF_INET,SOCK_STREAM,0); //建立socket对象
	SOCKADDR_IN addrSrv;
	HOSTENT* pHostent;
	pHostent = gethostbyname(domain.c_str());  //得到有关于域名的信息

	addrSrv.sin_addr.S_un.S_addr = *((DWORD *)pHostent->h_addr_list[0]);	//得到smtp服务器的网络字节序的ip地址
	addrSrv.sin_family = AF_INET;
	addrSrv.sin_port = htons(port);
	int err = connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));   //向服务器发送请求
	if(err != 0)
	{
		return 0;
		//printf("链接失败\n");
	}
	return sockClient;
}

BOOL CSmtp::Send(string &message)
{
	int err = send(sockClient, message.c_str(), message.length(), 0);
	if (err == SOCKET_ERROR)
	{
		return FALSE;
	}
	cout << message << endl;
	return TRUE;
}

BOOL CSmtp::Recv()
{
	memset(buff, 0, sizeof(char)* (MAXLEN + 1));
	int err = recv(sockClient, buff, MAXLEN, 0); //接收数据
	if (err == SOCKET_ERROR)
	{
		return FALSE;
	}
	buff[err] = '\0';
	cout << buff << endl;
	return TRUE;
}

int CSmtp::Login()
{
	Recv();

	string sendBuff;
	sendBuff = "EHLO ";
	sendBuff += user;
	sendBuff += "\r\n";

	if (FALSE == Send(sendBuff) || FALSE == Recv()) //既接收也发送
	{
		return 1; /*1表示发送失败由于网络错误*/
	}

	sendBuff.empty();
	sendBuff = "AUTH LOGIN\r\n";
	if (FALSE == Send(sendBuff) || FALSE == Recv()) //请求登陆
	{
		return 1; /*1表示发送失败由于网络错误*/
	}

	sendBuff.empty();
	int pos = user.find('@', 0);
	sendBuff = user.substr(0, pos); //得到用户名

	char *ecode;
	/*在这里顺带扯一句,关于string类的length函数与C语言中的strlen函数的区别,strlen计算出来的长度,只到'\0'字符为止,而string::length()函数实际上返回的是string类中字符数组的大小,你自己可以测试一下,这也是为什么我下面不使用string::length()的原因*/

	ecode = base64Encode(sendBuff.c_str(), strlen(sendBuff.c_str()));
	sendBuff.empty();
	sendBuff = ecode;
	sendBuff += "\r\n";
	delete []ecode;

	if (FALSE == Send(sendBuff) || FALSE == Recv()) //发送用户名,并接收服务器的返回
	{
		return 1; /*错误码1表示发送失败由于网络错误*/
	}

	sendBuff.empty();
	ecode = base64Encode(pass.c_str(), strlen(pass.c_str()));
	sendBuff = ecode;
	sendBuff += "\r\n";
	delete []ecode;

	if (FALSE == Send(sendBuff) || FALSE == Recv()) //发送用户密码,并接收服务器的返回
	{
		return 1; /*错误码1表示发送失败由于网络错误*/
	}

	if (NULL != strstr(buff, "550"))
	{
		return 2;/*错误码2表示用户名错误*/
	}

	if (NULL != strstr(buff, "535")) /*535是认证失败的返回*/
	{
		return 3; /*错误码3表示密码错误*/
	}
	return 0;
}

BOOL CSmtp::SendEmailHead()		//发送邮件头部信息
{
	string sendBuff;
	sendBuff = "MAIL FROM: <" + user + ">\r\n";
	if (FALSE == Send(sendBuff) || FALSE == Recv())
	{
		return FALSE; /*表示发送失败由于网络错误*/
	}

	sendBuff.empty();
	sendBuff = "RCPT TO: <" + targetAddr + ">\r\n";
	if (FALSE == Send(sendBuff) || FALSE == Recv())
	{
		return FALSE; /*表示发送失败由于网络错误*/
	}

	sendBuff.empty();
	sendBuff = "DATA\r\n";
	if (FALSE == Send(sendBuff) || FALSE == Recv())
	{
		return FALSE; //表示发送失败由于网络错误
	}

	sendBuff.empty();
	FormatEmailHead(sendBuff);
	if (FALSE == Send(sendBuff))
//发送完头部之后不必调用接收函数,因为你没有\r\n.\r\n结尾,服务器认为你没有发完数据,所以不会返回什么值
	{
		return FALSE; /*表示发送失败由于网络错误*/
	}
	return TRUE;
}

void CSmtp::FormatEmailHead(string &email)
{/*格式化要发送的内容*/
	email = "From: ";
	email += user;
	email += "\r\n";

	email += "To: ";
	email += targetAddr;
	email += "\r\n";

	email += "Subject: ";
	email += title;
	email += "\r\n";

	email += "MIME-Version: 1.0";
	email += "\r\n";

	email += "Content-Type: multipart/mixed;boundary=qwertyuiop";
	email += "\r\n";
	email += "\r\n";
}

BOOL CSmtp::SendTextBody()  /*发送邮件文本*/
{
	string sendBuff;
	sendBuff = "--qwertyuiop\r\n";
	sendBuff += "Content-Type: text/plain;";
	sendBuff += "charset=\"gb2312\"\r\n\r\n";
	sendBuff += content;
	sendBuff += "\r\n\r\n";
	return Send(sendBuff);
}

BOOL CSmtp::SendAttachment_Ex() /*发送附件*/
{
	for (list<FILEINFO *>::iterator pIter = listFile.begin(); pIter != listFile.end(); pIter++)
	{
		cout << "Attachment is sending ~~~~~" << endl;
		cout << "Please be patient!" << endl;
		string sendBuff;
		sendBuff = "--qwertyuiop\r\n";
		sendBuff += "Content-Type: application/octet-stream;\r\n";
		sendBuff += " name=\"";
		sendBuff += "base64.cpp\"";
		sendBuff += "\r\n";

		sendBuff += "Content-Transfer-Encoding: base64\r\n";
		sendBuff += "Content-Disposition: attachment;\r\n";
		sendBuff += " filename=\"";
		sendBuff += (*pIter)->fileName;
		sendBuff += "\"";

		sendBuff += "\r\n";
		sendBuff += "\r\n";
		Send(sendBuff);
		ifstream ifs((*pIter)->filePath, ios::in | ios::binary);

		char fileBuff[MAX_FILE_LEN];
		char *chSendBuff;
		memset(fileBuff, 0, sizeof(fileBuff));
		/*文件使用base64加密传送*/
		while (ifs.read(fileBuff, MAX_FILE_LEN))
		{
			//cout << ifs.gcount() << endl;
			chSendBuff = base64Encode(fileBuff, MAX_FILE_LEN);
			chSendBuff[strlen(chSendBuff)] = '\r';
			chSendBuff[strlen(chSendBuff)] = '\n';
			send(sockClient, chSendBuff, strlen(chSendBuff), 0);
			delete[]chSendBuff;
		}
		//cout << ifs.gcount() << endl;
		chSendBuff = base64Encode(fileBuff, ifs.gcount());
		chSendBuff[strlen(chSendBuff)] = '\r';
		chSendBuff[strlen(chSendBuff)] = '\n';
		int err = send(sockClient, chSendBuff, strlen(chSendBuff), 0);

		if (err != strlen(chSendBuff))
		{
			cout << "文件传送出错!" << endl;
			return FALSE;
		}
		delete []chSendBuff;
	}
	return TRUE;
}

BOOL CSmtp::SendEnd() /*发送结尾信息*/
{
	string sendBuff;
	sendBuff = "--qwertyuiop--";
	sendBuff += "\r\n.\r\n";
	if (FALSE == Send(sendBuff) || FALSE == Recv())
	{
		return FALSE;
	}
	cout << buff << endl;
	sendBuff.empty();
	sendBuff = "QUIT\r\n";
	return (Send(sendBuff) && Recv());
}

int CSmtp::SendEmail_Ex()
{
	int err = Login(); //先登录
	if (err != 0)
	{
		return err; //错误代码必须要返回
	}
	if (FALSE == SendEmailHead()) //发送EMAIL头部信息
	{
		return 1; /*错误码1是由于网络的错误*/
	}
	if (FALSE == SendTextBody())
	{
		return 1; /*错误码1是由于网络的错误*/
	}
	if (FALSE == SendAttachment_Ex())
	{
		return 1; /*错误码1是由于网络的错误*/
	}
	if (FALSE == SendEnd())
	{
		return 1; /*错误码1是由于网络的错误*/
	}
	return 0; /*0表示没有出错*/
}

void CSmtp::AddAttachment(string &filePath) //添加附件
{
	FILEINFO *pFile = new FILEINFO;
	strcpy_s(pFile->filePath, filePath.c_str());
	const char *p = filePath.c_str();
	strcpy_s(pFile->fileName, p + filePath.find_last_of("\\") + 1);
	listFile.push_back(pFile);
}

void CSmtp::DeleteAttachment(string &filePath) //删除附件
{
	list<FILEINFO *>::iterator pIter;
	for (pIter = listFile.begin(); pIter != listFile.end(); pIter++)
	{
		if (strcmp((*pIter)->filePath, filePath.c_str()) == 0)
		{
			listFile.remove(*pIter);
			delete *pIter;
			break;
		}
	}
}

void CSmtp::DeleteAllAttachment() /*删除所有的文件*/
{
	for (list<FILEINFO *>::iterator pIter = listFile.begin(); pIter != listFile.end(); pIter++)
	{
		listFile.remove(*pIter);
		delete *pIter;
	}
}

测试代码如下:

main.cpp

#include "Smtp.h"
#include <iostream>
using namespace std;

int main()
{

	CSmtp smtp(
		25,								/*smtp端口*/
		"smtp.163.com",					/*smtp服务器地址*/
		"[email protected]",	/*你的邮箱地址*/
		"19930714lyh",					/*邮箱密码*/
		"[email protected]",	/*目的邮箱地址*/
		"好啊!",							/*主题*/
		"李懿虎同学,你好!收到请回复!"		/*邮件正文*/
		);
	//添加附件时注意,\一定要写成\\,因为转义字符的缘故
	string filePath("C:\\Users\\李懿虎\\Desktop\\App\\SAkura\\模版.png");
	smtp.AddAttachment(filePath);
	/*还可以调用CSmtp::DeleteAttachment函数删除附件,还有一些函数,自己看头文件吧!*/
	filePath = "C:\\Users\\李懿虎\\Desktop\\sendEmail.cpp";
	smtp.AddAttachment(filePath);

	smtp.SendEmail_Ex();
	system("pause");
	return 0;
}

邮件正文及其附件的发送的C++实现,布布扣,bubuko.com

时间: 2024-08-24 23:25:58

邮件正文及其附件的发送的C++实现的相关文章

C#操作EML邮件文件实例(含HTML格式化邮件正文和附件)

使用QQ邮箱.163邮箱等导出的EML邮件,包含了邮件的发件人.主题.内容.附件等所有信息,该实例就如何解析这些信息,并在编辑后保存做个Demo. 如下图所示,EML文件是编码后的文本文件,可以使用正则表达式识别其中的关键字,例如Received.Sender.Cc.Bcc.From等. 但解析后的内容是经过编码后的,例如Sender的内容X-QQ-FEAT……,这个时候需要对内容进行解码,一般使用Base64进行编码. EML源文件包含了很多信息,除了使用邮箱客户端看到的收件人.发件人.主题.

javamail 收邮件并解析附件

package com.zz.mail; import java.io.*; import java.text.*; import java.util.*; import javax.mail.*; import javax.mail.internet.*; import java.io.File; import jxl.*; /** * 有一封邮件就需要建立一个ReciveMail对象 */ public class ReciveOneMail { private MimeMessage mi

获取163邮箱的邮件 并下载附件

老师要求让获取邮箱邮件内容,发件人.收件人.发送时间等等,转存到excel里面,并下载邮件带的附件,通过网上搜集资料,整理出如下代码,只是实现功能,代码并未优化. 使用的时候只需要填写自己邮箱账号密码就可 下面贴出代码, package ltg.defualt; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; import ltg.helper.POP3ReceiveMailTe

通过 IceWarp WebMail 智能附件轻松发送超大文件

IceWarp v11 邮件服务器可以设置系统中普通用户的文件夹映射作为该用户的个人 FTP 文件夹,让用户通过 WebMail 去管理和使用邮件服务器端提供的 FTP  服务,然后结合 WebMail 的智能附件(SmartAttach)功能,将超大文件通过邮件方式发送给对方.实际发送的并非是超大文件本身,而是通过 HTTP 方式提供的文件分享下载地址,超大附件的下载操作并不会占用邮件服务器有限的带宽资源.另外,还可以再进一步,结合最新版 IceWarp V11.4 提供的  TeamChat

phpMailer 发邮件例子、乱码、发送html内容介绍

//phpmailer代码工具类以及传到我的csdn"我的资源"中,可以带这里去下载</span> echo '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'; require_once("class.phpmailer.php"); //下载的文件必须放在该文件所在目录 $mail = new PHPMailer

利用springframework+javax.mail发邮件(普通邮件、带附件邮件、HTML格式邮件)

Spring提供了发送电子邮件的支持,可以发送普通邮件.带附件邮件.HTML格式邮件,甚至还可以使用Velocity模板定制化邮件内容. 一.引入相关的库 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <!-- spring核心库 -->         <dependency>             <groupId>org.springframework<

解决zabbix邮件内容为附件

安装zabbix之后,设置邮件脚本报警的时候,发送的报警内容变成了tcmime.1278.1278.1724.bin或ATT00001.bin. yum -y install  mailx dos2unix     //安装mailx工具和dos2unix转换工具 以下是脚本内容: [root@localhost alertscripts]# cat sendmail.sh #!/bin/bash #export.UTF-8         //解决发送的中文变成了乱码的问题 FILE=/tmp

Exchange 2013/2016 OWA无法访问邮件正文

问题描述 Exchange 2016 CU9 | 用户使用OWA查看邮件正文时,偶尔出现以下报错:排查过程 1. 检查服务器上的应用程序日志和系统日志,发现有143报错,显示OWA无法加载RMS templates. 2. 检查RMS设置,发现RMS是enabled状态.但是据客户反应,RMS服务器和RMS功能目前是不可用状态. 3. 从以下层面讲RMS功能禁用: 1) IRMConfiguration Set-Irmconfirguation -InternalLicensingEnable

zabbix邮件报警以附件发送的解决方法

最近搭建了一个zabbix服务器,但是到邮件报警的时候出问题了,为什么发送老是发送个附件.脚本命令是echo "$3"|mail -s "$2" $1  应该是对着呢. 最后查了好多资料,实验了很多次,发现大致的原因.因为windows和linux的换行符不同导致的. 可以把附件file一下看到: [[email protected] ~]# file tcmime.1953.1953.2321.bin tcmime.1953.1953.2321.bin: UTF-