精华区 [关闭][返回]

当前位置:网易精华区>>讨论区精华>>编程开发>>C/C++>>网络与通讯>>Re:如何编写SMTP需要身份验证的邮件发送程序?

主题:Re:如何编写SMTP需要身份验证的邮件发送程序?
发信人: wenbobo(灌了拂衣去)
整理人: wenbobo(2002-06-06 11:12:21), 站内信件
【 在 headspring 的大作中提到:】
:像outlook和foxmail等等,都带有身份验证支持,我想实现它,请问它遵循什么标准呢?
:......

除了RFC,就是STD,平时多看看。这个是同事的日常练习程序,也不知道对不对,参考一下吧

// atmosmail.cpp : Defines the entry point for the console application.
//
#pragma comment (lib,"wsock32.lib")

#ifndef  CMD_RESPONSE_SIZE
#define  CMD_RESPONSE_SIZE 1024
#endif

#ifndef  CMD_BLOCK_SIZE
#define  CMD_BLOCK_SIZE 1024
#endif

#ifndef  m_dwCmdTimeout
#define  m_dwCmdTimeout 60
#endif 

#ifndef  MAXPATH
#define  MAXPATH 100
#endif

#include "stdafx.h"
#include <winsock2.h>
#include <stdio.h>
#include <TCHAR.h>
#include <String>

SOCKET m_hSocket; 
LPTSTR m_strResult;

bool m_bExtensions=true;  // 默认情况下使用ESMTP协议

unsigned int  m_LineWidth = 76;

//Base64解码表
const char BASE64_ENCODE_TABLE[64] = {
 65,  66,  67,  68,  69,  70,  71,  72,  // 00 - 07
 73,  74,  75,  76,  77,  78,  79,  80,  // 08 - 15
 81,  82,  83,  84,  85,  86,  87,  88,  // 16 - 23
 89,  90,  97,  98,  99, 100, 101, 102,  // 24 - 31
103, 104, 105, 106, 107, 108, 109, 110,  // 32 - 39
111, 112, 113, 114, 115, 116, 117, 118,  // 40 - 47
119, 120, 121, 122,  48,  49,  50,  51,  // 48 - 55
 52,  53,  54,  55,  56,  57,  43,  47 };// 56 - 63

 ///////////////////////base64
//获取Base64编码长度
int Base64EncodeSize(int iSize)
{
int nSize, nCR;
nSize = (iSize + 2) / 3 * 4 ;
nCR = nSize / m_LineWidth; //计算回车数量
nSize+= nCR * 2;
return nSize;
}
//////////////////////////////////////////////////////////
int base64_encode(char *pSrc, unsigned int nSize, char *pDest)
{
   /*

*  对一段Buffer进行Base64编码
*
*   pSrc 输入Buffer
* nSize Buffer长度
* pDest 输出缓冲
*
*  注: 输出Buffer的长度可以使用 Base64EncodeSize(int) 方法取得
    *
    *  return: base64编码后的字符串的长度

*/

if ((pSrc == NULL) || (nSize <= 0)) return 0;

unsigned int iB, iInMax3, Len;
char *pInPtr, *pInLimitPtr;
char *OutPtr ;

pInPtr = pSrc;
iInMax3 = (nSize / 3) * 3;
OutPtr = pDest;
pInLimitPtr = pInPtr + iInMax3;

while (pInPtr != pInLimitPtr)
{
Len = 0;
while ((Len < m_LineWidth) && (pInPtr != pInLimitPtr))
{
iB = (unsigned char) *pInPtr++;
iB = iB << 8;

iB = iB | (unsigned char) *pInPtr++;
iB = iB << 8;

iB = iB | (unsigned char) *pInPtr++;

//以4 byte倒序写入输出缓冲
OutPtr[3] = BASE64_ENCODE_TABLE[iB & 0x3F];
iB = iB >> 6;
OutPtr[2] = BASE64_ENCODE_TABLE[iB & 0x3F];
iB = iB >> 6;
OutPtr[1] = BASE64_ENCODE_TABLE[iB & 0x3F];
iB = iB >> 6;
OutPtr[0] = BASE64_ENCODE_TABLE[iB];
OutPtr+=4;
Len+=4;
}
if (Len >= m_LineWidth)
{
*OutPtr++ = '\r'; //加上回车换行符
*OutPtr++ = '\n';
}
}
//设置尾部
switch (nSize - iInMax3)
{
case 1:
iB = (unsigned char) *pInPtr;
iB = iB << 4;
OutPtr[1] = BASE64_ENCODE_TABLE[iB & 0x3F];
iB = iB >> 6;
OutPtr[0] = BASE64_ENCODE_TABLE[iB];
OutPtr[2] = '='; //用'='也就是64码填充剩余部分
OutPtr[3] = '=';
OutPtr+=4;
break;
case 2:
iB = (unsigned char) *pInPtr++;
iB = iB << 8;
iB = iB | (unsigned char) *pInPtr;
iB = iB << 2;
OutPtr[2] = BASE64_ENCODE_TABLE[iB & 0x3F];
iB = iB >> 6;
OutPtr[1] = BASE64_ENCODE_TABLE[iB & 0x3F];
iB = iB >> 6;
OutPtr[0] = BASE64_ENCODE_TABLE[iB];
OutPtr[3] = '='; // Fill remaining byte.
OutPtr+=4;
break;
}
return (unsigned int) (OutPtr - pDest);
}
/////////////////////////////////////////////////////////////
// Send a command to the SMTP server and wait for a response
//if success return the integer message of the smtp server
//or failed return -1 
int SendCmd(LPTSTR pszCmd)
{
  FD_SET set;
  TIMEVAL tv;
  int nRet = 0;
  DWORD dwTick;
  CHAR szResult[CMD_RESPONSE_SIZE];
  LPSTR pszPos;
  LPSTR pszTok;
  DWORD dwPosition;
  DWORD dwLen;
  DWORD dwMax;
  BOOL bReportProgress = FALSE;
  LPSTR pszBuff;
  
  ZeroMemory(szResult,CMD_RESPONSE_SIZE);
  FD_ZERO(&set);

  // If we have a command to send, then send it.
  if (pszCmd)
  {  
     pszBuff = (LPSTR) malloc(lstrlen(pszCmd)+1);
 lstrcpyA(pszBuff,pszCmd);

    // Make sure the input buffer is clear before sending
    nRet = 1;
    while (nRet > 0)
    {
      FD_SET(m_hSocket,&set);
      tv.tv_sec = 0;
      tv.tv_usec = 0;
      nRet = select(1,&set,NULL,NULL,&tv);
      if (nRet == 1) nRet = recv(m_hSocket,szResult,CMD_RESPONSE_SIZE,0);
    }

    dwPosition = 0;
    dwLen = lstrlen(pszCmd);

    if (dwLen > CMD_BLOCK_SIZE) bReportProgress = TRUE;

    while (dwLen != dwPosition)
    {
      dwMax = min(CMD_BLOCK_SIZE,dwLen - dwPosition);
  printf("send char is %s\n",&pszBuff[dwPosition]);
      nRet = send(m_hSocket,&pszBuff[dwPosition],dwMax,0);
      if (nRet == SOCKET_ERROR)
      {
        free(pszBuff);
        return nRet;
      }
      dwPosition += dwMax;
      if (bReportProgress)
      {
       //
      }
    }
    // Wait for the CMD to finish being sent
    FD_ZERO(&set);
    FD_SET(m_hSocket,&set);
    nRet = select(1,NULL,&set,NULL,NULL);
    free(pszBuff);
  }

  // Prepare to receive a response
  ZeroMemory(szResult,CMD_RESPONSE_SIZE);
  pszPos = szResult;
  nRet=1;
  // Wait for the specified timeout for a full response string
  dwTick = GetTickCount();
  while ((GetTickCount() - dwTick) < (m_dwCmdTimeout * 1000))
{
FD_SET(m_hSocket,&set);

tv.tv_sec = m_dwCmdTimeout - ((GetTickCount() - dwTick) / 1000);
tv.tv_usec = 0;

// Check the socket for readability
nRet = select(1,&set,NULL,NULL,&tv);
if (nRet == SOCKET_ERROR)
{
printf("error:read message from smtp server\n");
break;
}

// If the socket has data, read it.
if (nRet == 1)
{
nRet = recv(m_hSocket,pszPos,CMD_RESPONSE_SIZE - (pszPos - szResult),0);
printf("Message from smtp server:%s\n",pszPos);
// Treats a graceful shutdown as an error
if (nRet == 0) nRet = SOCKET_ERROR;
if (nRet == SOCKET_ERROR)
{
printf("error:read Null message from smtp server\n");
break;
}

// Add the data to the total response string & check for a LF
pszPos += nRet;
pszTok = strrchr(szResult,'\n');
if (pszTok)
{
// Truncate CRLF combination and exit our wait loop
pszTok --;
pszTok[0] = 0;
break;
}
}
}

// Assign the response string
m_strResult = szResult;

// Evaluate the numeric response code
if (nRet && (nRet != SOCKET_ERROR))
{
szResult[3] = 0;
nRet = atoi(szResult);
}
else nRet = -1;

return nRet;
}

int SendAuthentication(LPSTR Auth,LPSTR PassWord)
{
int length;
int nRet;
LPSTR pszBuff;
TCHAR szName[128];
TCHAR szPassWord[128];

nRet=SendCmd("Auth Login\r\n");
if (nRet != 334)
{
printf("Auth Login failed\r\n");
return nRet;
}

length=lstrlen(Auth);
pszBuff = (LPSTR) malloc(Base64EncodeSize(length)+1);
pszBuff[Base64EncodeSize(length)]=0;
base64_encode(Auth, length, pszBuff);
printf("Auth=%s\r\n",Auth);
printf("Auth=%s\r\n",pszBuff);

wsprintf(szName,(_T("%s\r\n")),pszBuff);

printf("%s\n",szName);
nRet=SendCmd(szName);
//if (nRet != 235)

length=lstrlen(PassWord);
pszBuff = (LPSTR) malloc(Base64EncodeSize(length));
pszBuff[Base64EncodeSize(length)]=0;
base64_encode(PassWord, length, pszBuff);
printf("PassWrod=%s\r\n",PassWord);
printf("PassWrod=%s\r\n",pszBuff);
wsprintf(szPassWord,(_T("%s\r\n")),pszBuff);
printf("%s\n",szPassWord);
nRet=SendCmd(szPassWord);


return 1;
}

// Initiate a conversation with the SMTP server
// Returns 0 if successful, or a positive
// error values if the SMTP server gave an error or failure response.
int SendHelo()
{
int nRet = 0;
TCHAR szName[32];
TCHAR szMsg[39];
DWORD dwSize = 32;
GetComputerName(szName,&dwSize);
printf("%s\n",szName);
wsprintf(szMsg,(_T("EHLO %s\r\n")),szName);
printf("%s\n",szMsg);
if (m_bExtensions)

nRet = SendCmd(szMsg);

if (nRet != 250)
{
szMsg[0] = 'H';
szMsg[1] = 'E';
nRet = SendCmd(szMsg);
}

if (nRet != 250)
return nRet;



return 0;
}

// Send a MAIL FROM command to the server
// Returns 0 if successful, or a positive
// error value if the SMTP server gave an error or failure response.
int SendFrom(LPTSTR pszFrom)
{
int nRet = 0;
TCHAR szMsg[MAX_PATH];

wsprintf(szMsg,_T("MAIL FROM:%s\r\n"),pszFrom);

while (1)
{
nRet = SendCmd(szMsg);

// Send authentication if required, and retry the command
if (nRet == 530) nRet = SendAuthentication("xxxx\r\n","*******\r\n");

else break;
}
// Raise an error if we failed
if (nRet != 250) return nRet;
return (nRet == 250) ? 0:nRet;
}

// Send a RCPT TO command to the server
// Returns 0 if successful, or a positive
// error value if the SMTP server gave an error or failure response.
int SendTo(LPTSTR pszTo)
{
int nRet;
TCHAR szMsg[MAX_PATH];

wsprintf(szMsg,_T("RCPT TO:%s\r\n"),pszTo);

nRet = SendCmd(szMsg);
if (nRet != 250 && nRet != 251) return (nRet);
return (nRet == 250 || nRet == 251) ? 0:nRet;
}

// Send the body of an e-mail message to the server
// Returns 0 if successful, or a positive
// error value if the SMTP server gave an error or failure response.
int SendData(LPSTR Message)
{
int nRet;

// Send the DATA command. We need a 354 to proceed
nRet = SendCmd(_T("DATA\r\n"));
if (nRet != 354)
{
return nRet;
}
// Parse the body of the email message
// Send the body and expect a 250 OK reply.
nRet = SendCmd(Message);
if (nRet != 250) return(nRet);

return (nRet == 250) ? 0:nRet;
}

// Tell the SMTP server we're quitting
// Returns 0 if successful, or a positive
// error value if the SMTP server gave an error or failure response.
int SendQuitCmd()
{

int nRet;

// if (!m_bConnected) return 0;

nRet = SendCmd(_T("QUIT\r\n"));

if (nRet != 221) return (nRet);

return (nRet == 221) ? 0:nRet;
}




////////////////////////////////////////////////////////////////////////////
///////////////////////////////MAIN( )//////////////////////////////////////
////////////////////////////////////////////////////////////////////////////

void main(int argc,char *argv[])
{
struct sockaddr_in server_addr;
struct hostent *hp;
int nRet;
WORD wVersionRequested;
WSADATA wsaData;

int err;
if (argc < 2)
{
printf("Usage is error!\n");
printf("Right usage:\n");
printf("Exmaple: client 10.38.0.119 25\n");
printf("OR: client smtp-ent.21cn.com 25\n");
return;
}

wVersionRequested=MAKEWORD(1,1);

err=WSAStartup(wVersionRequested, &wsaData);
if (err!=0)
{
perror("there is no DLL to use");
return;
}


if ( (LOBYTE(wsaData.wVersion)!=1) || (HIBYTE(wsaData.wVersion)!=1) )
{
perror("there is not right DLL");
WSACleanup();
return;
}

m_hSocket=socket(AF_INET,SOCK_STREAM,0);
if (m_hSocket<0)
{
perror("there is error in opening stream socket!");
return;
}


server_addr.sin_family=AF_INET;
hp=gethostbyname(argv[1]);
if(hp==0)
{
perror("cannot find hostname\n");
return;
}

memcpy((char *)&server_addr.sin_addr,(char *)hp->h_addr,hp->h_length);
server_addr.sin_port=htons((unsigned short)atoi(argv[2]));

//Before send data,listenning
     
//进行连接
if(connect(m_hSocket,(struct sockaddr*)&server_addr,sizeof(server_addr))<0)
{
perror("there is error in connecting stream socket");
return;
}

nRet = SendCmd(NULL);
if (nRet != 220)
{
//关闭socket
closesocket(m_hSocket);
WSACleanup();
return;
}
printf("220\n");

if (SendHelo())
{
//关闭socket
closesocket(m_hSocket);
WSACleanup();
return;
}

getchar();
SendAuthentication("[email protected]","*****");
getchar();

if (SendFrom("[email protected]"))
{
//关闭socket
closesocket(m_hSocket);
WSACleanup();
return;
}

getchar();
if (SendTo("[email protected]"))
{
//关闭socket
closesocket(m_hSocket);
WSACleanup();
return;
}

getchar();
if (SendData("Subject: test \r\n\r\nthis is a test\r\nhyx\r\n.\r\n"))
{
//关闭socket
closesocket(m_hSocket);
WSACleanup();
return;
}

getchar();
if (SendQuitCmd())
{
//关闭socket
closesocket(m_hSocket);
WSACleanup();
return;
}

printf("send is ok\n");
//关闭socket
closesocket(m_hSocket);
WSACleanup();
return;
}



----
█◣◢█
◢█◤
◢█◤
█◤◥█  

[关闭][返回]