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

📄 smtp.cpp

📁 实现smtp的发送邮件的功能
💻 CPP
📖 第 1 页 / 共 2 页
字号:
							sDate,
							m_sXMailer);


	//Add the optional Reply-To Field
	if (m_ReplyTo.m_sEmailAddress.GetLength())
	{
		CString sReply;
		sReply.Format(_T("Reply-To: %s\r\n"), m_ReplyTo.GetRegularFormat());
		sBuf += sReply;
	}

	//Add the optional fields if attachments are included
	if (m_Attachments.GetSize())
		sBuf += _T("MIME-Version: 1.0\r\nContent-type: multipart/mixed; boundary=\"#BOUNDARY#\"\r\n");

	sBuf += _T("\r\n");

	//Return the result
	return sBuf;
}

void CSMTPMessage::FixSingleDot(CString& sBody)
{
  int nFind = sBody.Find(_T("\n."));
  if (nFind != -1)
  {
	  CString sLeft(sBody.Left(nFind+1));
	  CString sRight(sBody.Right(sBody.GetLength()-(nFind+1)));
	  FixSingleDot(sRight);
	  sBody = sLeft + _T(".") + sRight;
  }
}

void CSMTPMessage::AddBody(const CString& sBody)
{
  m_sBody = sBody;

  //Fix the case of a single dot on a line in the message body
  FixSingleDot(m_sBody);
}

BOOL CSMTPMessage::AddMultipleRecipients(const CString& sRecipients)
{
	ASSERT(sRecipients.GetLength()); //An empty string is now allowed
	
	//Loop through the whole string, adding recipients as they are encountered
	int length = sRecipients.GetLength();
	TCHAR* buf = new TCHAR[length + 1];	// Allocate a work area (don't touch parameter itself)
	_tcscpy(buf, sRecipients);
	for (int pos=0, start=0; pos<=length; pos++)
	{
		//Valid separators between addresses are ',' or ';'
		if ((buf[pos] == _T(',')) || (buf[pos] == _T(';')) || (buf[pos] == 0))
		{
			buf[pos] = 0;	//Redundant when at the end of string, but who cares.
      CString sTemp(&buf[start]);

			// Now divide the substring into friendly names and e-mail addresses
      CSMTPAddress To;
			int nMark = sTemp.Find(_T('<'));
			if (nMark >= 0)
			{
				To.m_sFriendlyName = sTemp.Left(nMark);
				int nMark2 = sTemp.Find(_T('>'));
				if (nMark2 < nMark)
				{
          //An invalid string was sent in, fail the call
					delete[] buf;
          SetLastError(ERROR_INVALID_DATA);
          TRACE(_T("An error occurred while parsing the recipients string\n"));
					return FALSE;
				}
				// End of mark at closing bracket or end of string
				nMark2 > -1 ? nMark2 = nMark2 : nMark2 = sTemp.GetLength() - 1;
				To.m_sEmailAddress = sTemp.Mid(nMark + 1, nMark2 - (nMark + 1));
			}
			else
			{
				To.m_sEmailAddress = sTemp;
				To.m_sFriendlyName = _T(_T(""));
			}

      //Finally add the new recipient to the array of recipients
			To.m_sEmailAddress.TrimRight();
			To.m_sEmailAddress.TrimLeft();
			To.m_sFriendlyName.TrimRight();
			To.m_sFriendlyName.TrimLeft();
			AddRecipient(To);
			start = pos + 1;
		}
	}
	delete[] buf;
	return TRUE;
}







CSMTPConnection::CSMTPConnection()
{
  m_bConnected = FALSE;
#ifdef _DEBUG
  m_dwTimeout = 20000; //default timeout of 20 seconds when debugging
#else
  m_dwTimeout = 2000;  //default timeout of 2 seconds for normal release code
#endif
}

CSMTPConnection::~CSMTPConnection()
{
  if (m_bConnected)
    Disconnect();
}

BOOL CSMTPConnection::Connect(LPCTSTR pszHostName, int nPort)
{
	//For correct operation of the T2A macro, see MFC Tech Note 59
	USES_CONVERSION;

	//paramater validity checking
  ASSERT(pszHostName);

  //Create the socket
  if (!m_SMTP.Create())
  {
    TRACE(_T("Failed to create client socket, GetLastError returns: %d\n"), GetLastError());
    return FALSE;
  }

  //Connect to the SMTP Host
  if (!m_SMTP.Connect(pszHostName, nPort))
  {
    TRACE(_T("Could not connect to the SMTP server %s on port %d, GetLastError returns: %d\n"), pszHostName, nPort, GetLastError());
    return FALSE;
  }
  else
  {
    //We're now connected !!
    m_bConnected = TRUE;

    //check the response to the login
    if (!ReadCommandResponse(220))
    {
      TRACE(_T("An unexpected SMTP login response was received\n"));
      Disconnect();
      return FALSE;
    }

		//retreive the localhost name
    char sHostName[100];
		gethostname(sHostName, sizeof(sHostName));
    TCHAR* pszHostName = A2T(sHostName);

    //Send the HELO command
		CString sBuf;
		sBuf.Format(_T("HELO %s\r\n"), pszHostName);
    LPCSTR pszData = T2A((LPTSTR) (LPCTSTR) sBuf);
    int nCmdLength = strlen(pszData);
    if (!m_SMTP.Send(pszData, nCmdLength))
    {
      Disconnect();
      TRACE(_T("An unexpected error occurred while sending the HELO command\n"));
      return FALSE;
    }
		//check the response to the HELO command
    if (!ReadCommandResponse(250))
    {
      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
  ASSERT(Message.GetNumberOfRecipients()); //Must have at least one recipient for the message
  for (int i=0; i<Message.GetNumberOfRecipients(); i++)
  {
    CSMTPAddress recipient = Message.GetRecipient(i);
		ASSERT(recipient.m_sEmailAddress.GetLength()); //must have an email address for this recipient
    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 MAIL command, GetLastError returns: %d\n"), GetLastError());
      return FALSE;
    }

    //check the response to each RCPT command
    if (!ReadCommandResponse(250))
    {
      SetLastError(ERROR_BAD_COMMAND);
      TRACE(_T("An unexpected RCPT response was received\n"));
      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->GetFilename());

		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::ReadCommandResponse(int nExpectedCode)
{
	char sBuf[1000];
	return ReadResponse(sBuf, sizeof(sBuf), "\r\n", nExpectedCode);
}

BOOL CSMTPConnection::ReadResponse(LPSTR pszBuffer, int nBuf, LPSTR pszTerminator, int nExpectedCode)
{
	//paramater validity checking
	ASSERT(pszBuffer);
	ASSERT(nBuf);

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

  //retrieve the reponse using until we
	//get the terminator or a timeout occurs
	BOOL bFoundTerminator = FALSE;
	int nReceived = 0;
	DWORD dwStartTicks = ::GetTickCount();
	while (!bFoundTerminator)
	{
		//timeout has occured
		if ((::GetTickCount() - dwStartTicks) >	m_dwTimeout)
		{
		  pszBuffer[nReceived] = '\0';
      SetLastError(WSAETIMEDOUT);
      m_sLastCommandResponse = pszBuffer; //Hive away the last command reponse
			return FALSE;
		}

    //check the socket for readability
    BOOL bReadible;
    if (!m_SMTP.IsReadible(bReadible))
    {
	    pszBuffer[nReceived] = '\0';
			m_sLastCommandResponse = pszBuffer; //Hive away the last command reponse
			return FALSE;
    }
    else if (!bReadible) //no data to receive, just loop around
    {
      Sleep(0); //Yield up our time slice to other running apps
                //helps to improve performance of system
      continue;
    }

		//receive the data from the socket
	  int nData = m_SMTP.Receive(pszBuffer+nReceived, nBuf-nReceived);
		if (nData == SOCKET_ERROR)
		{
		  pszBuffer[nReceived] = '\0';
      m_sLastCommandResponse = pszBuffer; //Hive away the last command reponse
		  return FALSE; 
		}
		else
		{
      if (nData)
			  dwStartTicks = ::GetTickCount(); //Reset the idle timeout
		  nReceived += nData;							   //Increment the count of data received
		}

		pszBuffer[nReceived] = '\0';	//temporarily NULL terminate the string
																	//so that strstr works
		bFoundTerminator = (strstr(pszBuffer, pszTerminator) != NULL);
	}

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

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

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

  return bSuccess;
}

⌨️ 快捷键说明

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