C+WinSock+SMTP

来源:互联网 发布:igv软件下载 编辑:程序博客网 时间:2024/05/16 08:52


 

前言:

 

在网上找了很长时间如何发电子邮件的教程,发现大多数都是不能用的

很黑心,要不就是有问题的,

烦人,,,所以决定自己写一个C+WinSock+SMTP,

不敢藏私,拿出来与大家分享

 

先对协议和端口进行一下说明

 

25端口:25端口为SMTP(Simple MailTransfer Protocol,简单邮件传输协议)服务器所开放,主要用于发送邮件,如今绝大多数邮件服务器都使用该协议。

      

109、110端口:109端口是为POP2(Post Office Protocol Version 2,邮局协议2)服务开放的,110端口是为POP3(邮局协议3)服务开放的,POP2、POP3都是主要用于接收邮件的。

 

 

实现原理:

 

假设由发件人zhaorunze123@126.com发到332447549@qq.com邮箱,

发送过程如下:

 

1.连接smtp服务器, smtp.126.com

主机返回:

220 126.com Anti-spam GT for CoremailSystem (126com[20101010])

 

32 32 30 20 31 32 36 2E 63 6F 6D 20 41 6E74 69

2D 73 70 61 6D 20 47 54 20 66 6F 72 20 436F 72

65 6D 61 69 6C 20 53 79 73 74 65 6D 20 2831 32

36 63 6F 6D 5B 32 30 31 30 31 30 31 30 5D29 0D

0A

 

 

2.查询支持什么指令(注意:有的教程上写的是HELO 其实是不对的。。。。。。)

发送命令:EHLOzhaorunze123@126.com\r\n (发送的命令要以"\r\n"作为结束标识符)

返回数据:

250-mail

250-PIPELINING

250-AUTH LOGIN PLAIN

250-AUTH=LOGIN PLAIN

250-coremail1Uxr2xKj7kG0xkI17xGrU7I0s8FY2U3Uj8Cz28x1UUUUU7Ic2I0Y2UroXVjYUCa0xDr

UUUUj

250-STARTTLS

250 8BITMIME

 

32 35 30 2D 6D 61 69 6C 0D 0A 32 35 30 2D50 49

50 45 4C 49 4E 49 4E 47 0D 0A 32 35 30 2D41 55

54 48 20 4C 4F 47 49 4E 20 50 4C 41 49 4E0D 0A

32 35 30 2D 41 55 54 48 3D 4C 4F 47 49 4E20 50

4C 41 49 4E 0D 0A 32 35 30 2D 63 6F 72 656D 61

69 6C 20 31 55 78 72 32 78 4B 6A 37 6B 4730 78

6B 49 31 37 78 47 72 55 37 49 30 73 38 4659 32

55 33 55 6A 38 43 7A 32 38 78 31 55 55 5555 55

37 49 63 32 49 30 59 32 55 72 6F 58 56 6A59 55

43 61 30 78 44 72 55 55 55 55 6A 0D 0A 3235 30

2D 53 54 41 52 54 54 4C 53 0D 0A 32 35 3020 38

42 49 54 4D 49 4D 45 0D 0A

 

3.用户登录

发送命令:AUTHLOGIN\r\n

返回数据:334dXNlcm5hbWU6 (这是username的base64编码)

33 33 34 20 64 58 4E 6C 63 6D 35 68 62 5755 36

0D 0A

 

发送帐号:emhhb3J1bnplMTIz(这是zhaorunze123的base64编码)

返回数据:334UGFzc3dvcmQ6 (这是password的base64编码)

33 33 34 20 55 47 46 7A 63 33 64 76 63 6D51 36

0D 0A

 

 

发送密码:XXXXXXXXX(这里是zhaorunze123这个帐号的密码的base64编码)

返回数据:235Authentication successful (登录成功)

32 33 35 20 41 75 74 68 65 6E 74 69 63 6174 69

6F 6E 20 73 75 63 63 65 73 73 66 75 6C 0D0A

 

 

4:发送邮箱说明

发送命令:MAILFROM: <zhaorunze123@126.com>\r\n

返回数据:250 MailOK

32 35 30 20 4D 61 69 6C 20 4F 4B 0D 0A

 

5.目的邮箱说明

发送命令:RCPT TO:<332447549@qq.com>\r\n

返回数据:250 MailOK

32 35 30 20 4D 61 69 6C 20 4F 4B 0D 0A

 

6.请求发送邮件

发送命令:DATA\r\n

返回命令:354 Enddata with <CR><LF>.<CR><LF>

33 35 34 20 45 6E 64 20 64 61 74 61 20 7769 74

68 20 3C 43 52 3E 3C 4C 46 3E 2E 3C 43 523E 3C

4C 46 3E 0D 0A

 

7.发送邮件头和邮件体

发送数据:(数据以“<CR><LF>.<CR><LF>”结束)

 

From: zhaorunze123@126.com

To: 332447549@qq.com

Subject: 我是标题

MIME-Version: 1.0

 

Have A Test!!! \r\n.\r\n

 

 

返回数据:250 MailOK queued as smtp4,jdKowLC7f6SfgapNAfJMBw--.4939S2 1303019935

32 35 30 20 4D 61 69 6C 20 4F 4B 20 71 7565 75

65 64 20 61 73 20 73 6D 74 70 34 2C 6A 644B 6F

77 4C 43 37 66 36 53 66 67 61 70 4E 41 664A 4D

42 77 2D 2D 2E 34 39 33 39 53 32 20 31 3330 33

30 31 39 39 33 35 0D 0A

 

8.结束发送数据

发送命令:QUIT\r\n

接收数据:221 Bye

32 32 31 20 42 79 65 0D 0A

 

9.断开连接

 

代码部分:

/////////////////////////////////////////////////////////////////////

// stdafx.h : 标准系统包含文件的包含文件,

// 或是经常使用但不常更改的

// 特定于项目的包含文件

//

 

#pragma once

 

#include "targetver.h"

 

#include <stdio.h>

#include <tchar.h>

#include<WinSock2.h>

#include<Windows.h>

 

#pragma comment (lib,"Ws2_32.lib")

 

 

SOCKET CreateConnection(char* pWebsite,int iPort);  //创建连接

 

//int DoWhat=0,先发送后接收,1,只发送,2只接收

bool SendAndRecvMsg(SOCKET sockClient,char* lpMessage,intMessagelen,int DoWhat,char* recvBuf,int recvBufLen);//发送消息接收消息

 

void CloseSock(SOCKET sockClient);

 

void InitializeWSA();

 

char* WebsiteToIPAddress(char* pWebsite);//网址转IP

 

char* StringToBase64(char* bString,int len); //asc2字符串转base64

 

bool FormatEmail(char* pFrom,char* pTo,char* pSubject,char*pMessage,__out char* Email);//格式化Email

 

void WINAPI SendEmail(                  //发送邮件

    char*pUserNameToSendEmail,         //发件箱

    char*pPassWordToSendEmail,         //发件箱的密码

    char* SMTPService,              //发件箱的SMTP服务器

    char* pTargetEmail,             //目标邮箱

    char* pEmailTitle,              //邮件的标题

    char* pContent                  //邮件的内容

    );

 

int GetAsc2Len(char* pString);

 

// TODO: 在此处引用程序需要的其他头文件

////////////////////////////////////////////////////////////////////

 

 

 

 

/////////////////////////////////////////////////////////////////////

//stdafx.cpp : 只包括标准包含文件的源文件

// 发送邮件的测试.pch 将作为预编译头

//stdafx.obj 将包含预编译类型信息

 

#include"stdafx.h"

 

//TODO: 在STDAFX.H 中

// 引用任何所需的附加头文件,而不是在此文件中引用

voidInitializeWSA()

{

    WSAData wsadata;

    WSAStartup(MAKEWORD(2,2),&wsadata);

}

 

char*WebsiteToIPAddress(char* pWebsite)

{

    hostent* ht=gethostbyname( pWebsite);

    char*IpAddress=(char*)HeapAlloc(GetProcessHeap(),0,32);

    memset(IpAddress,0,32);

    sprintf(IpAddress,"%d.%d.%d.%d",*(byte*)(ht->h_addr_list[0]),*(byte*)(ht->h_addr_list[0]+1),*(byte*)(ht->h_addr_list[0]+2),*(byte*)(ht->h_addr_list[0]+3));

    return IpAddress;

}

 

 

SOCKETCreateConnection(char* pWebsite,int iPort)

{

       //为建立socket对象做准备,初始化环境

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

       SOCKADDR_INaddrSrv;  

    char* IpAddress=WebsiteToIPAddress(pWebsite);

    //printf("%s\n",IpAddress);

    addrSrv.sin_addr.S_un.S_addr=inet_addr(IpAddress);//把U_LONG的主机字节顺序转换为TCP/IP网络字节顺序  

    addrSrv.sin_family=AF_INET;  

    addrSrv.sin_port=htons(iPort);  

    int tf =connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));   //向服务器发送请求 

    if(tf!=0)

    {

       return 0;

       //printf("链接失败\n");

    }

    return sockClient;

}

 

 

boolSendAndRecvMsg(SOCKET sockClient,char* pMessage,int Messagelen,int DoWhat,char*recvBuf,int recvBufLen)//int DoWhat是否接受数据

{

    char lpMessage[256]={0};

    memcpy(lpMessage,pMessage,Messagelen);

    printf("\n\n%s \n",lpMessage);

       if(DoWhat==0)

     {

       send(sockClient,lpMessage,Messagelen,0);

       memset(recvBuf,0,recvBufLen);

       DWORDnum=recv(sockClient,recvBuf,recvBufLen,0);    //接收数据

       printf("%s \n",recvBuf);

       int i=0;

       while(i!=num)

       {

            printf("%02X ",recvBuf[i++]);

            if((i)%16==0)

            {

                 printf("\n");

            }

       }

       printf("\n");

 

     }elseif (DoWhat==1)

     {

       send(sockClient,lpMessage,Messagelen,0);

 

     }elseif (DoWhat==2)

     {

       memset(recvBuf,0,recvBufLen);

       DWORDnum=recv(sockClient,recvBuf,recvBufLen,0);    //接收数据

       printf("%s \n",recvBuf);

       int i=0;

       while(i<num)

       {

            printf("%02X ",(byte)recvBuf[i++]);

            if((i)%16==0)

            {

               printf("\n");

            }

       }

       printf("\n");

     }

    

     return recvBuf;

}

 

voidCloseSock(SOCKET sockClient)

{

     //关闭套接字  

     closesocket(sockClient);  

     WSACleanup(); 

}

 

char*StringToBase64(char* bString,int len)//len是bString的长度,不算结束符\0

{

    int Index=0;

    byte data[3]={0};

    char*Base64=(char*)HeapAlloc(GetProcessHeap(),0,(len*4)/3+12);

    memset(Base64,0,(len*4)/3+12);

    char* tmp=(char*)HeapAlloc(GetProcessHeap(),0,5);

 

    while((Index+3)<=len)

    {

       memset(data,0,3);

       memcpy(data,bString+Index,3);

       memset(tmp,0,5);

       tmp[0]=(data[0]>>2)&0x3F;

       tmp[1]=((data[0]<<4)+(data[1]>>4))&0x3F;

       tmp[2]=((data[1]<<2)+(data[2]>>6))&0x3F;

       tmp[3]=data[2]&0x3F;

       lstrcat(Base64,tmp);

       Index+=3;

    }

    memset(tmp,0,5);

    Index=len%3;

    if(Index!=0)

    {

       memset(data,0,3);

       memcpy(data,bString+len-Index,Index);

       memset(tmp,0,5);

       tmp[0]=(data[0]>>2)&0x3F;

       tmp[1]=((data[0]<<4)+(data[1]>>4))&0x3F;

       tmp[2]=((data[1]<<2)+(data[2]>>6))&0x3F;

       tmp[3]=data[2]&0x3F;

       lstrcat(Base64,tmp);

 

       memset(tmp,0,5);

 

       Index=3-Index;

       while(Index--)

       {

           lstrcat(tmp,"=");

       }

    }

 

    Index=0;

    while(Base64[Index]!=0)

    {

//     //printf("%02d=",Base64[Index]);

       if(Base64[Index]<=25 &&Base64[Index]>=0)

       {

           Base64[Index]+='A';

 

       }else if(Base64[Index]<=51 &&Base64[Index]>=26)

       {

           Base64[Index]-=26;

           Base64[Index]+='a';

 

       }else if(Base64[Index]<=61 &&Base64[Index]>=52)

       {

           Base64[Index]-=4;

 

       }else if(Base64[Index]==62)

       {

           Base64[Index]='+';

 

       }else if(Base64[Index]==63)

       {

           Base64[Index]='/';

 

       }else

       {

//         MessageBox(0,"转换成Base64出错",&Base64[Index],0);

           //printf("%02d\n",Base64[Index]);

       }

//     //printf("%c\n",Base64[Index]);

 

       Index++;

    }

    lstrcat(Base64,tmp);

 

    HeapFree(GetProcessHeap(),0,tmp);

    return Base64;

}

 

boolFormatEmail(char* pFrom,char* pTo,char* pSubject,char* pMessage,__out char*Email)

{

    lstrcat(Email,"From: ");

    lstrcat(Email,pFrom);

    lstrcat(Email,"\r\n");

 

    lstrcat(Email,"To: ");

    lstrcat(Email,pTo);

    lstrcat(Email,"\r\n");

 

    lstrcat(Email,"Subject: ");

    lstrcat(Email,pSubject);

    lstrcat(Email,"\r\n");

 

    lstrcat(Email,"MIME-Version:1.0");

    lstrcat(Email,"\r\n");

    lstrcat(Email,"\r\n");

 

    lstrcat(Email,pMessage);

 

    lstrcat(Email,"\r\n.\r\n");

    return 1;

}

 

voidWINAPI SendEmail(

    char* pUserNameToSendEmail,        //发件箱

    char* pPassWordToSendEmail,        //发件箱的密码

    char* SMTPService,              //发件箱的SMTP服务器

    char* pTargetEmail,             //目标邮箱

    char* pEmailTitle,              //邮件的标题

    char* pContent                  //邮件的内容

    )

{

    char* base;

    char str[1024];

   

    InitializeWSA();

    ;

    SOCKETsockClient=CreateConnection(SMTPService,25);

    char recvBuf[1024];

    memset(recvBuf,0,1024);

 

    bool tf =SendAndRecvMsg(sockClient,0,0,2,recvBuf,1024);

    char UserNameToSendEmail[256]={0};

    sprintf(UserNameToSendEmail,"EHLO%s",pUserNameToSendEmail);

    lstrcat(UserNameToSendEmail,"\r\n\0");

    tf =SendAndRecvMsg(sockClient,UserNameToSendEmail,GetAsc2Len(UserNameToSendEmail),0,recvBuf,1024);

   

    tf = SendAndRecvMsg(sockClient,"AUTHLOGIN\r\n",strlen("AUTH LOGIN\r\n"),0,recvBuf,1024);

 

    char pUerName[256]={0};

    DWORDp=strstr(pUserNameToSendEmail,"@")-pUserNameToSendEmail;

    memcpy(pUerName,pUserNameToSendEmail,p);

   

    base=StringToBase64(pUerName,lstrlen(pUerName));

    memset(str,0,1024);

    sprintf(str,"%s\r\n",base);

    tf =SendAndRecvMsg(sockClient,str,lstrlen(str),0,recvBuf,1024);

 

    base=StringToBase64(pPassWordToSendEmail,lstrlen(pPassWordToSendEmail));

    memset(str,0,1024);

    sprintf(str,"%s\r\n",base);

    tf =SendAndRecvMsg(sockClient,str,lstrlen(str),0,recvBuf,1024);

 

    char MailFrom[256]={0};

    sprintf(MailFrom,"MAIL FROM:<%s>\r\n",pUserNameToSendEmail);

 

    tf =SendAndRecvMsg(sockClient,MailFrom,lstrlen(MailFrom),0,recvBuf,1024);

   

    char RcptTo[256]={0};

    sprintf(RcptTo,"RCPT TO:<%s>\r\n",pTargetEmail);

    tf =SendAndRecvMsg(sockClient,RcptTo,lstrlen(RcptTo),0,recvBuf,1024);

   

    tf =SendAndRecvMsg(sockClient,"DATA\r\n",lstrlen("DATA\r\n"),0,recvBuf,1024);

   

 

    char Email[1024]={0};

    FormatEmail(pUserNameToSendEmail,pTargetEmail,pEmailTitle,pContent,Email);

 

    tf =SendAndRecvMsg(sockClient,Email,lstrlen(Email),0,recvBuf,1024);

   

    tf =SendAndRecvMsg(sockClient,"QUIT\r\n",lstrlen("QUIT\r\n"),0,recvBuf,1024);

   

    CloseSock(sockClient);

 

    return ;

}

 

intGetAsc2Len(char* pString)

{

    int i=0;

    while(pString[i++]!=0);

    return i-1;

}

////////////////////////////////////////////////////////////////////

 

 

 

////////////////////////////////////////////////////////////////////

// 发送邮件的测试.cpp : 定义控制台应用程序的入口点。

//

 

#include "stdafx.h"

 

 

int _tmain(int argc, _TCHAR* argv[])

{

   SendEmail(

    "zhaorunze123@126.com",         //发件箱

    "XXXXXXXX",              //发件箱的密码

    "SMTP.126.com",             //发件箱的SMTP服务器

    "332447549@qq.com",         //目标邮箱

    "我是标题",              //邮件的标题

    "Have ATest!!!"         //邮件的内容

    );

 

  system("pause");

    return 0;

}

 

原创粉丝点击