VC发E-MAIL的方法,可带附件

        在网上搜索到的代码,要么不能成功发送,要么做的很复杂,看下去的心思都没有。自己参照网上的代码,再了解了下E-MAIL的协议,自己写了段认为是比较精简的代码。

        共有5个函数,两个是ZBAse64的编、解码函数(虽然发邮件用不到解码,也一并记录下来吧),这两个基本是网上搬过来的,做了少许改动。一个读返回码的函数,一个发附件的函数。再一个就是发E-MAIL的主函数了。

首先是相关的常量声明:

//*****************************************************************************
//E-MAIL参数
//*****************************************************************************
#define SMTP_PORT                   25
#define RESPONSE_BUFFER_SIZE        1024       //读取服务器返回字符串缓冲区大小
#define MAIL_BUFFER_SIZE            11400                //发送附件时文件的缓冲区大小

#define MAIL_COPYRIGHT              "xxxx"         // 版权信息,自定
#define MAIL_BOUNDARY               "12313413"         // 边界标识,自定
#define MAIL_SENDER                 "me"         // 发送者姓名
#define MAIL_RECEIVER               "you"             // 接收者姓名
#define MAIL_SUBJECT                "nonet"         // 邮件主题

因为只是测试,所以姓名、主题等定义为固定的,要做的更实用的话可以定义个结构将这些内容都包含进去。

接着是两个表格,用于ZBase64编、解码。

//*****************************************************************************
// ZBASE64编码表
//*****************************************************************************
const char EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

//*****************************************************************************
// ZBASE64解码表
//***************************************************************************** 
const char DecodeTable[] =
{
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   62, // '+'
   0, 0, 0,
   63, // '/'
   52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // '0'-'9'
   0, 0, 0, 0, 0, 0, 0,
   0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
   13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // 'A'-'Z'
   0, 0, 0, 0, 0, 0,
   26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
   39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // 'a'-'z'
};

函数部分:

/*****************************************************************************
/ ZBase64/编码
//*****************************************************************************
CString ZBase64Encode(const char *Data,  int DataByte)
{
  CString strEncode; 
  unsigned char Tmp[3]={0};
  int LineLength=0;


  for(int i=0; i<(int)(DataByte/3);i++)
  {
    Tmp[1] = *Data++;
    Tmp[2] = *Data++;
    Tmp[3] = *Data++;
    
    strEncode+= EncodeTable[Tmp[1] >> 2];
    strEncode+= EncodeTable[((Tmp[1] << 4) | (Tmp[2] >> 4)) & 0x3F];
    strEncode+= EncodeTable[((Tmp[2] << 2) | (Tmp[3] >> 6)) & 0x3F];
    strEncode+= EncodeTable[Tmp[3] & 0x3F];
    if(LineLength+=4,LineLength==76) {strEncode+="\r\n";LineLength=0;}
  }

  int Mod=DataByte % 3;
  if(Mod==1)
  {
    Tmp[1] = *Data++;
    strEncode+= EncodeTable[(Tmp[1] & 0xFC) >> 2];
    strEncode+= EncodeTable[((Tmp[1] & 0x03) << 4)];
    strEncode+= "==";
  }
  else if(Mod==2)
  {
    Tmp[1] = *Data++;
    Tmp[2] = *Data++;
    strEncode+= EncodeTable[(Tmp[1] & 0xFC) >> 2];
    strEncode+= EncodeTable[((Tmp[1] & 0x03) << 4) | ((Tmp[2] & 0xF0) >> 4)];
    strEncode+= EncodeTable[((Tmp[2] & 0x0F) << 2)];
    strEncode+= "=";
  }
  
  return strEncode;
}


//*****************************************************************************
// ZBase64解码
//*****************************************************************************
CString ZBase64Decode(const char *Data, int DataByte, int &OutByte)
{
  CString strDecode;

  int nValue;

  int i= 0;

  
  while (i < DataByte)
  {
    if (*Data != '\r' && *Data!='\n')
    {
      nValue = DecodeTable[*Data++] << 18;
      nValue += DecodeTable[*Data++] << 12;
      strDecode+=(nValue & 0x00FF0000) >> 16;
      OutByte++;
  
      if (*Data != '=')
      {
        nValue += DecodeTable[*Data++] << 6;
        strDecode+=(nValue & 0x0000FF00) >> 8;
        OutByte++;
  
        if (*Data != '=')
        {
          nValue += DecodeTable[*Data++];
          strDecode+=nValue & 0x000000FF;
          OutByte++;
        }
      }
      i += 4;
    }
    else
    {
      Data++;
      i++;
    }
  }
  
  return strDecode;
}

//*****************************************************************************
// 读取发送数据后服务器的返回码
//*****************************************************************************
UINT GetResponseCode(CSocket *pSocket)
{
   UINT nRet = 0;
   char szBuffer[RESPONSE_BUFFER_SIZE];

   if(pSocket->Receive(szBuffer, RESPONSE_BUFFER_SIZE) != SOCKET_ERROR)
   {
      szBuffer[4] = '\0';
      sscanf(szBuffer, _T("%d"), &nRet);
   }


   return nRet;
}


//*****************************************************************************
//发送E-MAIL附件 CSocket =CSocket 指针 szFilePath=附件路径

//*****************************************************************************
void SendAttchment(CSocket *pSocket, LPCTSTR szFilePath)
{
  CString csText;
  CStdioFile file;

   if(file.Open(szFilePath, CFile::modeRead|CFile::typeBinary))
   {
      UINT nSize; 
      char *pBuffer = new char[MAIL_BUFFER_SIZE+1];

       do
       {
          memset(pBuffer, 0, MAIL_BUFFER_SIZE+1);

          nSize = file.Read(pBuffer, MAIL_BUFFER_SIZE);
          if(nSize>0)
          {
             csText = ZBase64Encode(pBuffer, nSize);
             if(nSize<MAIL_BUFFER_SIZE) csText += "\r\n\r\n";
             if(pSocket->Send((LPCTSTR)csText, csText.GetLength()) == SOCKET_ERROR) break;
         }
      }while(nSize == MAIL_BUFFER_SIZE);

      file.Close();
     delete []pBuffer;  
  }
}

//*****************************************************************************
//发送E-MAIL

//  szMailAddresss:E-MAIL地址

// szSmtpParameter:包含SMTP服务器域名、登录SMTP服务器的帐号及密码,三者之间以 TAB字符连接

//szContent:邮件内容

//szAttachment:附件路径
//*****************************************************************************
BOOL SendEmail(LPCTSTR szMailAddresss, LPCTSTR szSmtpParameter, LPCTSTR szContent, LPCTSTR szAttachment)
{
  CSocket socket;    
  CString csText, csFileName;
  CString csMailFrom, csServer, csAccount, csPassword;
  char szBuffer[MAX_PATH];
  int iLen, iPos1, iPos2;
  BOOL fgAttachExist = FALSE;
  BOOL fgSocketExist = FALSE;
  BOOL fgSucceed = FALSE;

  csMailFrom=csServer=csAccount=csPassword="";

  //判断有没有附件并做标记
  if(szAttachment != NULL)
  {
     fgAttachExist = TRUE;
     csFileName = szAttachment;
    iLen = csFileName.GetLength();  iPos1 = csFileName.ReverseFind('\\'); 
    if(iPos1 != -1)  csFileName = csFileName.Right(iLen-iPos1-1);
  }
  
  //分离出SMTP主机、帐号、密码
  csText = szSmtpParameter;
  iLen = csText.GetLength(); iPos1 = csText.Find("\t");  iPos2 = csText.ReverseFind('\t');
  if(iPos1 != -1)
  {
    csServer = csText.Left(iPos1);
    if(iPos2 != -1)
     {
        csAccount = csText.Mid(iPos1+1, iPos2-iPos1-1);
       csPassword = csText.Right(iLen-iPos2-1);
     }
     iLen = csServer.GetLength(); iPos1 = csServer.Find(".");
     if(iPos1 != -1) csMailFrom.Format("%s@%s", csAccount, csServer.Right(iLen-iPos1-1));
  }
   
   do //使用do-while循环结构以便随时跳出运行
   {
        if(!socket.Create())  break;          //建立套接字
        fgSocketExist = TRUE;          //做标记

       //连接服务器
      if(!socket.Connect((LPCTSTR)csServer, SMTP_PORT))  break; 
      if(GetResponseCode(&socket) != 220)  break;
 
       //得到主机名,发送"HELO"
      gethostname(szBuffer, 80);
      csText.Format("HELO %s\r\n", szBuffer);
      socket.Send((LPCTSTR)csText, csText.GetLength());
      if(GetResponseCode(&socket) != 250)  break;                   //读取返回码,以判断是否发送成功(下同,不再注释)
      
      //发送要求登录信息
      csText.Format("AUTH LOGIN\r\n", (LPCTSTR)csMailFrom);
      socket.Send((LPCTSTR)csText, csText.GetLength());
       if(GetResponseCode(&socket) != 334)  break;

      //发送登录帐号
      csText = ZBase64Encode((LPCTSTR)csAccount, csAccount.GetLength());  csText += "\r\n";
      socket.Send((LPCTSTR)csText, csText.GetLength());
      if(GetResponseCode(&socket) != 334)  break;

      //发送密码
      csText = ZBase64Encode((LPCTSTR)csPassword, csPassword.GetLength()); csText += "\r\n";
      socket.Send((LPCTSTR)csText, csText.GetLength());
       if(GetResponseCode(&socket) != 235)  break;

        //发送发件人信息
       csText.Format(_T("MAIL From: <%s>\r\n" ), (LPCTSTR)csMailFrom);
       socket.Send((LPCTSTR)csText, csText.GetLength());
       if(GetResponseCode(&socket) != 250)  break;   //553需要验证,若没有发帐号信息则会返回553。现在貌似已没有不用登录的SMTP服务器了

      //发送收件人信息
      csText.Format(_T("RCPT TO: <%s>\r\n"), szMailAddresss);
      socket.Send((LPCTSTR)csText, csText.GetLength());
      if(GetResponseCode(&socket) != 250)  break;
    
       //发送数据开始命令
      csText = "DATA\r\n";
      socket.Send((LPCTSTR)csText, csText.GetLength());
      if(GetResponseCode(&socket) != 354)  break;

       //发送邮件头
      csText.Format("From: %s<%s>\r\n", MAIL_SENDER, (LPCTSTR)csMailFrom);    //发送者 
      csText.Format("To: %s<%s>\r\n", MAIL_RECEIVER, szMailAddresss);         //接收者
      csText += "Subject:"; csText += MAIL_SUBJECT; csText += "\r\n";         //主题
      csText += "X-mailer:"; csText += MAIL_COPYRIGHT; csText += "\r\n"; //版权
      csText += "Mime_Version:1.0\r\n";                                       //编码
      csText += "Content-type:multipart/mixed";                               //邮件头类型
      if(fgAttachExist) {csText += "; Boundary="; csText += MAIL_BOUNDARY;};  //有符件,指定分界符
      csText += "\r\n"; //指定分界符
      if(socket.Send((LPCTSTR)csText, csText.GetLength()) == SOCKET_ERROR) break;
 
      //发送内容 
     csText = "";
     if(fgAttachExist) {csText += "--"; csText += MAIL_BOUNDARY;  csText += "\r\n";};  //分界界首。若没有附件则不需要分界符
     csText += "Content-type:text/plain; Charset=gb2312\r\n";                //普通文本类型
     csText += "Content-Transfer-Encoding:8bit\r\n\r\n";                     //编码
     csText += szContent;  csText += "\r\n\r\n";                             //邮件内容
     if(socket.Send((LPCTSTR)csText, csText.GetLength()) == SOCKET_ERROR) break;

     //发送附件
     csText = "";
     if(fgAttachExist)
     {
        csText = "--";  csText += MAIL_BOUNDARY; csText += "\r\n";             //分界符
        csText += "Content-Type:application/octet-stream; Name=";
        csText += csFileName;  csText += "\r\n";
        csText += "Content-Disposition:attachment; FileName=";
        csText += csFileName;  csText += "\r\n";
        csText += "Content-Transfer-Encoding:Base64\r\n\r\n";
         if(socket.Send((LPCTSTR)csText, csText.GetLength()) == SOCKET_ERROR) break;

        SendAttchment(&socket, szAttachment);

        csText = "--"; csText += MAIL_BOUNDARY; csText += "--";              //界尾
      }

      //发送结束标记
      csText += "\r\n.\r\n";                                                           //结束标记
      socket.Send((LPCTSTR)csText, csText.GetLength());
      if(GetResponseCode(&socket) != 250)  break;
    
      //发送退出命令
      csText = "QUIT\r\n";
      socket.Send((LPCTSTR)csText, csText.GetLength());
      if(GetResponseCode(&socket) != 221) break;

      fgSucceed = TRUE;

   }while(FALSE);

   if(fgSocketExist) socket.Close();

   return fgSucceed;
}


例子:

SendEmail(“12345@163.com”, "smtp.163.com\tusr123\t8888","This is a Test!",  "c:\\test.txt");




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值