📄 smtp.cpp
字号:
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 + -