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

📄 smtp.cpp

📁 提供发送电子邮件的SMTP协议
💻 CPP
📖 第 1 页 / 共 3 页
字号:
      pszOut[nOutPos++] = *cp++;
      if (*cp) 
        pszOut[nOutPos++] = *cp;
      break;
    }
    case 1:
    {
      int c1 = pszIn[nInPos] & 0xFF;
      pszOut[nOutPos++] = m_base64tab[(c1 & 0xFC) >> 2];
      pszOut[nOutPos++] = m_base64tab[((c1 & 0x03) << 4)];
      pszOut[nOutPos++] = '=';
      pszOut[nOutPos++] = '=';
      cp = EOL;
      pszOut[nOutPos++] = *cp++;
      if (*cp) 
        pszOut[nOutPos++] = *cp;
      break;
    }
    case 2:
    {
      int c1 = pszIn[nInPos++] & 0xFF;
      int c2 = pszIn[nInPos] & 0xFF;
      pszOut[nOutPos++] = m_base64tab[(c1 & 0xFC) >> 2];
      pszOut[nOutPos++] = m_base64tab[((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4)];
      pszOut[nOutPos++] = m_base64tab[((c2 & 0x0F) << 2)];
      pszOut[nOutPos++] = '=';
      cp = EOL;
      pszOut[nOutPos++] = *cp++;
      if (*cp) 
        pszOut[nOutPos++] = *cp;
      break;
    }
    default: 
    {
      ASSERT(FALSE); 
      break;
    }
  }
  pszOut[nOutPos] = 0;
  *nOutLen = nOutPos;
  return TRUE;
}





CSMTPMessage::CSMTPMessage() : m_sXMailer(_T("CSMTPConnection v1.3"))
{
}

CSMTPMessage::~CSMTPMessage()
{
}

int CSMTPMessage::GetNumberOfRecipients(RECIPIENT_TYPE RecipientType) const
{
  int nSize = 0;
  switch (RecipientType)
  {
    case TO:  nSize = m_ToRecipients.GetSize();  break;
    case CC:  nSize = m_CCRecipients.GetSize();  break;
    case BCC: nSize = m_BCCRecipients.GetSize(); break;
    default: ASSERT(FALSE);                      break;
  }

	return nSize;
}

int CSMTPMessage::AddRecipient(CSMTPAddress& recipient, RECIPIENT_TYPE RecipientType)
{
  int nIndex = -1;
  switch (RecipientType)
  {
    case TO:  nIndex = m_ToRecipients.Add(recipient);  break;
    case CC:  nIndex = m_CCRecipients.Add(recipient);  break;
    case BCC: nIndex = m_BCCRecipients.Add(recipient); break;
    default: ASSERT(FALSE);                            break;
  }

  return nIndex;
}

void CSMTPMessage::RemoveRecipient(int nIndex, RECIPIENT_TYPE RecipientType)
{
  switch (RecipientType)
  {
    case TO:  m_ToRecipients.RemoveAt(nIndex);  break;
    case CC:  m_CCRecipients.RemoveAt(nIndex);  break;
    case BCC: m_BCCRecipients.RemoveAt(nIndex); break;
    default:  ASSERT(FALSE);                    break;
  }
}

CSMTPAddress CSMTPMessage::GetRecipient(int nIndex, RECIPIENT_TYPE RecipientType) const
{
  CSMTPAddress address;

  switch (RecipientType)
  {
    case TO:  address = m_ToRecipients.GetAt(nIndex);  break;
    case CC:  address = m_CCRecipients.GetAt(nIndex);  break;
    case BCC: address = m_BCCRecipients.GetAt(nIndex); break;
    default: ASSERT(FALSE);                            break;
  }

  return address;
}

int CSMTPMessage::AddAttachment(CSMTPAttachment* pAttachment)
{
  ASSERT(pAttachment->GetFilename().GetLength()); //an empty filename !
	return m_Attachments.Add(pAttachment);
}

void CSMTPMessage::RemoveAttachment(int nIndex)
{
	m_Attachments.RemoveAt(nIndex);
}

CSMTPAttachment* CSMTPMessage::GetAttachment(int nIndex) const
{
	return m_Attachments.GetAt(nIndex);
}

int CSMTPMessage::GetNumberOfAttachments() const
{
	return m_Attachments.GetSize();
}

CString CSMTPMessage::GetHeader() const
{
  //Form the Timezone info which will form part of the Date header
  TIME_ZONE_INFORMATION tzi;
  int nTZBias;
  if (GetTimeZoneInformation(&tzi) == TIME_ZONE_ID_DAYLIGHT)
    nTZBias = tzi.Bias + tzi.DaylightBias;
  else
    nTZBias = tzi.Bias;
  CString sTZBias;
  sTZBias.Format(_T("%+.2d%.2d"), -nTZBias/60, nTZBias%60);

  //Create the "Date:" part of the header
  CTime now(CTime::GetCurrentTime());
  CString sDate(now.Format(_T("%a, %d %b %Y %H:%M:%S ")));
  sDate += sTZBias;

  //Create the "To:" part of the header
  CString sTo;
  for (int i=0; i<GetNumberOfRecipients(TO); i++)
  {
    CSMTPAddress recipient = GetRecipient(i, TO);
    if (i)
 		  sTo += _T(",");
    sTo += recipient.GetRegularFormat();
  }

  //Create the "Cc:" part of the header
  CString sCc;
  for (i=0; i<GetNumberOfRecipients(CC); i++)
  {
    CSMTPAddress recipient = GetRecipient(i, CC);
    if (i)
 		  sCc += _T(",");
    sCc += recipient.GetRegularFormat();
  }

  //No Bcc info added in header

	//Stick everything together
	CString sBuf;
  if (sCc.GetLength())
	  sBuf.Format(_T("From: %s\r\n")\
                _T("To: %s\r\n")\
                _T("Cc: %s\r\n")\
							  _T("Subject: %s\r\n")\
							  _T("Date: %s\r\n")\
							  _T("X-Mailer: %s\r\n"), 
							  m_From.GetRegularFormat(),
                sTo, 
                sCc,
							  m_sSubject,
							  sDate,
							  m_sXMailer);
  else
	  sBuf.Format(_T("From: %s\r\n")\
                _T("To: %s\r\n")\
							  _T("Subject: %s\r\n")\
							  _T("Date: %s\r\n")\
							  _T("X-Mailer: %s\r\n"), 
							  m_From.GetRegularFormat(),
                sTo, 
							  m_sSubject,
							  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");
  else
		// avoid long textual message being automatically converted by the server:
	  sBuf += _T("MIME-Version: 1.0\r\nContent-type: text/plain; charset=US-ASCII\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, RECIPIENT_TYPE RecipientType)
{
	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();
      if (To.m_sEmailAddress.GetLength())
        AddRecipient(To, RecipientType);

      //Move on to the next position
			start = pos + 1;
		}
	}
	delete[] buf;
	return TRUE;
}







CSMTPConnection::CSMTPConnection()
{
  m_bConnected = FALSE;
#ifdef _DEBUG
  m_dwTimeout = 60000; //default timeout of 60 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))
    {

⌨️ 快捷键说明

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