ESMTP Class
By Brandon W. Yuille
Well, this is my first post on the PT Development Blog, so I thought I would start with some code that I know many will find useful.
This is a class I worte for a billing system to send out emails to customers when their invoices were ready to be viewed online.
Hope you'll be able to make use of this class!
Class Declaration
/**************************************************************
Name: ESMTP Class Ver: 1.0.1.1 Author: Brandon W. YuilleDesc: This class assumes MFC is used and all socket
initializations have taken place in
CWinApp::InitInstance(). Please don't consider this code
as production code for any sort of SMTP client. This is
simply provided so you can acomplish some simple tasks.
If you make modifications to this code that are useful,
please share them with others!This class is free to use by anyone.
Copyright (C) 2006 Photon Technologies
**************************************************************/
#pragma once#include <vector>
class CESMTP
{
public:
CESMTP(void);
~CESMTP(void);void AddRecipient(CString address, CString name = "");
void SetFrom(CString address, CString name = "");
void SetSubject(CString subject);
void SetESMTPServerAddress(CString address);
void SetESMTPServerPort(int port = 25);
void SetMsgBody(CString data);BOOL SendMsg();
protected:
BOOL RecvMessage(SOCKET *psock, CString requiredcode);struct NAMEADDR
{
CString name;
CString addr;
};std::vector<NAMEADDR> m_vto;
NAMEADDR m_from;
CString m_serveraddr;
int m_serverport;
CString m_data;
CString m_subject;
};
Class Implementation
#include "StdAfx.h"
#include ".\esmtp.h"CESMTP::CESMTP(void)
{
m_serverport = 25;
}CESMTP::~CESMTP(void)
{
}void CESMTP::AddRecipient(CString address, CString name)
{
NAMEADDR na;
na.addr = address;
na.name = name;m_vto.push_back(na);
}void CESMTP::SetFrom(CString address, CString name)
{
m_from.addr = address;
m_from.name = name;
}void CESMTP::SetSubject(CString subject)
{
m_subject = subject;
}void CESMTP::SetESMTPServerAddress(CString address)
{
m_serveraddr = address;
}void CESMTP::SetESMTPServerPort(int port)
{
m_serverport = port;
}void CESMTP::SetMsgBody(CString data)
{
data.Replace("\r\n.\r\n", "\r\n..\r\n");
if(data.Left(3) == ".\r\n")
data.Insert(0, ".");m_data = data;
}BOOL CESMTP::SendMsg()
{
SOCKET sock;
SOCKADDR_IN saremote;
CString SendBuf;// Create the TCP/IP CCCP socket.
if((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
return FALSE;
}saremote.sin_family = AF_INET;
saremote.sin_port = htons((short)m_serverport);
if(inet_addr(m_serveraddr.GetString()) == INADDR_NONE)
{
HOSTENT *hp;
hp = gethostbyname(m_serveraddr.GetString());
saremote.sin_addr.s_addr = *((unsigned long*)hp->h_addr);
}
else
{
saremote.sin_addr.s_addr = inet_addr(m_serveraddr.GetString());
}// Connect to CCCP server.
if(connect(sock, (SOCKADDR*)&saremote, sizeof(saremote)) == SOCKET_ERROR)
{
return FALSE;
}// Recieve Banner
if(!RecvMessage(&sock, "220"))
{
closesocket(sock);
return FALSE;
}// Send EHLO
SendBuf = "EHLO\r\n";
if(send(sock, SendBuf, SendBuf.GetLength(), 0) == SOCKET_ERROR)
{
closesocket(sock);
return FALSE;
}
// Recieve OK
if(!RecvMessage(&sock, "250"))
{
closesocket(sock);
return FALSE;
}// Send MAIL FROM:<address@domain.com>
SendBuf = "MAIL FROM:" + m_from.addr + "\r\n";
if(send(sock, SendBuf, SendBuf.GetLength(), 0) == SOCKET_ERROR)
{
closesocket(sock);
return FALSE;
}
// Recieve OK
if(!RecvMessage(&sock, "250"))
{
closesocket(sock);
return FALSE;
}for(int i = 0; i < m_vto.size(); i++)
{
// Send RCPT TO:<address@domain.com>
SendBuf = "RCPT TO:" + m_vto.at(i).addr + "\r\n";
if(send(sock, SendBuf, SendBuf.GetLength(), 0) == SOCKET_ERROR)
{
closesocket(sock);
return FALSE;
}
// Recieve OK
if(!RecvMessage(&sock, "250"))
{
closesocket(sock);
return FALSE;
}
}// Send DATA
SendBuf = "DATA\r\n";
if(send(sock, SendBuf, SendBuf.GetLength(), 0) == SOCKET_ERROR)
{
closesocket(sock);
return FALSE;
}
// Recieve Begin DATA
if(!RecvMessage(&sock, "354"))
{
closesocket(sock);
return FALSE;
}CString MsgBody;
MsgBody += "Subject: " + m_subject + "\r\n";
MsgBody += "To: ";
for(int i = 0; i < m_vto.size(); i++)
{
MsgBody += " " + m_vto.at(i).name + " <" + m_vto.at(i).addr + ">;";
}
MsgBody += "\r\n\r\n";
// Add the message data
MsgBody += m_data;
// End the message
MsgBody += "\r\n.\r\n";SendBuf = MsgBody;
if(send(sock, SendBuf, SendBuf.GetLength(), 0) == SOCKET_ERROR)
{
closesocket(sock);
return FALSE;
}
// Recieve OK
if(!RecvMessage(&sock, "250"))
{
closesocket(sock);
return FALSE;
}SendBuf = "QUIT\r\n";
if(send(sock, SendBuf, SendBuf.GetLength(), 0) == SOCKET_ERROR)
{
closesocket(sock);
return FALSE;
}
// Recieve Connection Closed
if(!RecvMessage(&sock, "221"))
{
closesocket(sock);
return FALSE;
}closesocket(sock);
return TRUE;
}BOOL CESMTP::RecvMessage(SOCKET *psock, CString requiredcode)
{
char szBuf[1025];
CString Buffer;
CString MsgCode;
int BufLen = 0;
int icount = 0;while((BufLen = recv(*psock, szBuf, 1024, 0)) > 0)
{
szBuf[BufLen] = '\0';
Buffer += szBuf;if(icount == 0)
MsgCode = Buffer.Left(3);if(Buffer.Find(MsgCode + " ") != -1)
break;icount++;
}if(MsgCode == requiredcode)
return TRUE;return FALSE;
}
