📄 smtp.cpp
字号:
#include "stdafx.h"
#include "smtp.h"
#include "Base64.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#define DEBUG
CSMTP::response_code CSMTP::response_table[] =
{
{ 250, _T( "SMTP server error" ) },
{ 220, _T( "SMTP server not available" ) },
{ 354, _T( "SMTP server not ready for data" ) },
{ 221, _T( "SMTP server didn't terminate session" ) }
};
CSMTP::CSMTP(LPCSTR szSMTPServerName, UINT nPort)
{
ASSERT( szSMTPServerName != NULL );
AfxSocketInit();
m_sSMTPServerHostName = szSMTPServerName;
m_nPort = nPort;
m_bConnected = FALSE;
m_sError = _T("OK");
response_buf = NULL;
}
CSMTP::~CSMTP()
{
Disconnect();
}
CString CSMTP::GetServerHostName()
{
return m_sSMTPServerHostName;
}
#define HOSTNAMELENGTH 88
BOOL CSMTP::Connect()
{
CString sHello;
TCHAR local_host[HOSTNAMELENGTH];
// 如果建立了连接则返回
if( m_bConnected )
return TRUE;
response_buf = new TCHAR[RESPONSE_BUFFER_SIZE];
if(!response_buf)
{
m_sError = _T("内存不足!");
return FALSE;
}
if( !m_wsSMTPServer.Create() )
{
m_sError = _T("无法创建套接字");
delete[] response_buf;
response_buf = NULL;
return FALSE;
}
if( !m_wsSMTPServer.Connect(GetServerHostName(), GetPort() ) )
{
m_sError = _T("无法与服务器建立连接!");
m_wsSMTPServer.Close();
delete[] response_buf;
response_buf = NULL;
return FALSE;
}
if( !get_response(CONNECT_SUCCESS) )
{
// 接收应答失败
m_sError = _T("服务器没有回答");
m_wsSMTPServer.Close();
delete[] response_buf;
response_buf = NULL;
return FALSE;
}
gethostname(local_host, HOSTNAMELENGTH);
// 以HELO命令开始发信
sHello.Format( _T("EHLO %s\r\n"), local_host);
m_wsSMTPServer.Send((LPCSTR) sHello, sHello.GetLength());
if( !get_response(GENERIC_SUCCESS))
{
m_wsSMTPServer.Close();
delete[] response_buf;
response_buf = NULL;
return FALSE;
}
m_bConnected = TRUE;
return SendAuthentication();
}
int CSMTP::SendCmd(char *Command)
{
int len = strlen(Command);
if(m_wsSMTPServer.Send(Command, len))
{
if(m_wsSMTPServer.Receive(response_buf, RESPONSE_BUFFER_SIZE) != SOCKET_ERROR )
{
response_buf[3] = 0;
return atoi(response_buf);
}
}
return -1;
}
BOOL CSMTP::SendAuthentication()
{
int nRet = 0;
CBase64 cvt;
CHAR *pszAuthType = NULL;
CString TmpS;
// This is an authentication loop, we can authenticate multiple times in case of failure.
while(1)
{
TmpS = _T("AUTH LOGIN\r\n");
nRet = SendCmd((char *)LPCTSTR(TmpS));
// If it was rejected, we have to abort.
if (nRet != 334)
{
return FALSE;
}
// Authentication has 2 stages for username and password.
// It is possible if the authentication fails here that we can
// resubmit proper credentials.
while (1)
{
pszAuthType = new CHAR[strlen(response_buf+4)+100];
if(pszAuthType)
{
strcpy(pszAuthType, response_buf+4);
cvt.Decode(pszAuthType);
TmpS = cvt.DecodedMessage();
TmpS = TmpS.Left(9);
TmpS.MakeLower();
if (TmpS == "username:")
cvt.Encode("alex");
else if (TmpS == "password:")
cvt.Encode("m85ti8e9");
else
{
delete pszAuthType;
pszAuthType = NULL;
break;
}
TmpS.Format("%s\r\n",cvt.EncodedMessage());
nRet = SendCmd((char *)LPCTSTR(TmpS));
// If we got a failed authentication request, raise a warning.
// this gives the owner a chance to change the username and password.
if (nRet == 535)
{
delete pszAuthType;
pszAuthType = NULL;
break;
}
// Break on any response other than 334, which indicates a request for more information
if (nRet != 334)
{
delete pszAuthType;
pszAuthType = NULL;
break;
}
else
{
delete pszAuthType;
pszAuthType = NULL;
}
}
else
break;
}
if(pszAuthType)
delete pszAuthType;
pszAuthType = NULL;
// Break if we're not retrying a failed authentication
if (nRet != TRUE) break;
}
if(nRet == 535)
return TRUE;
return (nRet == 235) ? TRUE : FALSE;
}
BOOL CSMTP::Disconnect()
{
BOOL bRet;
if( !m_bConnected )
return TRUE;
// 发送QUIT命令断开连接
CString strQuit = _T("QUIT\r\n");
m_wsSMTPServer.Send((LPCSTR)strQuit, strQuit.GetLength());
bRet = get_response(QUIT_SUCCESS);
m_wsSMTPServer.Close();
if( response_buf != NULL )
{
delete[] response_buf;
response_buf = NULL;
}
m_bConnected = FALSE;
return bRet;
}
UINT CSMTP::GetPort()
{
return m_nPort;
}
CString CSMTP::GetLastError()
{
return m_sError;
}
BOOL CSMTP::SendMessage(CMailMessage* msg)
{
if( msg == NULL )
return FALSE;
if( !m_bConnected )
{
m_sError = _T("哟,忘了先连服务器了");
return FALSE;
}
if( !FormatMailMessage(msg) )
return FALSE;
if( !transmit_message(msg) )
return FALSE;
return TRUE;
}
BOOL CSMTP::FormatMailMessage(CMailMessage * msg)
{
if( !msg )
return FALSE;
msg->FormatMessage();
return TRUE;
}
void CSMTP::SetServerProperties(LPCSTR szSMTPServerName, UINT nPort)
{
if( szSMTPServerName == NULL )
return;
m_sSMTPServerHostName = szSMTPServerName;
m_nPort = nPort;
}
CString CSMTP::cook_body(CMailMessage* msg)
{
ASSERT(msg);
CString strTemp = msg->m_strBody;
CString strCook = _T("");
CString strBad = _T("\r\n.\r\n");
CString strGood = _T("\r\n..\r\n");
int nPos, nStart = 0, nBadLength = strBad.GetLength();
if( strTemp.Left(3) == _T(".\r\n") )
strTemp = _T(".") + strTemp;
while( (nPos = strTemp.Find(strBad)) > -1 )
{
strCook = strTemp.Mid(nStart, nPos);
strCook += strGood;
strTemp = strCook + strTemp.Right(strTemp.GetLength() - (nPos + nBadLength));
}
return strTemp;
}
BOOL CSMTP::transmit_message(CMailMessage *msg)
{
CString strFrom, strTo, strTemp, strEmail;
if( msg == NULL )
return FALSE;
if( !m_bConnected )
{
m_sError = _T("请先建立连接!");
return FALSE;
}
// 发送MAIL命令
strFrom.Format( _T("MAIL From: <%s>\r\n"), (LPCSTR)msg->m_strFrom);
m_wsSMTPServer.Send((LPCSTR)strFrom, strFrom.GetLength());
if( !get_response(GENERIC_SUCCESS) )
return FALSE;
// 发送RCPT命令
//#ifdef DEBUG
// strTo.Format(_T("RCPT TO: <%s>\r\n"), (LPCSTR)"beanstud-007@smtp.dzbjet.com");
//#else
strTo.Format(_T("RCPT TO: <%s>\r\n"), (LPCSTR)msg->m_strTo);
//#endif
m_wsSMTPServer.Send((LPCSTR)strTo, strTo.GetLength());
if( !get_response(GENERIC_SUCCESS) ) return FALSE;
// 发送DATA命令
strTemp = _T("DATA\r\n");
m_wsSMTPServer.Send((LPCSTR)strTemp, strTemp.GetLength());
if( !get_response(DATA_SUCCESS) )
{
// 发送DATA命令失败
return FALSE;
}
// 发送邮件头
m_wsSMTPServer.Send((LPCSTR)msg->m_strHeader, msg->m_strHeader.GetLength());
// 发送邮件正文
strTemp = cook_body(msg);
m_wsSMTPServer.Send((LPCSTR)strTemp, strTemp.GetLength());
// 给邮件正文加上结束标志
strTemp = _T("\r\n.\r\n");
m_wsSMTPServer.Send((LPCSTR)strTemp, strTemp.GetLength());
if(!get_response(GENERIC_SUCCESS))
return FALSE;
return TRUE;
}
BOOL CSMTP::get_response(UINT response_expected)
{
ASSERT( response_expected >= GENERIC_SUCCESS );
ASSERT( response_expected < LAST_RESPONSE );
CString sResponse;
UINT response;
response_code* pResp;
if( m_wsSMTPServer.Receive(response_buf, RESPONSE_BUFFER_SIZE) == SOCKET_ERROR )
{
m_sError = _T("套接字错误");
return FALSE;
}
sResponse = response_buf;
sscanf( (LPCSTR)sResponse.Left(3), _T("%d"), &response );
pResp = &response_table[response_expected];
if( response != pResp->nResponse )
{
m_sError.Format(_T("%d : %s"), response, (LPCSTR)pResp->sMessage );
return FALSE;
}
return TRUE;
}
void CSMTP::Cancel()
{
// 取消阻塞的连接
m_wsSMTPServer.CancelBlockingCall();
// 关闭套接字
m_wsSMTPServer.Close();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -