主要参考:
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;
}