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

📄 smtp.cpp

📁 提供发送电子邮件的SMTP协议
💻 CPP
📖 第 1 页 / 共 3 页
字号:
      Disconnect();
      TRACE(_T("An unexpected HELO response was received\n"));
      return FALSE;
    } 

    return TRUE;
  }
}

BOOL CSMTPConnection::Disconnect()
{
  BOOL bSuccess = FALSE;      

  //disconnect from the SMTP server if connected 
  if (m_bConnected)
  {
    char sBuf[10];
    strcpy(sBuf, "QUIT\r\n");
    int nCmdLength = strlen(sBuf);
    if (!m_SMTP.Send(sBuf, nCmdLength))
      TRACE(_T("Failed in call to send QUIT command, GetLastError returns: %d\n"), GetLastError());

    //Check the reponse
    bSuccess = ReadCommandResponse(221);
    if (!bSuccess)
    {
      SetLastError(ERROR_BAD_COMMAND);
      TRACE(_T("An unexpected QUIT response was received\n"));
    }

    //Reset all the state variables
    m_bConnected = FALSE;
  }
  else
    TRACE(_T("Already disconnected from SMTP server, doing nothing\n"));
 
  //free up our socket
  m_SMTP.Close();
 
  return bSuccess;
}

BOOL CSMTPConnection::SendMessage(CSMTPMessage& Message)
{
	//For correct operation of the T2A macro, see MFC Tech Note 59
	USES_CONVERSION;

	//paramater validity checking
  ASSERT(m_bConnected); //Must be connected to send a message

  //Send the MAIL command
	ASSERT(Message.m_From.m_sEmailAddress.GetLength());
  CString sBuf;
  sBuf.Format(_T("MAIL FROM:<%s>\r\n"), Message.m_From.m_sEmailAddress);
  LPCSTR pszMailFrom = T2A((LPTSTR) (LPCTSTR) sBuf);
  int nCmdLength = strlen(pszMailFrom);
  if (!m_SMTP.Send(pszMailFrom, nCmdLength))
  {
    TRACE(_T("Failed in call to send MAIL command, GetLastError returns: %d\n"), GetLastError());
    return FALSE;
  }

  //check the response to the MAIL command
  if (!ReadCommandResponse(250))
  {
    SetLastError(ERROR_BAD_COMMAND);
    TRACE(_T("An unexpected MAIL response was received\n"));
    return FALSE;
  } 

  //Send the RCPT command, one for each recipient (includes the TO, CC & BCC recipients)

  //Must be sending to someone
  ASSERT(Message.GetNumberOfRecipients(CSMTPMessage::TO) + 
         Message.GetNumberOfRecipients(CSMTPMessage::CC) + 
         Message.GetNumberOfRecipients(CSMTPMessage::BCC));

  //First the "To" recipients
  for (int i=0; i<Message.GetNumberOfRecipients(CSMTPMessage::TO); i++)
  {
    CSMTPAddress recipient = Message.GetRecipient(i, CSMTPMessage::TO);
    if (!SendRCPTForRecipient(recipient))
      return FALSE;
  }

  //Then the "CC" recipients
  for (i=0; i<Message.GetNumberOfRecipients(CSMTPMessage::CC); i++)
  {
    CSMTPAddress recipient = Message.GetRecipient(i, CSMTPMessage::CC);
    if (!SendRCPTForRecipient(recipient))
      return FALSE;
  }

  //Then the "BCC" recipients
  for (i=0; i<Message.GetNumberOfRecipients(CSMTPMessage::BCC); i++)
  {
    CSMTPAddress recipient = Message.GetRecipient(i, CSMTPMessage::BCC);
    if (!SendRCPTForRecipient(recipient))
      return FALSE;
  }

  //Send the DATA command
  char* pszDataCommand = "DATA\r\n";
  nCmdLength = strlen(pszDataCommand);
  if (!m_SMTP.Send(pszDataCommand, nCmdLength))
  {
    TRACE(_T("Failed in call to send MAIL command, GetLastError returns: %d\n"), GetLastError());
    return FALSE;
  }

  //check the response to the DATA command
  if (!ReadCommandResponse(354))
  {
    SetLastError(ERROR_BAD_COMMAND);
    TRACE(_T("An unexpected DATA response was received\n"));
    return FALSE;
  } 

  //Send the Header
  CString sHeader = Message.GetHeader();
  char* pszHeader = T2A((LPTSTR) (LPCTSTR) sHeader);
  nCmdLength = strlen(pszHeader);
  if (!m_SMTP.Send(pszHeader, nCmdLength))
  {
    TRACE(_T("Failed in call to send the header, GetLastError returns: %d\n"), GetLastError());
    return FALSE;
  }

	//Send the Mime Header for the body
  if (Message.m_Attachments.GetSize())
  {
	  char* psBodyHeader = (_T("\r\n--#BOUNDARY#\r\n")\
		                      _T("Content-Type: text/plain; charset=us-ascii\r\n")\
									        _T("Content-Transfer-Encoding: quoted-printable\r\n\r\n"));
    nCmdLength = strlen(psBodyHeader);
    if (!m_SMTP.Send(psBodyHeader, nCmdLength))
    {
      TRACE(_T("Failed in call to send the body header, GetLastError returns: %d\n"), GetLastError());
      return FALSE;
    }
  }

  //Send the body
  char* pszBody = T2A((LPTSTR) (LPCTSTR) Message.m_sBody);
  nCmdLength = strlen(pszBody);
  if (!m_SMTP.Send(pszBody, nCmdLength))
  {
    TRACE(_T("Failed in call to send the header, GetLastError returns: %d\n"), GetLastError());
    return FALSE;
  }

  //Send all the attachments
  for (i=0; i<Message.m_Attachments.GetSize(); i++)
  {
    CSMTPAttachment* pAttachment = Message.m_Attachments.GetAt(i);

		//First send the Mime header for each attachment
		CString sContent;
		sContent.Format(_T("\r\n\r\n--#BOUNDARY#\r\n")\
		                _T("Content-Type: application/octet-stream; name=%s\r\n")\
										_T("Content-Transfer-Encoding: base64\r\n")\
										_T("Content-Disposition: attachment; filename=%s\r\n\r\n"), 
                    pAttachment->GetFilename(), pAttachment->GetTitle());

		char* pszContent = T2A((LPTSTR) (LPCTSTR) sContent);
		nCmdLength = strlen(pszContent);
		if (!m_SMTP.Send(pszContent, nCmdLength))
		{
			TRACE(_T("Failed in call to send Mime attachment header, GetLastError returns: %d\n"), GetLastError());
			return FALSE;
		}

    //Then send the encoded attachment
    if (!m_SMTP.Send(pAttachment->GetEncodedBuffer(), pAttachment->GetEncodedSize()))
    {
      TRACE(_T("Failed in call to send the attachment, GetLastError returns: %d\n"), GetLastError());
      return FALSE;
    }
  }

	//Send the final mime boundary
  if (Message.m_Attachments.GetSize())
  {
	  char* pszFinalBoundary = "\r\n--#BOUNDARY#--";
	  nCmdLength = strlen(pszFinalBoundary);
	  if (!m_SMTP.Send(pszFinalBoundary, nCmdLength))
	  {
		  TRACE(_T("Failed in call to send Mime attachment header, GetLastError returns: %d\n"), GetLastError());
		  return FALSE;
	  }
  }

  //Send the end of message indicator
  char* pszEOM = "\r\n.\r\n";
	nCmdLength = strlen(pszEOM);
  if (!m_SMTP.Send(pszEOM, nCmdLength))
  {
    TRACE(_T("Failed in call to send end of message indicator, GetLastError returns: %d\n"), GetLastError());
    return FALSE;
  }

  //check the response to the End of Message command
  if (!ReadCommandResponse(250))
  {
    SetLastError(ERROR_BAD_COMMAND);
    TRACE(_T("An unexpected end of message response was received\n"));
    return FALSE;
  } 

	return TRUE;
}

BOOL CSMTPConnection::SendRCPTForRecipient(CSMTPAddress& recipient)
{
	//For correct operation of the T2A macro, see MFC Tech Note 59
	USES_CONVERSION;

	ASSERT(recipient.m_sEmailAddress.GetLength()); //must have an email address for this recipient

  CString sBuf;
  sBuf.Format(_T("RCPT TO:<%s>\r\n"), recipient.m_sEmailAddress);
  LPTSTR pszRCPT = T2A((LPTSTR) (LPCTSTR) sBuf);

  int nCmdLength = strlen(pszRCPT);
  if (!m_SMTP.Send(pszRCPT, nCmdLength))
  {
    TRACE(_T("Failed in call to send RCPT command, GetLastError returns: %d\n"), GetLastError());
    return FALSE;
  }

  //check the response to the RCPT command
  if (!ReadCommandResponse(250))
  {
    SetLastError(ERROR_BAD_COMMAND);
    TRACE(_T("An unexpected RCPT response was received\n"));
    return FALSE;
  } 
  
  return TRUE;
}

BOOL CSMTPConnection::ReadCommandResponse(int nExpectedCode)
{
  LPSTR pszOverFlowBuffer = NULL;
  char sBuf[256];
  BOOL bSuccess = ReadResponse(sBuf, 256, "\r\n", nExpectedCode, &pszOverFlowBuffer);
  if (pszOverFlowBuffer)
    delete [] pszOverFlowBuffer;

  return bSuccess;
}

BOOL CSMTPConnection::ReadResponse(LPSTR pszBuffer, int nInitialBufSize, LPSTR pszTerminator, int nExpectedCode, LPSTR* ppszOverFlowBuffer, int nGrowBy)
{
  ASSERT(ppszOverFlowBuffer);          //Must have a valid string pointer
  ASSERT(*ppszOverFlowBuffer == NULL); //Initially it must point to a NULL string

  //must have been created first
  ASSERT(m_bConnected);

  //The local variables which will receive the data
  LPSTR pszRecvBuffer = pszBuffer;
  int nBufSize = nInitialBufSize;
  
  //retrieve the reponse using until we
	//get the terminator or a timeout occurs
	BOOL bFoundTerminator = FALSE;
	int nReceived = 0;
	DWORD dwStartTicks = ::GetTickCount();
	while (!bFoundTerminator)
	{
		//Has the timeout occured
		if ((::GetTickCount() - dwStartTicks) >	m_dwTimeout)
		{
		  pszRecvBuffer[nReceived] = '\0';
      SetLastError(WSAETIMEDOUT);
      m_sLastCommandResponse = pszRecvBuffer; //Hive away the last command reponse
			return FALSE;
		}

    //check the socket for readability
    BOOL bReadible;
    if (!m_SMTP.IsReadible(bReadible))
    {
	    pszRecvBuffer[nReceived] = '\0';
			m_sLastCommandResponse = pszRecvBuffer; //Hive away the last command reponse
			return FALSE;
    }
    else if (!bReadible) //no data to receive, just loop around
    {
      Sleep(250); //Sleep for a while before we loop around again
      continue;
    }

		//receive the data from the socket
    int nBufRemaining = nBufSize-nReceived-1; //Allows allow one space for the NULL terminator
    if (nBufRemaining<0)
      nBufRemaining = 0;
	  int nData = m_SMTP.Receive(pszRecvBuffer+nReceived, nBufRemaining);

    //Reset the idle timeout if data was received
    if (nData)
    {
			dwStartTicks = ::GetTickCount();

      //Increment the count of data received
		  nReceived += nData;							   
    }

    //If an error occurred receiving the data
		if (nData == SOCKET_ERROR)
		{
      //NULL terminate the data received
      if (pszRecvBuffer)
		    pszBuffer[nReceived] = '\0';

      m_sLastCommandResponse = pszRecvBuffer; //Hive away the last command reponse
		  return FALSE; 
		}
		else
		{
      //NULL terminate the data received
      if (pszRecvBuffer)
		    pszRecvBuffer[nReceived] = '\0';

      if (nBufRemaining-nData == 0) //No space left in the current buffer
      {
        //Allocate the new receive buffer
        nBufSize += nGrowBy; //Grow the buffer by the specified amount
        LPSTR pszNewBuf = new char[nBufSize];

        //copy the old contents over to the new buffer and assign 
        //the new buffer to the local variable used for retreiving 
        //from the socket
        if (pszRecvBuffer)
          strcpy(pszNewBuf, pszRecvBuffer);
        pszRecvBuffer = pszNewBuf;

        //delete the old buffer if it was allocated
        if (*ppszOverFlowBuffer)
          delete [] *ppszOverFlowBuffer;
        
        //Remember the overflow buffer for the next time around
        *ppszOverFlowBuffer = pszNewBuf;        
      }
		}

    //Check to see if the terminator character(s) have been found
		bFoundTerminator = (strstr(pszRecvBuffer, pszTerminator) != NULL);
	}

	//Remove the terminator from the response data
  pszRecvBuffer[nReceived - strlen(pszTerminator)] = '\0';

  //determine if the response is an error
	char sCode[4];
	strncpy(sCode, pszRecvBuffer, 3);
	sCode[3] = '\0';
	sscanf(sCode, "%d", &m_nLastCommandResponseCode);
	BOOL bSuccess = (m_nLastCommandResponseCode == nExpectedCode);

  if (!bSuccess)
  {
    SetLastError(WSAEPROTONOSUPPORT);
    m_sLastCommandResponse = pszRecvBuffer; //Hive away the last command reponse
  }

  return bSuccess;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -