C++ smtp 发送邮件

  • Post author:
  • Post category:其他


主要参考:


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


调整的内容有:


1. 去除附件发送


2. 增加Linux平台运行


直接上代码:



Stmp.h

#ifndef __SMTP_H__
#define __SMTP_H__

#ifdef _MSC_VER
#	include <winsock2.h>
#	pragma comment(lib, "Ws2_32.lib")
#else
#	include <unistd.h>
#	include <sys/errno.h>
#	include <sys/fcntl.h>
#	include <sys/types.h>
#	include <sys/socket.h>
#	include <netinet/in.h>
#	include <netinet/tcp.h>
#	include <arpa/inet.h>
#	include <netdb.h>
#	include <net/if.h>
#	include <sys/ioctl.h>
#endif

#include <iostream>
#include <list>
using namespace std;

const int MAX_EMAIL_MESSAGE_LEN = 1024;

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

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;

public:
	char buff[MAX_EMAIL_MESSAGE_LEN + 1];
	int buffLen;
	int sockClient;

public:
	bool CreateConn();
	bool Send(string& strMessage);
	bool Recv();

	void FormatEmailHead(string& strEmail);
	int Login();
	bool SendEmailHead();
	bool SendTextBody();
	bool SendEnd();

public:
	void SetSrvDomain(string& strDomain) { this->domain = strDomain; }
	void SetUserName(string& strUser) { this->user = strUser; }
	void SetPass(string& strPass) { this->pass = strPass; }
	void SetTargetEmail(string& strTargetAddr) { this->targetAddr = strTargetAddr; }
	void SetEmailTitle(string& strTitle) { this->title = strTitle; }
	void SetContent(string& strContent) { this->content = strContent; }
	void SetPort(int nPort) { this->port = nPort; }
	int SendEmail_Ex();
	char* base64Encode(char const* pOrigSigned, unsigned origLength);
};

#endif // !__SMTP_H__

Smtp.cpp

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

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'

	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];
	}

	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 = 25;
	this->user = "";
	this->pass = "";
	this->targetAddr = "";
	this->title = "";
	this->domain = "";

#ifdef _MSC_VER
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	wVersionRequested = MAKEWORD(2, 1);
	err = WSAStartup(wVersionRequested, &wsaData);
#endif
	this->sockClient = 0;
}

CSmtp::~CSmtp(void)
{
#ifdef _MSC_VER
	closesocket(sockClient);
	WSACleanup();
#else
	close(sockClient);
#endif
}

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;

#ifdef _MSC_VER
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	wVersionRequested = MAKEWORD(2, 1);
	err = WSAStartup(wVersionRequested, &wsaData);
#endif
	this->sockClient = 0;
}

bool CSmtp::CreateConn()
{
	int skClientTemp = (int)socket(AF_INET, SOCK_STREAM, 0);
	sockaddr_in saddr;
	hostent* pHostent;
	pHostent = gethostbyname(domain.c_str());

	saddr.sin_addr.s_addr = *((unsigned long*)pHostent->h_addr_list[0]);
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(port);
	int err = connect(skClientTemp, (sockaddr*)&saddr, sizeof(saddr));
	if (err != 0)
		return false;
	this->sockClient = (int)skClientTemp;
	if (false == Recv())
		return false;
	return true;
}

bool CSmtp::Send(string& strMessage)
{
	int err = (int)send(sockClient, strMessage.c_str(), (int)strMessage.length(), 0);
	if (err < 0)
	{
		return false;
	}
	cout << strMessage.c_str() << endl;
	return true;
}

bool CSmtp::Recv()
{
	memset(buff, 0, sizeof(char)* (MAX_EMAIL_MESSAGE_LEN + 1));
	int err = recv(sockClient, buff, MAX_EMAIL_MESSAGE_LEN, 0);
	if (err < 0)
	{
		return false;
	}
	buff[err] = '\0';
	cout << buff << endl;
	return true;
}

int CSmtp::Login()
{
	string sendBuff;
	sendBuff = "EHLO ";
	sendBuff += user;
	sendBuff += "\r\n";

	if (false == Send(sendBuff) || false == Recv())
		return 1;

	sendBuff.empty();
	sendBuff = "AUTH LOGIN\r\n";
	if (false == Send(sendBuff) || false == Recv())
		return 1;

	sendBuff.empty();
	int pos = (int)user.find('@', 0);
	sendBuff = user.substr(0, pos);

	char *ecode;

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

	if (false == Send(sendBuff) || false == Recv())
		return 1;

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

	if (false == Send(sendBuff) || false == Recv())
		return 1;

	if (NULL != strstr(buff, "550"))
		return 2;

	if (NULL != strstr(buff, "535"))
		return 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))
		return false;

	return true;
}

void CSmtp::FormatEmailHead(string& strEmail)
{
	strEmail = "From: ";
	strEmail += user;
	strEmail += "\r\n";

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

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

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

	strEmail += "Content-Type: multipart/mixed;boundary=qwertyuiop";
	strEmail += "\r\n";
	strEmail += "\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::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()
{
	if (false == CreateConn())
		return 1;
	int err = Login();
	if (err != 0)
		return err;
	if (false == SendEmailHead())
		return 1;
	if (false == SendTextBody())
		return 1;
	if (false == SendEnd())
		return 1;
	return 0;
}

测试代码

main.cpp

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

int main()
{
	CSmtp smtp(
		25,									/*smtp端口*/
		"smtp.qq.com",						/*smtp服务器地址*/
		"from@qq.com",				        /*你的邮箱地址*/
		"password",					        /*邮箱密码*/
		"to@qq.com",					    /*目的邮箱地址*/
		"title",							/*主题*/
		"要发送的内容"		                /*邮件正文*/
	);

	int err;
	if ((err = smtp.SendEmail_Ex()) != 0)
	{
		if (err == 1)
			cout << "错误1: 由于网络不畅通,发送失败!" << endl;
		if (err == 2)
			cout << "错误2: 用户名错误,请核对!" << endl;
		if (err == 3)
			cout << "错误3: 用户密码错误,请核对!" << endl;
		if (err == 4)
			cout << "错误4: 请检查附件目录是否正确,以及文件是否存在!" << endl;
	}

	system("pause");
	return 0;
}