c++ 发邮件(含附件)

本程序在vs2013测试通过,一共3个文件,发邮件的程序封装为Csmtp 类。

这里写图片描述

1,测试用的主函数


#include "Csmtp.h"
#pragma comment(lib, "Kernel32.lib")  

int main()
{

	Csmtp mail(
		25,
		"smtp.126.com",
		"xxx@126.com",// 来源邮箱
		"xxx",   //密码
		"xxx.com" //目标邮箱
		);

	if (!mail.CReateSocket())
	{
		cout << "ReateSocket failed!" << endl;
		return -1;//
	}
	//标题默认是主机名,内容默认是ip
	mail.setTitle("test mail");
	mail.setContent("this is content.");
	//附件路径错误,不影响邮件正文的发送。
	mail.addfile("test.jpg"); //添加附件
	//mail.addfile("test2.png"); //添加附件

	mail.SendMail(); //类主函数
	system("pause");
	return 0;
}

2, Csmtp类定义

#include <iostream>  
#include <string>  
#include <vector>
#include <fstream>  

#include <WinSock2.h>  //适用平台 Windows

#pragma  comment(lib, "ws2_32.lib") /*链接ws2_32.lib动态链接库*/ 
// POP3服务器(端口:110) Csmtp服务器(端口:25) 
using namespace std;
class Csmtp
{

	int port;
	string domain;
	string user;
	string pass;
	string target;
	string title;  //邮件标题
	string content;  //邮件内容


	HOSTENT* pHostent;
	SOCKET sockClient;  //客户端的套接字
	vector <string> filename;  //存储附件名的向量

public:

	Csmtp(
		int _port, //端口25
		string _domain,     //域名
		string _user,       //发送者的邮箱
		string _pass,       //密码
		string _target)     //目标邮箱
		:port(_port), domain(_domain), user(_user), pass(_pass), target(_target){};//内容 
	bool CReateSocket();
	void setTitle(string tem){ title = tem; }
	void setContent(string tem){ content = tem; }

	int SendAttachment(SOCKET &sockClient);
	int SendMail();
	void addfile(string str){ filename.push_back(str); }

};

3, Csmtp 类的实现

#include "Csmtp.h"
//#include <afx.h>//异常类
static const char base64Char[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
char* 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;
}


int Csmtp::SendAttachment(SOCKET &sockClient) /*发送附件*/
{
	for (std::vector<string>::iterator iter = filename.begin(); iter != filename.end(); iter++)
	{
		cout << "Attachment is sending··· " << endl;

		string path = *iter;
		ifstream ifs(path, ios::in | ios::binary); //'或链接2个属性,以输入、二进制打开'
		if (false == ifs.is_open())
		{
			cout << "无法打开文件!" << endl;
			return 1;
		}

		string sendstring;
		sendstring = "--@boundary@\r\nContent-Type: application/octet-stream; name=\"1.jpg\"\r\n";
		sendstring += "Content-Disposition: attachment; filename=\"1.jpg\"\r\n";
		sendstring += "Content-Transfer-Encoding: base64\r\n\r\n";
		send(sockClient, sendstring.c_str(), sendstring.length(), 0);

		//infile.read((char*)buffer,sizeof(数据类型));

		// get length of file:
		ifs.seekg(0, ifs.end);
		int length = ifs.tellg();
		ifs.seekg(0, ifs.beg);
		cout << "length:" << length << endl;
		// allocate memory:
		char * buffer = new char[length];
		// read data as a block:
		ifs.read(buffer, length);
		ifs.close();
		char *pbase;
		pbase = base64Encode(buffer, length);
		delete[]buffer;
		string str(pbase);
		delete[]pbase;
		str += "\r\n";
		int err = send(sockClient, str.c_str(), strlen(str.c_str()), 0);

		if (err != strlen(str.c_str()))
		{
			cout << "附件发送出错!" << endl;
			return 1;
		}
	}
	return 0;
}


bool Csmtp::CReateSocket()
{
	WSADATA wsaData;
	WORD wVersionRequested = MAKEWORD(2, 1);
	//WSAStarup,即WSA(Windows SocKNDs Asynchronous,Windows套接字异步)的启动命令
	int err = WSAStartup(wVersionRequested, &wsaData);
	cout << "WSAStartup(0:successful):" << err << endl;

	char namebuf[128];    //获得本地计算机名
	string ip_list;
	if (0 == gethostname(namebuf, 128))
	{
		struct hostent* pHost;  //获得本地IP地址
		pHost = gethostbyname(namebuf);  //pHost返回的是指向主机的列表
		for (int i = 0; pHost != NULL&&pHost->h_addr_list[i] != NULL; i++)
		{
			string tem = inet_ntoa(*(struct in_addr *)pHost->h_addr_list[i]);
			ip_list += tem;
			ip_list += "\n";
		}
	}
	else
	{
		cout << "获取主机信息失败..." << endl;
	}
	//
	title = namebuf;// 邮件标题
	content = ip_list; //主机ip

	sockClient = socket(AF_INET, SOCK_STREAM, 0); //建立socket对象  

	pHostent = gethostbyname(domain.c_str()); //得到有关于域名的信息

	if (pHostent == NULL)
	{
		printf("创建连接失败,也许没联网!\n");
		return false;
	}

	return true;
}


int Csmtp::SendMail()
{
	char *ecode;

	char buff[500];  //recv函数返回的结果
	int err = 0;
	string message; //

	SOCKADDR_IN addrServer;  //服务端地址
	addrServer.sin_addr.S_un.S_addr = *((DWORD *)pHostent->h_addr_list[0]); //得到smtp服务器的网络字节序的ip地址     



	addrServer.sin_family = AF_INET;
	addrServer.sin_port = htons(port); //连接端口25 
	//int connect (SOCKET s , const struct sockaddr FAR *name , int namelen );
	err = connect(sockClient, (SOCKADDR*)&addrServer, sizeof(SOCKADDR));   //向服务器发送请求  
	cout << "connect:" << err << endl;
	//telnet smtp.126.com 25 连接服务器结束
	buff[recv(sockClient, buff, 500, 0)] = '\0';
	cout<<"connect:"<<buff<<endl;

	message = "ehlo 126.com\r\n";
	send(sockClient, message.c_str(), message.length(), 0);

	buff[recv(sockClient, buff, 500, 0)] = '\0';
	cout<<"helo:"<<buff<<endl;

	message = "auth login \r\n";
	send(sockClient, message.c_str(), message.length(), 0);
	buff[recv(sockClient, buff, 500, 0)] = '\0';
	cout<<"auth login:"<<buff<<endl;
	//上传邮箱名
	message = user;
	ecode = base64Encode(message.c_str(), strlen(message.c_str()));
	message = ecode;
	message += "\r\n";
	delete[]ecode;
	send(sockClient, message.c_str(), message.length(), 0);
	buff[recv(sockClient, buff, 500, 0)] = '\0';
	cout<<"usrname:"<<buff<<endl;
	//上传邮箱密码
	message = pass;
	ecode = base64Encode(message.c_str(), strlen(message.c_str()));
	message = ecode;
	delete[]ecode;
	message += "\r\n";
	send(sockClient, message.c_str(), message.length(), 0);
	buff[recv(sockClient, buff, 500, 0)] = '\0';
	cout<<"password:"<<buff<<endl;

	message = "mail from:<" + user + ">\r\nrcpt to:<" + target + ">\r\n";
	send(sockClient, message.c_str(), message.length(), 0);
	buff[recv(sockClient, buff, 500, 0)] = '\0';
	cout<<"mail from: "<<buff<<endl;
	buff[recv(sockClient, buff, 500, 0)] = '\0';
	cout<<"rcpt to: "<<buff<<endl;

	message = "data\r\n";//data要单独发送一次
	send(sockClient, message.c_str(), message.length(), 0);
	buff[recv(sockClient, buff, 500, 0)] = '\0';
	cout<<"data: "<<buff<<endl;
	///-----------------------------------------DATA-------------------------------------
	//要使用Csmtp 发送附件, 需要对Csmtp 头信息进行说明, 改变Content-type 及为每一段正文添加BOUNDARY 名,
	cout << "-------------------DATA------------------------" << endl;
	//  头
	message = "from:" + user + "\r\nto:" + target + "\r\nsubject:" + title + "\r\n";
	message += "MIME-Version: 1.0\r\n";
	message += "Content-Type: multipart/mixed;boundary=@boundary@\r\n\r\n";
	send(sockClient, message.c_str(), message.length(), 0);

	//  正文
	message = "--@boundary@\r\nContent-Type: text/plain;charset=\"gb2312\"\r\n\r\n" + content + "\r\n\r\n";
	send(sockClient, message.c_str(), message.length(), 0);

	//------------------------------------------------------------------------------------------------
	//  发送附件

	SendAttachment(sockClient);

	/*发送结尾信息*/
	message = "--@boundary@--\r\n.\r\n";
	send(sockClient, message.c_str(), message.length(), 0);
	buff[recv(sockClient, buff, 500, 0)] = '\0';
	cout<<"end_qwertyuiop:"<<buff<<endl;

	message = "QUIT\r\n";
	send(sockClient, message.c_str(), message.length(), 0);
	buff[recv(sockClient, buff, 500, 0)] = '\0';
	cout << "Send mail is finish:" << buff << endl;
	return 0;
}


容易理解的简化版可以点击->这里

  • 5
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值