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

2024-06-02 22:38

本文主要是介绍邮件正文及其附件的发送的C++实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转载一篇邮件发送的实现,转载自http://blog.csdn.net/lishuhuakai/article/details/27852009

亲自测试,可以使用,稍加修改添加群发功能,直接上代码

stmp.h

#ifndef __SMTP_H__ //避免重复包含  
#define __SMTP_H__  #include <iostream>  
#include <list>  
#include <vector>
#include <WinSock2.h>  
using namespace std;  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       //内容  );  ~CSmtp(void);  private:  int port; //邮件发送服务器端口string domain;  //邮件发送服务器地址string user;  //发送邮箱emailstring pass;  //发送邮箱密码string targetAddr;  //接收邮箱string title;  //邮件标题string content; //邮件正文 /*为了方便添加文件,删除文件神马的,使用list容器最为方便,相信大家在数据结构里面都学过*/  list <FILEINFO *> listFile;  char buff[MAXLEN + 1];  int buffLen;  SOCKET sockClient;  //客户端的套接字  vector <string> m_vectorTargetEamil;//接收邮箱列表private:  bool CreateConn(); /*创建连接*/  bool Send(string &message);  bool Recv();  void FormatEmailHead(string &email);//格式化要发送的邮件头部  int Login();  bool SendEmailHead();       //发送邮件头部信息  bool SendTextBody();        //发送文本信息  //bool SendAttachment();        //发送附件  int SendAttachment_Ex();  bool SendEnd();  public:  void AddAttachment(string &filePath); //添加附件  void DeleteAttachment(string &filePath); //删除附件  void DeleteAllAttachment(); //删除所有的附件  void SetSrvDomain(string &domain);  void SetUserName(string &user);  void SetPass(string &pass);  void SetTargetEmail(string &targetAddr);  void SetEmailTitle(string &title);  void SetContent(string &content);  void SetPort(int port);  int SendEmail_Ex();  /*关于错误码的说明:1.网络错误导致的错误2.用户名错误3.密码错误4.文件不存在0.成功*/  char* base64Encode(char const* origSigned, unsigned origLength);  void AddTargetEmail(string &strTargetEmail);//添加目地邮箱地址int SendVecotrEmail();//发送多封邮件到多个地址
};  #endif // !__SMTP_H__  


stmp.cpp

#include "stdafx.h"
#include "Smtp.h"  
#include <iostream>  
#include <fstream>  
using namespace std;  #pragma  comment(lib, "ws2_32.lib") /*链接ws2_32.lib动态链接库*/  /*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 = 25;  this->user = "";  this->pass = "";  this->targetAddr = "";  this->title = "";  this->domain = "";  WORD wVersionRequested;  WSADATA wsaData;  int err;  wVersionRequested = MAKEWORD(2, 1);  err = WSAStartup(wVersionRequested, &wsaData);  this->sockClient = 0;  }  CSmtp::~CSmtp(void)  
{  DeleteAllAttachment();  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 = 0;  
</pre><pre name="code" class="cpp"><span style="white-space:pre">	</span>m_vectorTargetEamil.push_back(targetEmail);
}  bool 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 false;  //printf("链接失败\n");  }  this->sockClient = sockClient;  if (false == Recv())  {  return false;  }  return true;  
}  bool CSmtp::Send(string &message)  
{  int err = send(sockClient, message.c_str(), message.length(), 0);  if (err == SOCKET_ERROR)  {  return false;  }  string message01;  cout << message.c_str() << 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()  
{  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: <";sendBuff += user;sendBuff += ">\r\n";  if (false == Send(sendBuff) || false == Recv())  {  return false; /*表示发送失败由于网络错误*/  }  sendBuff.empty();  sendBuff = "RCPT TO: <";sendBuff += targetAddr;sendBuff += ">\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);  
}  int 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 += (*pIter)->fileName;  sendBuff += "\"";  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);  if (false == ifs.is_open())  {  return 4; /*错误码4表示文件打开错误*/  }  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 1;  }  delete[]chSendBuff;  }  return 0;  
}  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;  }  //Recv();  int err = Login(); //先登录  if (err != 0)  {  return err; //错误代码必须要返回  }  if (false == SendEmailHead()) //发送EMAIL头部信息  {  return 1; /*错误码1是由于网络的错误*/  }  if (false == SendTextBody())  {  return 1; /*错误码1是由于网络的错误*/  }  err = SendAttachment_Ex();  if (err != 0)  {  return err;  }  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)  {  FILEINFO *p = *pIter;  listFile.remove(*pIter);  delete p;  break;  }  }  
}  void CSmtp::DeleteAllAttachment() /*删除所有的文件*/  
{  for (list<FILEINFO *>::iterator pIter = listFile.begin(); pIter != listFile.end();)  {  FILEINFO *p = *pIter;  pIter = listFile.erase(pIter);  delete p;  }  
}  void CSmtp::SetSrvDomain(string &domain)  
{  this->domain = domain;  
}  void CSmtp::SetUserName(string &user)  
{  this->user = user;  
}  void CSmtp::SetPass(string &pass)  
{  this->pass = pass;  
}  
void CSmtp::SetTargetEmail(string &targetAddr)  
{  this->targetAddr = targetAddr;  
}  
void CSmtp::SetEmailTitle(string &title)  
{  this->title = title;  
}  
void CSmtp::SetContent(string &content)  
{  this->content = content;  
}  
void CSmtp::SetPort(int port)  
{  this->port = port;  
}  //发送多封邮件到多个地址
int CSmtp::SendVecotrEmail()
{if (m_vectorTargetEamil.empty()){return -1;//没有目地邮箱地址}int nRet = 0;vector <string>::iterator it;for (it=m_vectorTargetEamil.begin(); it!=m_vectorTargetEamil.end(); it++){targetAddr = *it;SendEmail_Ex();}return nRet;
}//添加目地邮箱地址
void CSmtp::AddTargetEmail(string &strTargetEmail)
{vector <string>::iterator it;for (it=m_vectorTargetEamil.begin(); it!=m_vectorTargetEamil.end(); it++){if (!it->compare(strTargetEmail)){break;}}if (it == m_vectorTargetEamil.end()){m_vectorTargetEamil.push_back(strTargetEmail);}
}

测试

#include "stdafx.h"#include "Smtp.h"  int _tmain(int argc, _TCHAR* argv[])
{CSmtp smtp(  <span style="white-space:pre">	</span>25,                             /*smtp端口*/  "smtp.163.com",                 /*smtp服务器地址*/  "12345678@163.com",    <span style="white-space:pre">		</span>/*你的邮箱地址*/ "12345678",                 <span style="white-space:pre">	</span>/*邮箱密码*/  "987654321@163.com",   <span style="white-space:pre">		</span>/*目的邮箱地址*/  <span style="white-space:pre">	</span>"TEST",                         /*主题*/  <span style="white-space:pre">	</span>"测试测试!收到请回复!"        /*邮件正文*/  <span style="white-space:pre">	</span>);  //添加附件时注意,\一定要写成\\,因为转义字符的缘故 
//     string filePath("D:\\附件.txt"); 
//     smtp.AddAttachment(filePath); /*还可以调用CSmtp::DeleteAttachment函数删除附件,还有一些函数,自己看头文件吧!*/  //单个发送<span style="white-space:pre">	</span>int err;  <span style="white-space:pre">	</span>if ((err = smtp.SendEmail_Ex()) != 0)  <span style="white-space:pre">	</span>{  <span style="white-space:pre">	</span> <span style="white-space:pre">	</span>if (err == 1)  <span style="white-space:pre">		</span>cout << "错误1: 由于网络不畅通,发送失败!" << endl;  <span style="white-space:pre">	</span>if (err == 2)  <span style="white-space:pre">		</span>cout << "错误2: 用户名错误,请核对!" << endl;  <span style="white-space:pre">	</span>if (err == 3)  <span style="white-space:pre">		</span>cout << "错误3: 用户密码错误,请核对!" << endl;  <span style="white-space:pre">	</span>if (err == 4)  <span style="white-space:pre">		</span>cout << "错误4: 请检查附件目录是否正确,以及文件是否存在!" << endl;  <span style="white-space:pre">	</span>}//群发string strTarEmail = "12345678@qq.com";smtp.AddTargetEmail(strTarEmail);int err;  if ((err = smtp.SendVecotrEmail()) != 0)  {  if (err == -1)  cout << "错误-1: 没有目地邮箱地址!" << endl;  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;
}


这篇关于邮件正文及其附件的发送的C++实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1025294

相关文章

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount