C++ 发送邮件(C++源码)


  本文代码完成于2013年,经久失修。不能保证协议的完整性。内容仅供参考!!!



-----------------------分割于2016年10月19日11:20:14------------------------------------




效果



这里是类的代码 CSendMail .h


*************************************************************************/  
#pragma once  
struct sMailInfo //邮件信息  
{  
    char*   m_pcUserName;//用户登录邮箱的名称  
    char*   m_pcUserPassWord;//用户登录邮箱的密码  
    char*   m_pcSenderName;//用户发送时显示的名称  
    char*   m_pcSender;//发送者的邮箱地址  
    char*   m_pcReceiver;//接收者的邮箱地址  
    char*   m_pcTitle;//邮箱标题  
    char*   m_pcBody;//邮件文本正文  
    char*   m_pcIPAddr;//服务器的IP  
    char*   m_pcIPName;//服务器的名称(IP与名称二选一,优先取名称)  
    sMailInfo(){memset(this,0,sizeof(sMailInfo));}  
};  
class CSendMail  
{  
public:  
    CSendMail(void);  
    ~CSendMail(void);  
  
public:  
    bool SendMail(sMailInfo &smailInfo);//发送邮件,需要在发送的时候初始化邮件信息  
    void AddFilePath(char * pcFilePath);//添加附件的决定路径到附件列表中  
    void DeleteFilePath(char* pcFilePath);//删除附件路径,如果有的话  
    void DeleteAllPath(void);//删除全部附件的路径  
  
protected:  
    void GetFileName(char* fileName,char* filePath);//从附件的路径中获取文件名称  
    void Char2Base64(char* pBuff64,char* pSrcBuff,int iLen);//把char类型转换成Base64类型  
    bool  CReateSocket(SOCKET &sock);//建立socket连接  
    bool Logon(SOCKET &sock);//登录邮箱,主要进行发邮件前的准备工作  
    int GetFileData(char* FilePath);//由文件路径获取附件内容  
  
    bool SendHead(SOCKET &sock);//发送邮件头  
    bool SendTextBody(SOCKET &sock);//发送邮件文本正文  
    bool SendFileBody(SOCKET &sock);//发送邮件附件  
    bool SendEnd(SOCKET &sock);//发送邮件结尾  
protected:  
    CList<char*,char*> m_pcFilePathList;//记录附件路径  
  
    char  m_cSendBuff[4096];//发送缓冲区  
    char  m_cReceiveBuff[1024];  
    char* m_pcFileBuff;//指向附件内容  
    sMailInfo m_sMailInfo;  
};  


CSendMail.cpp

/************************************************************************ 
* 发送邮件模块 
*可以发送文本和附件(支持多个附件一起发送) 
*Date:2011-12-01 
************************************************************************/  
#include "StdAfx.h"  
#include "CSendMail.h"  
#include "winsock2.h"  
#pragma comment(lib,"WSOCK32")  
#pragma comment(lib, "ws2_32")

CSendMail::CSendMail(void)  
{  
    m_pcFileBuff=NULL;  
    memset(m_cSendBuff,0,sizeof(m_cSendBuff));  
    memset(m_cReceiveBuff,0,sizeof(m_cReceiveBuff));  
}  
  
  
CSendMail::~CSendMail(void)  
{  
    DeleteAllPath();  
}  
  
  
void CSendMail::Char2Base64(char* pBuff64,char* pSrcBuff,int iLen)  
{  
    //1   1   1   1   1   1   1   1  
    // 分配给pBuff64  ↑ 分配给pBuff64+1  
    //         point所在的位置  
    static char Base64Encode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";//base64所映射的字符表  
    int point;//每一个源字符拆分的位置,可取2,4,6;初始为2  
    point=2;  
    int i;  
    int iIndex;//base64字符的索引  
    char n=0;//上一个源字符的残留值  
    for(i=0;i<iLen;i++)  
    {  
        if(point==2)  
        {  
            iIndex=((*pSrcBuff)>>point)&0x3f;//取得pSrcBuff的高point位  
        }  
        else if (point==4)  
        {  
            iIndex=((*pSrcBuff)>>point)&0xf;//取得pSrcBuff的高point位  
        }  
        else if(point==6)  
        {  
            iIndex=((*pSrcBuff)>>point)&0x3;//取得pSrcBuff的高point位  
        }  
        iIndex+=n;//与pSrcBuff-1的低point结合组成Base64的索引  
        *pBuff64++=Base64Encode[iIndex];//由索引表得到pBuff64  
        n=((*pSrcBuff)<<(6-point));//计算源字符中的残留值  
        n=n&0x3f;//确保n的最高两位为0  
        point+=2;//源字符的拆分位置上升2  
        if(point==8)//如果拆分位置为8说明pSrcBuff有6位残留,可以组成一个完整的Base64字符,所以直接再组合一次  
        {  
            iIndex=(*pSrcBuff)&0x3f;//提取低6位,这就是索引了  
            *pBuff64++=Base64Encode[iIndex];//  
            n=0;//残留值为0  
            point=2;//拆分位置设为2  
        }  
        pSrcBuff++;  
  
    }  
    if(n!=0)  
    {  
        *pBuff64++=Base64Encode[n];  
    }  
    if(iLen%3==2)//如果源字符串长度不是3的倍数要用'='补全  
    {  
        *pBuff64='=';  
    }  
    else if(iLen%3==1)  
    {  
        *pBuff64++='=';  
        *pBuff64='=';  
    }  
}  
  
void CSendMail::AddFilePath(char * pcFilePath)//添加附件路径  
{  
    if(pcFilePath==NULL)  
    {  
        return;  
    }  
    int i;  
    char* temp;  
    for(i=0;i<m_pcFilePathList.GetCount();i++)  
    {  
        temp=m_pcFilePathList.GetAt(m_pcFilePathList.FindIndex(i));  
        if(strcmp(pcFilePath,temp)==0)//如果已经存在就不用再添加了  
        {  
            return;  
        }  
    }  
    m_pcFilePathList.AddTail(pcFilePath);  
}  
  
void CSendMail::DeleteFilePath(char* pcFilePath)//删除附件路径  
{  
    int i;  
    char* temp;  
    for(i=0;i<m_pcFilePathList.GetCount();i++)  
    {  
        temp=m_pcFilePathList.GetAt(m_pcFilePathList.FindIndex(i));  
        if(strcmp(temp,pcFilePath)==0)//找到并删除它,如果没找到就算了  
        {  
            m_pcFilePathList.RemoveAt(m_pcFilePathList.FindIndex(i));  
            delete[] temp;  
            return;  
        }  
    }  
}  
  
  
void CSendMail::DeleteAllPath(void)  
{  
    m_pcFilePathList.RemoveAll();  
}  
  
int CSendMail::GetFileData(char* FilePath)  
{  
    m_pcFileBuff=NULL;  
    if(FilePath==NULL)  
    {  
        return 0;  
    }  
    CFile f;  
    int len;  
      
      
    USES_CONVERSION;  
    if(!f.Open(A2W(FilePath),CFile::modeRead|CFile::modeNoTruncate|CFile::typeBinary))  
    {  
        return 0;  
    }  
    len=(int)f.GetLength();  
    m_pcFileBuff=new char[len+1];  
    memset(m_pcFileBuff,0,len+1);  
    f.Read(m_pcFileBuff,len);  
  
    f.Close();  
    return len;  
}  
  
void CSendMail::GetFileName(char* fileName,char* filePath)  
{  
    if(filePath==NULL || fileName==NULL)  
    {  
        return;  
    }  
    int i;  
    for(i=0;i<(int)strlen(filePath);i++)  
    {  
        if(filePath[strlen(filePath)-1-i]=='\\')  
        {  
            memcpy(fileName,&filePath[strlen(filePath)-i],i);  
            return;  
        }  
    }  
}  
  
bool CSendMail::CReateSocket(SOCKET &sock)  
{  
    WORD wVersionRequested;  
    WSADATA wsaData;  
    int err;  
    wVersionRequested = MAKEWORD( 2, 2 );  
    err = WSAStartup( wVersionRequested, &wsaData );  
    if ( err != 0 )   
    {  
        return false;  
    }  
    if ( LOBYTE( wsaData.wVersion ) != 2 ||  
        HIBYTE( wsaData.wVersion ) != 2 )  
    {  
        WSACleanup( );  
        return false;   
    }  
    sock = socket(AF_INET,SOCK_STREAM,IPPROTO_IP);  
    if (sock == INVALID_SOCKET)  
    {  
        return false;  
    }  
  
    sockaddr_in servaddr;  
    memset(&servaddr,0,sizeof(sockaddr_in));  
    servaddr.sin_family = AF_INET;  
    servaddr.sin_port = htons(25);//发邮件一般都是25端口  
    if(m_sMailInfo.m_pcIPName=="")  
    {  
        servaddr.sin_addr.s_addr = inet_addr(m_sMailInfo.m_pcIPAddr);//直接使用IP地址  
    }  
    else  
    {  
        struct hostent *hp=gethostbyname(m_sMailInfo.m_pcIPName);//使用名称  
		if (hp == NULL)
		{
			DWORD dwErrCode =	GetLastError();
			return false;
		}
        servaddr.sin_addr.s_addr=*(int*)(*hp->h_addr_list);  
    }  
  
  
    int ret = connect(sock,(sockaddr*)&servaddr,sizeof(servaddr));//建立连接  
    if (ret == SOCKET_ERROR)  
    {  
		DWORD dwErr = GetLastError();
        return false;  
    }  
  
    return true;  
}  
  
  
bool CSendMail::Logon(SOCKET &sock)  
{  
    recv(sock,m_cReceiveBuff,1024,0);  
  
    memset(m_cSendBuff,0,sizeof(m_cSendBuff));  
    sprintf_s(m_cSendBuff,"HELO []\r\n");  
    send(sock,m_cSendBuff,strlen(m_cSendBuff),0);//开始会话  
    recv(sock,m_cReceiveBuff,1024,0);  
    if(m_cReceiveBuff[0]!='2' || m_cReceiveBuff[1]!='5' || m_cReceiveBuff[2]!='0')  
    {  
        return false;  
    }  
  
    memset(m_cSendBuff,0,sizeof(m_cSendBuff));  
    sprintf_s(m_cSendBuff,"AUTH LOGIN\r\n");  
    send(sock,m_cSendBuff,strlen(m_cSendBuff),0);//请求登录  
    recv(sock,m_cReceiveBuff,1024,0);  
    if(m_cReceiveBuff[0]!='3' || m_cReceiveBuff[1]!='3' || m_cReceiveBuff[2]!='4')  
    {  
        return false;  
    }  
  
    memset(m_cSendBuff,0,sizeof(m_cSendBuff));  
    Char2Base64(m_cSendBuff,m_sMailInfo.m_pcUserName,strlen(m_sMailInfo.m_pcUserName));  
    m_cSendBuff[strlen(m_cSendBuff)]='\r';  
    m_cSendBuff[strlen(m_cSendBuff)]='\n';  
    send(sock,m_cSendBuff,strlen(m_cSendBuff),0);//发送用户名  
    recv(sock,m_cReceiveBuff,1024,0);  
    if(m_cReceiveBuff[0]!='3' || m_cReceiveBuff[1]!='3' || m_cReceiveBuff[2]!='4')  
    {  
        return false;  
    }  
  
    memset(m_cSendBuff,0,sizeof(m_cSendBuff));  
    Char2Base64(m_cSendBuff,m_sMailInfo.m_pcUserPassWord,strlen(m_sMailInfo.m_pcUserPassWord));  
    m_cSendBuff[strlen(m_cSendBuff)]='\r';  
    m_cSendBuff[strlen(m_cSendBuff)]='\n';  
    send(sock,m_cSendBuff,strlen(m_cSendBuff),0);//发送用户密码  
    recv(sock,m_cReceiveBuff,1024,0);  
    if(m_cReceiveBuff[0]!='2' || m_cReceiveBuff[1]!='3' || m_cReceiveBuff[2]!='5')  
    {  
        return false;  
    }  
    return true;//登录成功  
}  
  
  
bool CSendMail::SendHead(SOCKET &sock)  
{  
    int rt;  
    memset(m_cSendBuff,0,sizeof(m_cSendBuff));  
    sprintf_s(m_cSendBuff,"MAIL FROM:<%s>\r\n",m_sMailInfo.m_pcSender);  
    rt=send(sock,m_cSendBuff,strlen(m_cSendBuff),0);  
      
    if(rt!=strlen(m_cSendBuff))  
    {  
        return false;  
    }  
    recv(sock,m_cReceiveBuff,1024,0);  
  
    memset(m_cSendBuff,0,sizeof(m_cSendBuff));  
    sprintf_s(m_cSendBuff,"RCPT TO:<%s>\r\n",m_sMailInfo.m_pcReceiver);  
    rt=send(sock,m_cSendBuff,strlen(m_cSendBuff),0);  
    if(rt!=strlen(m_cSendBuff))  
    {  
        return false;  
    }  
    recv(sock,m_cReceiveBuff,1024,0);  
  
    memset(m_cSendBuff,0,sizeof(m_cSendBuff));  
    memcpy(m_cSendBuff,"DATA\r\n",strlen("DATA\r\n"));  
    rt=send(sock,m_cSendBuff,strlen(m_cSendBuff),0);  
    if(rt!=strlen(m_cSendBuff))  
    {  
        return false;  
    }  
    recv(sock,m_cReceiveBuff,1024,0);  
  
    memset(m_cSendBuff,0,sizeof(m_cSendBuff));  
    sprintf_s(m_cSendBuff,"From:\"%s\"<%s>\r\n",m_sMailInfo.m_pcSenderName,m_sMailInfo.m_pcSender);  
    sprintf_s(&m_cSendBuff[strlen(m_cSendBuff)],150,"To:\"INVT.COM.CN\"<%s>\r\n",m_sMailInfo.m_pcReceiver);  
    sprintf_s(&m_cSendBuff[strlen(m_cSendBuff)],150,"Subject:%s\r\nMime-Version: 1.0\r\nContent-Type: multipart/mixed;   boundary=\"INVT\"\r\n\r\n",m_sMailInfo.m_pcTitle);  
    rt=send(sock,m_cSendBuff,strlen(m_cSendBuff),0);  
    if(rt!=strlen(m_cSendBuff))  
    {  
        return false;  
    }  
  
    return true;  
}  
  
bool CSendMail::SendTextBody(SOCKET &sock)  
{  
    int rt;  
    memset(m_cSendBuff,0,sizeof(m_cSendBuff));  
    sprintf_s(m_cSendBuff,"--INVT\r\nContent-Type: text/plain;\r\n  charset=\"gb2312\"\r\n\r\n%s\r\n\r\n",m_sMailInfo.m_pcBody);  
    rt=send(sock,m_cSendBuff,strlen(m_cSendBuff),0);  
    if(rt!=strlen(m_cSendBuff))  
    {  
        return false;  
    }  
    else  
    {  
        return true;  
    }  
}  
  
bool CSendMail::SendFileBody(SOCKET &sock)  
{  
    int i;  
    char* filePath;  
    int rt;  
    int len;  
    int pt=0;  
    char fileName[128];  
    for(i=0;i<m_pcFilePathList.GetCount();i++)  
    {  
        pt=0;  
        memset(fileName,0,128);  
        filePath=m_pcFilePathList.GetAt(m_pcFilePathList.FindIndex(i));  
        len=GetFileData(filePath);  
        GetFileName(fileName,filePath);  
  
        sprintf_s(m_cSendBuff,"--INVT\r\nContent-Type: application/octet-stream;\r\n  name=\"%s\"\r\nContent-Transfer-Encoding: base64\r\nContent-Disposition: attachment;\r\n  filename=\"%s\"\r\n\r\n",fileName,fileName);  
        send(sock,m_cSendBuff,strlen(m_cSendBuff),0);  
        while (pt<len)  
        {  
            memset(m_cSendBuff,0,sizeof(m_cSendBuff));  
            Char2Base64(m_cSendBuff,&m_pcFileBuff[pt],min(len-pt,3000));  
            m_cSendBuff[strlen(m_cSendBuff)]='\r';  
            m_cSendBuff[strlen(m_cSendBuff)]='\n';  
            rt=send(sock,m_cSendBuff,strlen(m_cSendBuff),0);  
            pt+=min(len-pt,3000);  
            if(rt!=strlen(m_cSendBuff))  
            {  
                return false;  
            }  
        }  
        if(len!=0)  
        {  
            delete [] m_pcFileBuff;  
        }  
    }  
  
    return true;  
}  
  
bool CSendMail::SendEnd(SOCKET &sock)  
{  
    sprintf_s(m_cSendBuff,"--INVT--\r\n.\r\n");  
    send(sock,m_cSendBuff,strlen(m_cSendBuff),0);  
  
    sprintf_s(m_cSendBuff,"QUIT\r\n");  
    send(sock,m_cSendBuff,strlen(m_cSendBuff),0);  
    closesocket(sock);  
    WSACleanup();  
    return true;  
}  
  
  
bool CSendMail::SendMail(sMailInfo &smailInfo)  
{  
    memcpy(&m_sMailInfo,&smailInfo,sizeof(smailInfo));  
    if(m_sMailInfo.m_pcBody==NULL  
        || m_sMailInfo.m_pcIPAddr==NULL  
        || m_sMailInfo.m_pcIPName==NULL  
        || m_sMailInfo.m_pcReceiver==NULL  
        || m_sMailInfo.m_pcSender==NULL  
        || m_sMailInfo.m_pcSenderName==NULL  
        || m_sMailInfo.m_pcTitle==NULL  
        || m_sMailInfo.m_pcUserName==NULL  
        || m_sMailInfo.m_pcUserPassWord==NULL)  
    {  
        return false;  
    }  
    SOCKET sock;  
    if(!CReateSocket(sock))//建立连接  
    {  
        return false;  
    }  
  
    if(!Logon(sock))//登录邮箱  
    {  
        return false;  
    }  
  
    if(!SendHead(sock))//发送邮件头  
    {  
        return false;  
    }  
  
    if(!SendTextBody(sock))//发送邮件文本部分  
    {  
        return false;  
    }  
  
    if(!SendFileBody(sock))//发送附件  
    {  
        return false;  
    }  
  
    if(!SendEnd(sock))//结束邮件,并关闭sock  
    {  
        return false;  
    }  
  
    return true;  
}  


测试代码

#include "CSendMail/CSendMail.h"
void testMail2()
{
	sMailInfo sm;
	sm.m_pcUserName = "这里是QQ号码";//"";
	sm.m_pcUserPassWord ="这里是QQ密码";// "";
	sm.m_pcSenderName = "爱说话的汤姆猫";
	sm.m_pcSender = "snifferzhu@qq.com";//发送者的邮箱地址  
	sm.m_pcReceiver = "w_izard@qq.com";//接收者的邮箱地址  
	sm.m_pcTitle = "测试垃圾邮件";//邮箱标题  
	sm.m_pcBody = "你想快速发家致富吗?你想一夜成名吗?访问 http://www.sb.com";//邮件文本正文  
	sm.m_pcIPAddr = "" ;//服务器的IP可以留空 
	sm.m_pcIPName ="smtp.qq.com" ;//服务器的名称(IP与名称二选一,优先取名称)  

	CSendMail csm;
	while(TRUE)
	{
		csm.SendMail(sm);
		Sleep(1000 * 20);
	}
	
}





代码说明:

SMailer 是网上流传最广泛的一个C++发送邮件的类。但是我在测试的时候并没有发送成功。没有找出原因在哪里。

CSendMail 是在CSDN上找到的一个发送邮件的类。经测试可用。

我写了一个测试的工程

http://download.csdn.net/detail/witch_soya/4978408



  • 3
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值