SmtpSendManger.cpp
上传用户:weimei12
上传日期:2022-08-11
资源大小:185k
文件大小:14k
- #include "StdAfx.h"
- #include "MailMessage.h"
- #include "SmtpSendManger.h"
- #include "MIMEContentAgent.h"
- #include "MIMEMessage.h"
- #include "MIMECode.h"
- #include "Base64.h"
- CSmtpSendManger::response_code CSmtpSendManger::s_response_table[] =
- {
- //Response expected, Error message if we don't get it
- { 250, _T( "SMTP server error" ) },// GENERIC_SUCCESS
- { 220, _T( "SMTP server not available" ) },// CONNECT_SUCCESS
- { 354, _T( "SMTP server not ready for data" ) },// DATA_SUCCESS
- { 221, _T( "SMTP server didn't terminate session" ) },// QUIT_SUCCESS
- { 334, _T( "Login SMTP server" ) },//AUTH LOGIN
- { 235, _T("authentication successfully") },//LOGIN_SUCCESS
- { 553, _T("authentication failed") },//LOGIN_FAILED
- //List here, not process mow. Maybe different way to use instead of the above error code.
- //error code, error description
- { 501, _T("Syntax error in parameters or arguments") },
- { 502, _T("Command not implemented") },
- { 503, _T("Bad sequence of commands") },
- { 504, _T("Command parameter not implemented") },
- { 211, _T("System status, or system help reply") },
- { 214, _T("Help message") },
- { 421, _T("<domain> Service not available, closing transmission channel") },
- { 251, _T("User not local; will forward to <forward-path>") },
- { 450, _T("Requested mail action not taken: mailbox unavailable") },
- { 550, _T("Requested action not taken: mailbox unavailable") },
- { 451, _T("Requested action aborted: error in processing") },
- { 551, _T("User not local; please try <forward-path>") },
- { 452, _T("Requested action not taken: insufficient system storage") },
- { 552, _T("Requested mail action aborted: exceeded storage allocation") },
- { 554, _T("Transaction failed") }
- };
- CSmtpSendManger::CSmtpSendManger(void)
- {
- AfxSocketInit();
- m_strError = _T("OK");
- m_pszResponse_buf = NULL;
- m_nRecvTimeout = 50000;
- m_nSendTimeout = 50000;
- m_bValidate = TRUE;
- }
- CSmtpSendManger::~CSmtpSendManger(void)
- {
- Disconnect();
- }
- ///<summary>
- /// send the mail
- ///</summary>
- HRESULT CSmtpSendManger::SendMailMessage(const CString& strRcs,
- const CString& strCCRcs,
- const CString& strBCCRcs,
- const CString& strSubject,
- const CString& strContent,
- const CStringArray& strAttachFiles)
- {
- //construct the mail
- CMIMEMessage msgToSend;
- msgToSend.SetInfo(m_strSendMail, strSubject, strContent, m_strUserName, m_strPassword);
- msgToSend.AddMultipleRecipients(strRcs);
- msgToSend.AddMultipleRecipients(strCCRcs, CMailMessage::CC);
- msgToSend.AddMultipleRecipients(strBCCRcs, CMailMessage::BCC);
- int i = 0;
- for (; i < strAttachFiles.GetSize(); i++)
- {
- msgToSend.AddMIMEPart(strAttachFiles[i]);
- }
- if(msgToSend.GetNumRecipients() == 0)
- {
- m_strError = _T("No Recipients");
- return HRESULT_FAIL;
- }
- msgToSend.FormatMessage();
- //start the transmission
- if (!Connect())
- {
- return HRESULT_FAIL;
- }
- if (!CmdHelo(EXTEND_SMTP))
- {
- Disconnect();
- return HRESULT_FAIL;
- }
- if (m_bValidate)
- {
- if (!CmdAuthLogin())
- {
- Disconnect();
- return HRESULT_FAIL;
- }
- }
- if (!CmdMailFrom())
- {
- Disconnect();
- return HRESULT_FAIL;
- }
- if (!AddMultiRecipient(&msgToSend))
- {
- Disconnect();
- return HRESULT_FAIL;
- }
- if (!CmdData(&msgToSend))
- {
- Disconnect();
- return HRESULT_FAIL;
- }
- if (!Disconnect())
- {
- return HRESULT_FAIL;
- }
- return HRESULT_SUCCESS;
- }
- ///<summary>
- /// set the user name
- ///</summary>
- void CSmtpSendManger::SetUserName(const CString& strUserName)
- {
- m_strUserName = strUserName;
- }
- ///<summary>
- /// set the password
- ///</summary>
- void CSmtpSendManger::SetPassword(const CString& strPassword)
- {
- m_strPassword = strPassword;
- }
- ///<summary>
- /// set the Smtp server address
- ///</summary>
- void CSmtpSendManger::SetSmtpServer(const CString& strSmtpServer)
- {
- m_strSmtpServer = strSmtpServer;
- }
- ///<summary>
- /// set the sender address
- ///</summary>
- void CSmtpSendManger::SetSendMail(const CString& strSendMail)
- {
- m_strSendMail = strSendMail;
- }
- ///<summary>
- /// set whether to validate the identity
- ///</summary>
- void CSmtpSendManger::SetValidate(IN BOOL bValidate)
- {
- m_bValidate = bValidate;
- }
- ///<summary>
- /// get the last error description
- ///</summary>
- CString CSmtpSendManger::GetLastErrorMsg()
- {
- return m_strError;
- }
- BOOL CSmtpSendManger::Connect()
- {
- //Allocate memory for receiving, and the memory will be deleted in Disconnect();
- m_pszResponse_buf = new char[RESPONSE_BUFFER_SIZE];
- if(m_pszResponse_buf == NULL)
- {
- m_strError = _T("Not enough memory");
- return FALSE;
- }
- memset(m_pszResponse_buf, 0, sizeof(RESPONSE_BUFFER_SIZE));
- //Create socket, and set corresponding parameters
- if(!m_wsSMTPServer.Create())
- {
- m_strError = _T("Unable to create the socket.");
- delete m_pszResponse_buf;
- m_pszResponse_buf = NULL;
- return FALSE;
- }
- if (!SetNetParams())
- {
- return FALSE;
- }
- //Connect the server
- if(!m_wsSMTPServer.Connect(m_strSmtpServer, SMTP_PORT))
- {
- m_strError = _T("Unable to connect to server");
- m_wsSMTPServer.Close();
- delete m_pszResponse_buf;
- m_pszResponse_buf = NULL;
- return FALSE;
- }
- if(!CheckResponse(CONNECT_SUCCESS))
- {
- m_strError = _T("Server didn't respond.");
- m_wsSMTPServer.Close();
- delete m_pszResponse_buf;
- m_pszResponse_buf = NULL;
- return FALSE;
- }
- return TRUE;
- }
- BOOL CSmtpSendManger::Disconnect()
- {
- CmdQuit();
- m_wsSMTPServer.Close();
- if(m_pszResponse_buf != NULL)
- {
- delete[] m_pszResponse_buf;
- m_pszResponse_buf = NULL;
- }
- return TRUE;
- }
- ///<summary>
- /// identify the sender to the receiver
- ///</summary>
- BOOL CSmtpSendManger::CmdHelo(int nType /* = ORIGIN_SMTP */)
- {
- char szLocal_host[_MAX_PATH] = {0};
- gethostname(szLocal_host, _MAX_PATH);
- CString strHello;
- if (ORIGIN_SMTP == nType)
- {
- strHello.Format("HELO %srn", szLocal_host);
- }
- else if (EXTEND_SMTP == nType)
- {
- strHello.Format("EHLO %srn", szLocal_host);
- }
- m_wsSMTPServer.Send(strHello, strHello.GetLength());
- if(!CheckResponse(GENERIC_SUCCESS))
- {
- m_wsSMTPServer.Close();
- delete m_pszResponse_buf;
- m_pszResponse_buf = NULL;
- return FALSE;
- }
- return TRUE;
- }
- ///<summary>
- /// initiate a mail transaction
- ///</summary>
- BOOL CSmtpSendManger::CmdMailFrom()
- {
- CString strCmdFrom;
- strCmdFrom.Format("MAIL From: <%s>rn", m_strSendMail);
- m_wsSMTPServer.Send(strCmdFrom, strCmdFrom.GetLength());
- if(!CheckResponse(GENERIC_SUCCESS))
- {
- return FALSE;
- }
- return TRUE;
- }
- ///<summary>
- /// identify the recipient
- ///</summary>
- BOOL CSmtpSendManger::CmdRcptTo(const CString& strTo)
- {
- CString strCmdTo;
- strCmdTo.Format("RCPT TO: <%s>rn", strTo);
- m_wsSMTPServer.Send(strCmdTo, strCmdTo.GetLength());
- if(!CheckResponse(GENERIC_SUCCESS))
- {
- return FALSE;
- }
- return TRUE;
- }
- ///<summary>
- /// transmit data without any encoding mechanisms
- ///</summary>
- BOOL CSmtpSendManger::CmdData(CMailMessage* pMsg)
- {
- ASSERT(pMsg != NULL);
- if (NULL == pMsg)
- {
- return FALSE;
- }
- CString strTemp;
- // Send the DATA command
- strTemp = "DATArn";
- m_wsSMTPServer.Send(strTemp, strTemp.GetLength());
- if(!CheckResponse(DATA_SUCCESS))
- {
- return FALSE;
- }
- // Send the header
- m_wsSMTPServer.Send(pMsg->GetMailHeader(), pMsg->GetMailHeader().GetLength());
- // Send the body
- strTemp = CookBody(pMsg);
- m_wsSMTPServer.Send(strTemp, strTemp.GetLength());
- // Signal end of data
- strTemp = "rn.rn";
- m_wsSMTPServer.Send(strTemp, strTemp.GetLength());
- if(!CheckResponse(GENERIC_SUCCESS))
- {
- return FALSE;
- }
- return TRUE;
- }
- ///<summary>
- /// confirm a user
- ///</summary>
- BOOL CSmtpSendManger::CmdVrfy(const CString& str)
- {
- CString strCmd;
- strCmd.Format("VRFY %srn", str);
- m_wsSMTPServer.Send(strCmd, strCmd.GetLength());
- if(!CheckResponse(GENERIC_SUCCESS))
- {
- return FALSE;
- }
- return TRUE;
- }
- ///<summary>
- /// confirm a mailing list
- ///</summary>
- BOOL CSmtpSendManger::CmdExpn(const CString& strList)
- {
- CString strCmd;
- strCmd.Format("EXPN %srn", strList);
- m_wsSMTPServer.Send(strCmd, strCmd.GetLength());
- if(!CheckResponse(GENERIC_SUCCESS))
- {
- return FALSE;
- }
- return TRUE;
- }
- ///<summary>
- /// ask the receiver to send helpful information
- ///</summary>
- BOOL CSmtpSendManger::CmdHelp(vector<CString>& strCmdList)
- {
- CString strCmd;
- strCmd = "HELPrn";
- m_wsSMTPServer.Send(strCmd, strCmd.GetLength());
- //Receive the response
- int nLen = 0 ;
- Sleep(300);
- if( (nLen = m_wsSMTPServer.Receive(m_pszResponse_buf, RESPONSE_BUFFER_SIZE)) == SOCKET_ERROR)
- {
- m_strError = _T("Socket Error");
- return FALSE;
- }
- m_pszResponse_buf[nLen] = ' ';
- CString strResponse;
- strResponse = m_pszResponse_buf;
- TRACE("receive: %sn", strResponse);
- //parse the response
- if (strResponse.Find("rn") <= 0)
- {
- m_strError = _T("Response Error");
- return FALSE;
- }
- strResponse = strResponse.Right(strResponse.GetLength() - strResponse.Find("rn") - 6);//4 = strlen("rn214 ")
- while (strResponse.Find(" ") > 0)
- {
- strCmdList.push_back(strResponse.Left(strResponse.Find(" ")));
- strResponse = strResponse.Right(strResponse.GetLength() - strResponse.Find(" ") - 1);
- }
- strCmdList.push_back(strResponse);//the last cmd
- return TRUE;
- }
- ///<summary>
- /// no action other than that the receiver send an OK reply
- ///</summary>
- BOOL CSmtpSendManger::CmdNoop()
- {
- CString strCmd;
- strCmd = "NOOPrn";
- m_wsSMTPServer.Send(strCmd, strCmd.GetLength());
- if(!CheckResponse(GENERIC_SUCCESS))
- {
- return FALSE;
- }
- return TRUE;
- }
- ///<summary>
- /// close the transmission
- ///</summary>
- BOOL CSmtpSendManger::CmdQuit()
- {
- CString strCmd;
- strCmd = "QUITrn";
- m_wsSMTPServer.Send(strCmd, strCmd.GetLength());
- if(!CheckResponse(QUIT_SUCCESS))
- {
- return FALSE;
- }
- return TRUE;
- }
- ///<summary>
- /// cancel the current transaction
- ///</summary>
- BOOL CSmtpSendManger::CmdRSET()
- {
- CString strCmd;
- strCmd = "RSETrn";
- m_wsSMTPServer.Send(strCmd, strCmd.GetLength());
- if(!CheckResponse(GENERIC_SUCCESS))
- {
- return FALSE;
- }
- return TRUE;
- }
- ///<summary>
- /// verify the user
- ///</summary>
- BOOL CSmtpSendManger::CmdAuthLogin()
- {
- CString strVerify;
- // Send the verify command
- strVerify.Format("AUTH LOGINrn") ;
- m_wsSMTPServer.Send(strVerify, strVerify.GetLength());
- if(!CheckResponse(AUTH_LOGIN))
- {
- return FALSE;
- }
- // Send the username
- CString strUserName;
- strUserName.Format(m_strUserName);
- CBase64 base64;
- strUserName = base64.Encode(strUserName, strUserName.GetLength());
- strUserName += "rn" ;
- m_wsSMTPServer.Send(strUserName, strUserName.GetLength());
- if(!CheckResponse(AUTH_LOGIN))
- {
- return FALSE;
- }
- //Send the password
- CString strPassword;
- strPassword.Format(m_strPassword);
- strPassword = base64.Encode(strPassword, strPassword.GetLength());
- strPassword += "rn";
- m_wsSMTPServer.Send(strPassword, strPassword.GetLength());
- if(!CheckResponse(LOGIN_SUCCESS))
- {
- return FALSE;
- }
- return TRUE;
- }
- ///<summary>
- /// transmit data encoded with base64
- ///</summary>
- BOOL CSmtpSendManger::AddMultiRecipient(CMailMessage * pMsg)
- {
- ASSERT(pMsg != NULL);
- if (NULL == pMsg)
- {
- return FALSE;
- }
- CString strTemp;
- CString strEmail;
- // Send RCPT commands (one for each recipient)
- //the primary recipients
- int i = 0;
- for(; i < pMsg->GetNumRecipients(); i++)
- {
- pMsg->GetRecipient(strEmail, strTemp, i);
- CmdRcptTo(strEmail);
- }
- //the secondary recipients
- for(i = 0; i < pMsg->GetNumRecipients(CMailMessage::CC); i++)
- {
- pMsg->GetRecipient(strEmail, strTemp, i, CMailMessage::CC);
- CmdRcptTo(strEmail);
- }
- //additional recipients
- for(i = 0; i < pMsg->GetNumRecipients(CMailMessage::BCC); i++)
- {
- pMsg->GetRecipient(strEmail, strTemp, i, CMailMessage::BCC);
- CmdRcptTo(strEmail);
- }
-
- return TRUE;
- }
- ///<summary>
- /// set socket parameters
- ///</summary>
- BOOL CSmtpSendManger::SetNetParams()
- {
- //off TIME_WAIT
- struct linger zeroLinger;
- zeroLinger.l_onoff = 1;
- zeroLinger.l_linger = 0;
- if(!m_wsSMTPServer.SetSockOpt(SO_LINGER, (const char *)&zeroLinger
- ,sizeof(zeroLinger)))
- {
- m_strError = _T("Unable to off time_wait.");
- delete m_pszResponse_buf;
- m_pszResponse_buf = NULL;
- return FALSE;
- }
- //set receive timeout
- if(!m_wsSMTPServer.SetSockOpt(SO_RCVTIMEO, (const char *)&m_nRecvTimeout
- ,sizeof(m_nRecvTimeout)))
- {
- m_strError = _T("Unable to set receive timeout.");
- delete m_pszResponse_buf;
- m_pszResponse_buf = NULL;
- return FALSE;
- }
- //set send timeout
- if(!m_wsSMTPServer.SetSockOpt(SO_SNDTIMEO, (const char *)&m_nSendTimeout
- ,sizeof(m_nSendTimeout)))
- {
- m_strError = _T("Unable to set send timeout.");
- delete m_pszResponse_buf;
- m_pszResponse_buf = NULL;
- return FALSE;
- }
- return TRUE;
- }
- ///<summary>
- /// handle the periods in the message body
- ///</summary>
- CString CSmtpSendManger::CookBody(CMailMessage * pMsg)
- {
- CString strTemp;
- ASSERT(pMsg != NULL);
- if (NULL == pMsg)
- {
- return strTemp;
- }
-
- CString strCooked = "";
- LPTSTR pszBad = "rn.rn";
- LPTSTR pszGood = "rn..rn";
- int nPos = 0;
- int nStart = 0;
- int nBadLength = (int)strlen(pszBad);
- strTemp = pMsg->GetMailBody();
- if(strTemp.Left(3) == ".rn")
- {
- strTemp = "." + strTemp;
- }
- while((nPos = strTemp.Find(pszBad)) > -1)
- {
- strCooked = strTemp.Mid(nStart, nPos);
- strCooked += pszGood;
- strTemp = strCooked + strTemp.Right(strTemp.GetLength() - (nPos + nBadLength));
- }
- return strTemp;
- }
- BOOL CSmtpSendManger::CheckResponse(UINT nResponse_expected)
- {
- ASSERT(nResponse_expected >= GENERIC_SUCCESS);
- ASSERT(nResponse_expected < LAST_RESPONSE);
- CString strResponse;
- UINT nResponse = LAST_RESPONSE;
- response_code* pResp = NULL;
- //Receive the response
- int nLen = 0 ;
- Sleep(300);
- if( (nLen = m_wsSMTPServer.Receive(m_pszResponse_buf, RESPONSE_BUFFER_SIZE)) == SOCKET_ERROR)
- {
- m_strError = _T("Socket Error");
- return FALSE;
- }
- m_pszResponse_buf[nLen] = ' ';
- strResponse = m_pszResponse_buf;
- TRACE("receive: %sn", strResponse);
- //parse the response
- sscanf_s(strResponse.Left(3), "%d", &nResponse);
- pResp = &s_response_table[nResponse_expected];
- if(nResponse != pResp->nResponse)
- {
- m_strError.Format(_T("%d:%s"), nResponse, pResp->pszMessage);
- return FALSE;
- }
- return TRUE;
- }