⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smtp.cpp

📁 EMail VC++程序开发
💻 CPP
字号:
// SMTP.cpp: implementation of the CSMTP class.
// 

#include "stdafx.h"
#include "SMTP.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

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" ) }
};


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CSMTP::CSMTP( LPCTSTR 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 == NULL)
	{
		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("HELO %s\r\n"),local_host);
	m_wsSMTPServer.Send((LPCTSTR)sHello,sHello.GetLength());

	if(!get_response(GENERIC_SUCCESS))
	{
		// 获得应答信息失败
		m_wsSMTPServer.Close();
		delete response_buf;
		response_buf = NULL;
		return FALSE;
	}
	m_bConnected = TRUE;
	return TRUE;
}

BOOL CSMTP::Disconnect()
{
	BOOL bRet;
	if(!m_bConnected)
		return TRUE;

	// 发送QUIT命令断开连接
	CString strQuit = _T( "QUIT\r\n" );
	m_wsSMTPServer.Send((LPCTSTR)strQuit, strQuit.GetLength());

	bRet = get_response(QUIT_SUCCESS);

	// 关闭套接字
	m_wsSMTPServer.Close();

	// 释放资源,并将连接标志置为FALSE
	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)
	{
		// msg为空是没有意义的
		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 == NULL)
	{
		// msg为空是没有意义的
		return FALSE;
	}

	if(!msg->GetNumRecipients())
	{
		m_sError = _T("No Recipients");
		return FALSE;
	}

	// 在CMailMessage中封装了“格式化”消息的功能
	msg->FormatMessage();
	return TRUE;
}

void CSMTP::SetServerProperties( LPCTSTR 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_sBody;
	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" ),(LPCTSTR)msg->m_sFrom);
	m_wsSMTPServer.Send((LPCTSTR)strFrom,strFrom.GetLength());
	if(!get_response(GENERIC_SUCCESS))
		return FALSE;
	
	// 发送RCPT命令
	for(int i = 0;i < msg->GetNumRecipients();i++)
	{
		msg->GetRecipient(strEmail,strTemp,i);
		strTo.Format(_T("RCPT TO: <%s>\r\n"),(LPCTSTR)strEmail);
		m_wsSMTPServer.Send((LPCTSTR)strTo,strTo.GetLength());
		get_response(GENERIC_SUCCESS);
	}

	// 处理抄送
	for(i = 0;i < msg->GetNumRecipients(CMailMessage::CC);i++)
	{
	   msg->GetRecipient(strEmail,strTemp,i,CMailMessage::CC);
	   strTo.Format(_T("RCPT TO: <%s>\r\n"),(LPCTSTR)strEmail);
	   m_wsSMTPServer.Send((LPCTSTR)strTo,strTo.GetLength());
	   get_response(GENERIC_SUCCESS);
	}

	// 处理暗送
    for(i = 0;i < msg->GetNumRecipients(CMailMessage::BCC);i++)
	{
	   msg->GetRecipient(strEmail,strTemp,i,CMailMessage::BCC);
	   strTo.Format(_T( "RCPT TO: <%s>\r\n"),(LPCTSTR)strEmail);
	   m_wsSMTPServer.Send((LPCTSTR)strTo,strTo.GetLength());
	   get_response(GENERIC_SUCCESS);
	}

	// 发送DATA命令
	strTemp = _T("DATA\r\n");
	m_wsSMTPServer.Send((LPCTSTR)strTemp,strTemp.GetLength());
	if(!get_response(DATA_SUCCESS))
	{
		// 发送DATA命令失败
		return FALSE;
	}

	// 发送邮件头
	m_wsSMTPServer.Send((LPCTSTR)msg->m_sHeader,msg->m_sHeader.GetLength());

	// 发送邮件正文
	strTemp = cook_body(msg);
	m_wsSMTPServer.Send((LPCTSTR)strTemp,strTemp.GetLength());

	// 给邮件正文加上结束标志
	strTemp = _T("\r\n.\r\n");
	m_wsSMTPServer.Send((LPCTSTR)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((LPCTSTR)sResponse.Left(3),_T("%d"),&response );
	pResp = &response_table[response_expected];
	if(response != pResp->nResponse)
	{
		m_sError.Format(_T("%d : %s"),response,(LPCTSTR)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 + -