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

📄 sendmail.c

📁 SMTP protocol implementation for sending emails
💻 C
字号:
/////////////////////////////////////////////////////////////////
// SendMail.cpp - implements the functions for the SendMail DLL.
// Author - Arnab Bhaduri.
/////////////////////////////////////////////////////////////////

// defines //////////////////////////////////////////////////////

#define STRICT
#define	WIN32_LEAN_AND_MEAN
#define	NOGDI
#define	NOIME

#define	VERIFY_RET_VAL( arg ) \
            { int nRet = arg; if( nRet ) return nRet; }

// includes /////////////////////////////////////////////////////

#include <windows.h>
#include <winsock.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/timeb.h>

#include "sendmail.h"

// private functions - used internally //////////////////////////

int SendMailMessage( SENDMAIL *pMail ); 
int Send( SOCKET s, const char *lpszBuff, int nLen, int nFlags );
int Receive( SOCKET s, LPTSTR lpszBuff, int nLenMax, int nFlags,
			  LPCTSTR lpszReplyCode );
void LogMessage( LPCTSTR lpszMsg );

// Static variables /////////////////////////////////////////////

static BOOL   gbLog  = FALSE;
static HANDLE ghFile = INVALID_HANDLE_VALUE;
static char   gszMailerID[] = "X-Mailer: SendMail DLL V1.0\r\n";
static char   gszLogFile[]  = "SendMail.Log";


// SendMail - sends an SMTP mail message to specified host. This
// is the only exported function from this DLL.
/////////////////////////////////////////////////////////////////
__declspec ( dllexport )
BOOL WINAPI SendMail( SENDMAIL *pMail, int *pResult )
{
WORD    wVersion = MAKEWORD( 1, 1 );
WSADATA wsaData;
int     nRet;

// check for required parameters
if( pMail == NULL || pResult == NULL ||	pMail->lpszHost == NULL ||
    pMail->lpszRecipient == NULL ||	pMail->lpszSubject == NULL  ||
    pMail->lpszMessage == NULL )
    {
    if( pResult )
        *pResult = WSAEINVAL;
    return FALSE;
    }

if( (*pResult = WSAStartup(wVersion, &wsaData)) )
    return FALSE;

// open log file if specified
if( pMail->bLog )
    {
    char szLogPath[ MAX_PATH + 1 ];

    *szLogPath = '\0';
    GetTempPath( MAX_PATH, szLogPath );
    strcat( szLogPath, gszLogFile );

    ghFile = CreateFile( szLogPath, GENERIC_WRITE, FILE_SHARE_READ,
                         NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
                         NULL );

    if( ghFile != INVALID_HANDLE_VALUE )
        gbLog = TRUE;
    }

// try to send the message
nRet = SendMailMessage( pMail );

if( nRet != 0 )
    {
    if( gbLog )
        {
        char szMsg[ MAX_LINE_SIZE ];

        if( nRet < 0 )
            sprintf( szMsg, "SMTP error %d in SendMail.\n",
                     -nRet );
        else
            sprintf( szMsg, "Socket error %d in SendMail.\n",
                     nRet );
        LogMessage( szMsg );
        }
    }

// cleanup socket lib and log file
WSACleanup();
if( ghFile != INVALID_HANDLE_VALUE )
    {
    CloseHandle( ghFile );
    ghFile = INVALID_HANDLE_VALUE;
    gbLog  = FALSE;
    }

*pResult = nRet;
return ( *pResult == 0 );
}


// SendMailMessage - actually sends the message.This is a private
// function.
/////////////////////////////////////////////////////////////////
int SendMailMessage( SENDMAIL *pMail )
{
char   szBuff[ MAX_LINE_SIZE + 1 ]; // transmit/receive buffer
char   szUser[ MAX_NAME_SIZE + 1 ]; // user name buffer
char   szName[ MAX_NAME_SIZE + 1 ]; // host name buffer
DWORD  dwSize = MAX_NAME_SIZE;
SOCKET s;

struct hostent    *ph;
struct sockaddr_in addr;

char         szTime[ MAX_NAME_SIZE + 1 ]; // time related vars
time_t       tTime;
struct tm   *ptm;
struct timeb tbTime;

// connect to the SMTP port on remote host
if( (s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET )
    return WSAGetLastError();

if( isdigit(*pMail->lpszHost) && strchr(pMail->lpszHost, '.') )
    {
    unsigned long iaddr = inet_addr( pMail->lpszHost );
    ph = gethostbyaddr( (const char *)&iaddr, 4, PF_INET );
    }
else
    ph = gethostbyname( pMail->lpszHost );

if( ph == NULL )
    return WSAGetLastError();

addr.sin_family = AF_INET;
addr.sin_port   = htons( SMTP_PORT );
memcpy( &addr.sin_addr, ph->h_addr_list[0],
        sizeof(struct in_addr) );

if( connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr)) )
    return WSAGetLastError();

// receive signon message
VERIFY_RET_VAL( Receive( s, szBuff, MAX_LINE_SIZE, 0, "220" ); );

// get user name and local host name
GetUserName( szUser, &dwSize );
gethostname( szName, MAX_NAME_SIZE );

// send HELO message
sprintf( szBuff, "HELO %s\r\n", szName );
VERIFY_RET_VAL( Send( s, szBuff, strlen(szBuff), 0 ); )
VERIFY_RET_VAL( Receive( s, szBuff, MAX_LINE_SIZE, 0, "250" ); )

// send MAIL message
if( pMail->lpszSender )
    {
    sprintf( szBuff, "MAIL FROM: <%s", pMail->lpszSender );
    if( strchr( pMail->lpszSender, '@' ) )
        strcat( szBuff, ">\r\n" );
    else
        sprintf( szBuff + strlen( szBuff ), "@%s>\r\n", szName );
    }
else
    sprintf( szBuff, "MAIL FROM:<%s@%s>\r\n", szUser, szName );

VERIFY_RET_VAL( Send( s, szBuff, strlen(szBuff), 0 ); )
VERIFY_RET_VAL( Receive( s, szBuff, MAX_LINE_SIZE, 0, "250" ); )

// send RCPT message
sprintf( szBuff, "RCPT TO: <%s>\r\n", pMail->lpszRecipient );
VERIFY_RET_VAL( Send( s, szBuff, strlen(szBuff), 0 ); )
VERIFY_RET_VAL( Receive( s, szBuff, MAX_LINE_SIZE, 0, "25" ); )

// send DATA message
sprintf( szBuff, "DATA\r\n" );
VERIFY_RET_VAL( Send( s, szBuff, strlen(szBuff), 0 ); )
VERIFY_RET_VAL( Receive( s, szBuff, MAX_LINE_SIZE, 0, "354" ); )

// construct date string
tTime = time( NULL );
ptm   = localtime( &tTime );

strftime( szTime, MAX_NAME_SIZE, "%a, %d %b %Y %H:%M:%S %Z", ptm );

// find time zone offset and correct for DST
ftime( &tbTime );
if( tbTime.dstflag )
    tbTime.timezone -= 60;

sprintf( szTime + strlen(szTime), " %2.2d%2.2d",
         -tbTime.timezone / 60, tbTime.timezone % 60 );

// send mail headers
// Date:
sprintf( szBuff, "Date: %s\r\n", szTime );
VERIFY_RET_VAL( Send( s, szBuff, strlen(szBuff), 0 ); )

// X-Mailer:
VERIFY_RET_VAL( Send( s, gszMailerID, strlen(gszMailerID), 0 ); )

// Message-ID:
if( pMail->lpszMessageID )
    {
    sprintf( szBuff, "Message-ID: %s\r\n", pMail->lpszMessageID );
    VERIFY_RET_VAL( Send( s, szBuff, strlen(szBuff), 0 ); )
    }

// To:
sprintf( szBuff, "To: %s", pMail->lpszRecipient );
if( pMail->lpszRecipientName )
    sprintf( szBuff + strlen(szBuff), " (%s)\r\n",
             pMail->lpszRecipientName );
else
    strcat( szBuff, "\r\n" );
VERIFY_RET_VAL( Send( s, szBuff, strlen(szBuff), 0 ); )

// From:
if( pMail->lpszSender )
    {
    sprintf( szBuff, "From: %s", pMail->lpszSender );
    if( pMail->lpszSenderName )
        sprintf( szBuff + strlen(szBuff), " (%s)\r\n",
                 pMail->lpszSenderName );
    else
        strcat( szBuff, "\r\n" );
    }
else
    sprintf( szBuff, "From: %s@%s\r\n", szUser, szName );
VERIFY_RET_VAL( Send( s, szBuff, strlen(szBuff), 0 ); )

// Reply-To:
if( pMail->lpszReplyTo )
    {
    sprintf( szBuff, "Reply-To: %s", pMail->lpszReplyTo );
    if( pMail->lpszReplyToName )
    sprintf( szBuff + strlen(szBuff), " (%s)\r\n",
             pMail->lpszReplyToName );
    else
        strcat( szBuff, "\r\n" );
    VERIFY_RET_VAL( Send( s, szBuff, strlen(szBuff), 0 ); )
	}

// Subject:
sprintf( szBuff, "Subject: %s\r\n", pMail->lpszSubject );
VERIFY_RET_VAL( Send( s, szBuff, strlen(szBuff), 0 ); )

/////////////////////////////////////////////////////////
// 08/13/98 rlb
// empty line needed after headers, RFC822
strcpy(szBuff, "\r\n");
VERIFY_RET_VAL( Send( s, szBuff, strlen(szBuff), 0 ); )
/////////////////////////////////////////////////////////


// send message text
VERIFY_RET_VAL( Send( s, pMail->lpszMessage, \
                      strlen(pMail->lpszMessage), 0 ); )

// send message terminator and receive reply
VERIFY_RET_VAL( Send( s, "\r\n.\r\n", 5, 0 ); )
VERIFY_RET_VAL( Receive( s, szBuff, MAX_LINE_SIZE, 0, "250" ); )

// send QUIT message
sprintf( szBuff, "QUIT\r\n" );
VERIFY_RET_VAL( Send( s, szBuff, strlen(szBuff), 0 ); )
VERIFY_RET_VAL( Receive( s, szBuff, MAX_LINE_SIZE, 0, "221" ); )

closesocket( s );
return 0;
}


// Send - send the request to the SMTP server, and handle errors.
/////////////////////////////////////////////////////////////////
int Send( SOCKET s, const char *lpszBuff, int nLen, int nFlags )
{
int nCnt = 0;

while( nCnt < nLen )
    {
    int nRes = send( s, lpszBuff + nCnt, nLen - nCnt, nFlags );
    if( nRes == SOCKET_ERROR )
        return WSAGetLastError();
    else
        nCnt += nRes;
    }

if( gbLog )
    LogMessage( lpszBuff );

return 0;
}


// Receive - receive a reply from the SMTP server, and verify that
// the request has succeeded by checking against the specified
// reply code.
/////////////////////////////////////////////////////////////////
int Receive( SOCKET s, LPTSTR lpszBuff, int nLenMax, int nFlags,
			  LPCTSTR lpszReplyCode )
{
LPTSTR p;
int    nRes = recv( s, lpszBuff, nLenMax, nFlags );

if( nRes == SOCKET_ERROR )
    return WSAGetLastError();
else
    *( lpszBuff + nRes ) = '\0';

if( gbLog )
    LogMessage( lpszBuff );

// check reply code for success/failure
p = strtok( lpszBuff, "\n" );
while( p )
    {
    if( *(p + 3) == ' ' )
        {
        if( !strncmp(p, lpszReplyCode, strlen(lpszReplyCode)) )
            return 0;
        else
            {
            int nErr = 1;

            sscanf( p, "%d", &nErr );
            return -nErr;
            }
        }
    else
        p = strtok( NULL, "\n" );
    }

return -1;
}


// LogMessage - log messages to log file.
/////////////////////////////////////////////////////////////////
void LogMessage( LPCTSTR lpszMsg )
{
DWORD dwRet;

if( ghFile != INVALID_HANDLE_VALUE )
    WriteFile( ghFile, lpszMsg, strlen(lpszMsg), &dwRet, NULL );
}

// End //

⌨️ 快捷键说明

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