Click to See Complete Forum and Search --> : C++ sending Email


abc_master
December 12th, 2001, 11:00 PM
How can you send emails in C++ by using system commands in Unix?. I have heard of mailx. what does it do? and can it help solve my problem?

Axter
December 13th, 2001, 01:29 PM
Here's a class that can do what you need.
I added two example functions at the end.

#include <stdio.h>

#ifdef WIN32
#include <afxsock.h>
#include <winsock.h>
#pragma warning(disable:4786)
#else //WIN32
typedef unsigned int SOCKET;
#endif //WIN32

#include <string>
#include <fstream>
#include <list>
#include <time.h>
#include <ctype.h>

class GeneralSendMailClass
{
public:
class EmailAddr
{
public:
EmailAddr(const std::string &EmailID, std::string UserName)
: m_EmailID(EmailID), m_UserName(UserName)
{
}
EmailAddr(const char*EmailID)
: m_EmailID(EmailID), m_UserName("")
{
}
const std::string m_EmailID;
const std::string m_UserName;
};

enum {SMTP_OUTGOING_MAIL_PORT = 25, BASE64_MAXLINE = 76, MAX_LINE_SIZE = 4094, AUTHENTICATION_PORT = 113};
enum LoginMethod{AUTH_LOGIN_METHOD, LOGIN_PLAIN_METHOD};
GeneralSendMailClass(std::string X_Mailer = "X-Mailer: GeneralSendMailClass By David Maisonave\r\n", std::string X_Phone = "")
:m_socket(NULL), m_InitiateGood(true),m_UniqueContentID(0),
m_X_Mailer(X_Mailer), m_X_Phone(X_Phone), Auth_UserID(""), Auth_Password(""), m_LoginMethod(AUTH_LOGIN_METHOD)
{
#ifdef WIN32
WORD wVersion = MAKEWORD( 1, 1 );
WSADATA wsaData;
if (WSAStartup(wVersion, &wsaData)) m_InitiateGood=false;
else m_InitiateGood = true;
#endif //WIN32
}
~GeneralSendMailClass()
{
#ifdef WIN32
WSACleanup();
#endif //WIN32
}
std::string SendEmail(const EmailAddr &To,
const std::string &Subject,
const std::string &Body,
const std::string &EmailSenderHostName,
const std::string &EmailSenderUserID,
const EmailAddr &Sender = EmptyEmailAddr,
const std::list<EmailAddr> *CC_List = NULL,
const std::list<EmailAddr> *BCC_List = NULL,
const std::list<std::string> *AttachmentPath_List = NULL,
const EmailAddr &ReplyToAddr = EmptyEmailAddr,
const std::string *MessageID = NULL)
{
if (!m_InitiateGood) return "Error: GeneralSendMailClass failed to initiate properly";
if( (m_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET )
return "Error: socket function return INVALID_SOCKET";
std::string ReturnValue = NO_ERRORS;
bool SendResetIf_Throw = false;
ReturnValueFromReceive="";
try
{
hostent *mailhost = NULL;
if( isdigit(*EmailSenderHostName.c_str()) && strchr(EmailSenderHostName.c_str(), '.') )
{
unsigned long tmp_iaddr = inet_addr(EmailSenderHostName.c_str());
mailhost = gethostbyaddr( (const char *)&tmp_iaddr, 4, PF_INET );
}
else mailhost = gethostbyname(EmailSenderHostName.c_str());
if(mailhost == NULL) throw("Error: hostent *mailhost = NULL");
struct sockaddr_in my_addr;
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(SMTP_OUTGOING_MAIL_PORT);
memcpy( &my_addr.sin_addr, mailhost->h_addr_list[0], sizeof(struct in_addr) );
if (connect(m_socket, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))) throw("Error: connect failed");
if (!VerifyReply(CHK_220_REPLY)) throw("Error: Did not Recv 220 before hello");
if (Auth_Password.size())
{
// send EHLO message
sprintf(m_EmailBuffer, "EHLO %s%s", EmailSenderHostName.c_str(),CRLF_SET.c_str());
if (!SendStr()) throw("Error: Failed to send EHLO");
if (!VerifyReply(CHK_250_REPLY )) throw("Error: Failed to Recv 250 after sending EHLO");
// Send Auth Login
switch(m_LoginMethod)
{
case AUTH_LOGIN_METHOD:
sprintf(m_EmailBuffer, "AUTH LOGIN%s", CRLF_SET.c_str());
break;
case LOGIN_PLAIN_METHOD:
sprintf(m_EmailBuffer, "AUTH LOGIN PLAIN%s", CRLF_SET.c_str());
break;
}
if (!SendStr()) throw("Error: Failed to send AUTH LOGIN");
if (!VerifyReply(CHK_334_REPLY )) throw("Error: Failed to Recv 334 after sending AUTH LOGIN");
// Send AuthUserID
if (Auth_UserID.size() == 0) Auth_UserID = EmailSenderUserID;
sprintf(m_EmailBuffer, "%s%s",
(m_LoginMethod == AUTH_LOGIN_METHOD)?Encode64(Auth_UserID).c_str():Auth_UserID.c_str(),
CRLF_SET.c_str());
if (!SendStr()) throw("Error: Failed to send Auth_UserID");
if (!VerifyReply(CHK_334_REPLY )) throw("Error: Failed to Recv 334 after sending Auth_UserID");
// Send AuthPassword
sprintf(m_EmailBuffer, "%s%s",
(m_LoginMethod == AUTH_LOGIN_METHOD)?Encode64(Auth_Password).c_str():Auth_Password.c_str(),
CRLF_SET.c_str());
if (!SendStr()) throw("Error: Failed to send Auth_Password");
if (!VerifyReply(CHK_235_REPLY )) throw("Error: Failed to Recv 235 after sending Auth_Password");
}
else
{
// send HELO message
sprintf(m_EmailBuffer, "HELO %s%s", EmailSenderHostName.c_str(),CRLF_SET.c_str());
if (!SendStr()) throw("Error: Failed to send Hello");
if (!VerifyReply(CHK_250_REPLY )) throw("Error: Failed to Recv 250 after sending hello");
}
SendResetIf_Throw = true;
// send MAIL message
if(Sender.m_EmailID.size())
{//Need to add code for Sender.m_UserName
sprintf(m_EmailBuffer, "MAIL FROM: <%s", Sender.m_EmailID.c_str());
if( strchr(Sender.m_EmailID.c_str(), '@' ) ) strcat( m_EmailBuffer, ">");
else
sprintf(m_EmailBuffer + strlen(m_EmailBuffer), "@%s>", EmailSenderHostName.c_str());
strcat(m_EmailBuffer, CRLF_SET.c_str());
}
else sprintf(m_EmailBuffer, "MAIL FROM:<%s@%s>%s", EmailSenderUserID.c_str(), EmailSenderHostName.c_str(), CRLF_SET.c_str());
// send MAIL FROM message
if (!SendStr()) throw("Error: Failed to send From");
if (!VerifyReply(CHK_250_REPLY )) throw("Error: Failed to Recv 250 after sending From");
// send RCPT message
sprintf(m_EmailBuffer, "RCPT TO: <%s>%s", To.m_EmailID.c_str(), CRLF_SET.c_str());
if (!SendStr()) throw("Error: Failed to send TO");
if (!VerifyReply(CHK_250_REPLY )) throw("Error: Failed to Recv 250 after sending RCPT TO");

// send DATA message
sprintf( m_EmailBuffer, "DATA%s", CRLF_SET.c_str());
if (!SendStr()) throw("Error: Failed to send DATA line");
if (!VerifyReply(CHK_354_REPLY )) throw("Error: Failed to Recv 354 after sending DATA line");

// construct date string
time_t tTime = time( NULL );
strftime(m_EmailBuffer, MAX_LINE_SIZE, "Date: %a, %d %b %Y %H:%M:%S %Z", localtime(&tTime));
strcat(m_EmailBuffer, CRLF_SET.c_str());
// send mail headers
// Date:
if(!SendStr()) throw("Error: Failed to send DATE");
// X-Mailer:
if (m_X_Mailer.size())
{
if(!Send(m_X_Mailer.c_str(), m_X_Mailer.size())) throw("Error: Failed to send X-Mailer");
}
// X-Phone:
if (m_X_Phone.size())
{
if(!Send(m_X_Phone.c_str(), m_X_Phone.size())) throw("Error: Failed to send X-Phone");
}
// Message-ID:
if(MessageID)
{
sprintf(m_EmailBuffer, "Message-ID: %s%s", MessageID->c_str(), CRLF_SET.c_str());
if(!SendStr()) throw("Error: Failed to send Message-ID");
}
// To:
sprintf(m_EmailBuffer, "To: <%s>", To.m_EmailID.c_str());
if(To.m_UserName.size())
{
sprintf(m_EmailBuffer + strlen(m_EmailBuffer), " (%s)",To.m_UserName.c_str());
}
strcat(m_EmailBuffer, CRLF_SET.c_str());
if(!SendStr()) throw("Error: Failed to send TO");
// From:
if(Sender.m_EmailID.size())
{
sprintf( m_EmailBuffer, "From: <%s>", Sender.m_EmailID.c_str());
if(Sender.m_UserName.size())
sprintf(m_EmailBuffer + strlen(m_EmailBuffer), " (%s)",Sender.m_UserName.c_str());
strcat(m_EmailBuffer, CRLF_SET.c_str());
}
else
sprintf( m_EmailBuffer, "From: <%s@%s>%s", EmailSenderUserID.c_str(), EmailSenderHostName.c_str(), CRLF_SET.c_str());
if(!SendStr()) throw("Error: Failed to send From");
// Reply-To:
if(ReplyToAddr.m_EmailID.size())
{
sprintf( m_EmailBuffer, "Reply-To: <%s>", ReplyToAddr.m_EmailID.c_str());
if(ReplyToAddr.m_UserName.size())
sprintf(m_EmailBuffer + strlen(m_EmailBuffer), " (%s)",ReplyToAddr.m_UserName.c_str());
strcat(m_EmailBuffer, CRLF_SET.c_str());
if(!SendStr()) throw("Error: Failed to send Reply-To");
}
// CC:
if(CC_List)
{
strcpy(m_EmailBuffer,"CC: ");
for (std::list<EmailAddr>::const_iterator email_addr_item = CC_List->begin();
email_addr_item != CC_List->end();email_addr_item++)
{
std::list<EmailAddr>::const_iterator test_item = email_addr_item;
test_item++;
sprintf(m_EmailBuffer + strlen(m_EmailBuffer), "<%s>", email_addr_item->m_EmailID.c_str());
if(email_addr_item->m_UserName.size())
sprintf(m_EmailBuffer + strlen(m_EmailBuffer), " (%s)%s",email_addr_item->m_UserName.c_str(), (test_item==CC_List->end())?"":EMAIL_ADDR_DIV_CHR);
else
strcat(m_EmailBuffer, (test_item==CC_List->end())?"":EMAIL_ADDR_DIV_CHR);
}
strcat(m_EmailBuffer, CRLF_SET.c_str());
if(!SendStr()) throw("Error: Failed to send CC_List");
}
// BCC:
if(BCC_List)
{
strcpy(m_EmailBuffer,"BCC: ");
for (std::list<EmailAddr>::const_iterator email_addr_item = BCC_List->begin();
email_addr_item != BCC_List->end();email_addr_item++)
{
std::list<EmailAddr>::const_iterator test_item = email_addr_item;
test_item++;
sprintf(m_EmailBuffer + strlen(m_EmailBuffer), "<%s>", email_addr_item->m_EmailID.c_str());
if(email_addr_item->m_UserName.size())
sprintf(m_EmailBuffer + strlen(m_EmailBuffer), " (%s)%s",email_addr_item->m_UserName.c_str(), (test_item==BCC_List->end())?"":EMAIL_ADDR_DIV_CHR);
else
strcat(m_EmailBuffer, (test_item==BCC_List->end())?"":EMAIL_ADDR_DIV_CHR);
}
strcat(m_EmailBuffer, CRLF_SET.c_str());
if(!SendStr()) throw("Error: Failed to send BCC_List");
}
// Subject:
sprintf(m_EmailBuffer, "Subject: %s%s", Subject.c_str(), CRLF_SET.c_str());
if(!SendStr()) throw("Error: Failed to send Subject");
if(AttachmentPath_List)
{
sprintf(m_EmailBuffer, "MIME-Version: 1.0%sContent-type: multipart/mixed; boundary=\"#BOUNDARY#\"%s", CRLF_SET.c_str(), CRLF_SET.c_str());
SendStr();
}
/////////////////////////////////////////////////////////
// 08/13/98 rlb
// empty line needed after headers, RFC822
strcpy(m_EmailBuffer, CRLF_SET.c_str());
if(!SendStr()) throw("Error: Failed to send empty line needed after headers(1)");
strcpy(m_EmailBuffer, CRLF_SET.c_str());
if(!SendStr()) throw("Error: Failed to send empty line needed after headers(2)");
if(AttachmentPath_List)
{
sprintf(m_EmailBuffer, "%s--#BOUNDARY#%sContent-Type: text/plain; charset=ISO-8859-1%sContent-Transfer-Encoding: quoted-printable%s%s",
CRLF_SET.c_str(), CRLF_SET.c_str(), CRLF_SET.c_str(), CRLF_SET.c_str(), CRLF_SET.c_str());
SendStr();
}
/////////////////////////////////////////////////////////
// send message text
if(!Send(Body.c_str(), Body.size())) throw("Error: Failed to send send message text");

// AttachmentPath_List:
if(AttachmentPath_List)
{
for (std::list<std::string>::const_iterator attachment_file_item = AttachmentPath_List->begin();
attachment_file_item != AttachmentPath_List->end();attachment_file_item++)
{
std::string DestStringForEncodeData;
if (Encode64(*attachment_file_item, DestStringForEncodeData))
{
if(!Send(DestStringForEncodeData.c_str(), DestStringForEncodeData.size()))
throw("Error: Failed to send BCC_List");
}
}
strcpy(m_EmailBuffer, CRLF_SET.c_str());
strcat(m_EmailBuffer, "--#BOUNDARY#--");
SendStr();
}
// send message terminator and receive reply
if(!Send("\r\n.\r\n", 5)) throw("Error: Failed to send message terminator");
if(!VerifyReply(CHK_250_REPLY )) throw("Error: Failed to Recv 250 reply after sending message terminator");
SendResetIf_Throw=false; //No use sending reset if fail at this point

// send QUIT message
strcpy(m_EmailBuffer, "QUIT" );
strcat(m_EmailBuffer, CRLF_SET.c_str());
if(!SendStr()) throw("Error: Failed to send QUIT message");
if(!VerifyReply(CHK_221_REPLY )) throw("Error: Failed to Recv 221 reply after sending QUIT message");
}
catch(const char* ErrMsg)
{
ReturnValue = ErrMsg;
if (ReturnValueFromReceive.size())
{
ReturnValue += " Last Rcvd = " + ReturnValueFromReceive;
}
if (SendResetIf_Throw)
{
strcpy(m_EmailBuffer, "RESET");
strcat(m_EmailBuffer, CRLF_SET.c_str());
SendStr();
strcpy(m_EmailBuffer, "QUIT");
strcat(m_EmailBuffer, CRLF_SET.c_str());
SendStr();
}
}
shutdown (m_socket, 2);
#ifdef WIN32
closesocket(m_socket);
#else
#endif
m_socket = NULL;
return ReturnValue;
}
static const char* NO_ERRORS;
std::string Auth_Password;
std::string Auth_UserID;
LoginMethod m_LoginMethod;
private:
SOCKET m_socket;
bool m_InitiateGood;
char m_EmailBuffer[MAX_LINE_SIZE + 1];
const std::string m_X_Mailer;
const std::string m_X_Phone;
int m_UniqueContentID;
std::string ReturnValueFromReceive;
static const char* m_base64Table;
static const char* CHK_220_REPLY;
static const char* CHK_221_REPLY;
static const char* CHK_235_REPLY;
static const char* CHK_250_REPLY;
static const char* CHK_334_REPLY;
static const char* CHK_354_REPLY;
static const char* EMAIL_ADDR_DIV_CHR;
static const std::string CRLF_SET;
static const EmailAddr EmptyEmailAddr;
bool SendStr(void)
{
return Send(m_EmailBuffer, strlen(m_EmailBuffer));
}
bool VerifyReply(const char* szReplyString)
{
return Receive(m_EmailBuffer, MAX_LINE_SIZE, 0, szReplyString);
}
bool Receive(char* szBuffer, int nLenMax, int nFlags, const char* szReplyString)
{
int nRes = recv(m_socket, szBuffer, nLenMax, nFlags);
ReturnValueFromReceive = szBuffer;
if (nRes == SOCKET_ERROR ) return false;
#if defined(_DEBUG) || defined(DEBUG)
static bool FirstPass = true;
std::ofstream file("log_recv.txt",std::ios::out|((FirstPass)?0:std::ios::app));
FirstPass=false;
if (!file.fail())
{
file.seekp(0, std::ios::end);
file.write(szBuffer,nRes);
file.close();
}
#endif //defined(_DEBUG) || defined(DEBUG)
*(szBuffer + nRes ) = '\0';
char* szPtr = strtok( szBuffer, "\n" );
while(szPtr)
{
if(*(szPtr + 3) == ' ')
{
if(!strncmp(szPtr, szReplyString, strlen(szReplyString))) return true;
else return false;
}
else szPtr = strtok( NULL, "\n" );
}
return false;
}
bool Send(const char *szBuffer, size_t nLen)
{
int nCnt = 0;
while( nCnt < nLen )
{
int nRes = send( m_socket, szBuffer + nCnt, nLen - nCnt, 0);
if( nRes == SOCKET_ERROR) return false;
else nCnt += nRes;
}
return true;
}
bool Encode64(const unsigned char *in, unsigned inlen,
unsigned char *out, unsigned outmax)
{
unsigned olen = (inlen + 2) / 3 * 4;
if (outmax < olen) return false;
while (inlen >= 3)
{
/* user provided max buffer size; make sure we don't go over it */
*out++ = m_base64Table[in[0] >> 2];
*out++ = m_base64Table[((in[0] << 4) & 0x30) | (in[1] >> 4)];
*out++ = m_base64Table[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
*out++ = m_base64Table[in[2] & 0x3f];
in += 3;
inlen -= 3;
}
if (inlen > 0)
{
/* user provided max buffer size; make sure we don't go over it */
*out++ = m_base64Table[in[0] >> 2];
unsigned char oval = (in[0] << 4) & 0x30;
if (inlen > 1)
oval |= in[1] >> 4;
*out++ = m_base64Table[oval];
*out++ = (inlen < 2) ? '=' : m_base64Table[(in[1] << 2) & 0x3c];
*out++ = '=';
}
if (olen < outmax) *out = '\0';
return true;
}
std::string Encode64(const char *in, unsigned inlen)
{
char *TmpBuf = new char[inlen*2];
std::string ReturnValue = "";
if (Encode64((const unsigned char *)in, inlen, (unsigned char *)TmpBuf, inlen*2))
{
ReturnValue = TmpBuf;
}
delete [] TmpBuf;
return ReturnValue;
}
std::string Encode64(const std::string &Src)
{
return Encode64(Src.c_str(), Src.size());
}

bool Encode64(const std::string &FileName, std::string &encodedFile)
{
std::ifstream file(FileName.c_str(), std::ios::binary);
if (file.fail())
{
encodedFile = "";
return false;
}
file.seekg(0, std::ios::end);
unsigned int FileLen = file.tellg();
file.seekg(0, std::ios::beg);
unsigned char *SrcBuf = new unsigned char[FileLen];
file.read((char *)SrcBuf,FileLen);
file.close();
unsigned int DestLen = FileLen * 1.5;
unsigned char *DestBuf = new unsigned char[DestLen];
bool ReturnValue = Encode64(SrcBuf, FileLen, DestBuf, DestLen);
if (ReturnValue)
{
encodedFile = CRLF_SET + CRLF_SET + "--#BOUNDARY#";
encodedFile += CRLF_SET + "Content-Type: text/plain; charset=ISO-8859-1; name=" + FileName;
encodedFile += CRLF_SET + "Content-Transfer-Encoding: base64";
encodedFile += CRLF_SET + "Content-Disposition: attachment; filename=" + FileName;
encodedFile += CRLF_SET + CRLF_SET;
encodedFile += (char *)DestBuf;
}
delete [] SrcBuf;
delete [] DestBuf;
return ReturnValue;
}
};
const char* GeneralSendMailClass::NO_ERRORS = "OK";
const char* GeneralSendMailClass::CHK_220_REPLY = "220";
const char* GeneralSendMailClass::CHK_221_REPLY = "221";
const char* GeneralSendMailClass::CHK_235_REPLY = "235";
const char* GeneralSendMailClass::CHK_250_REPLY = "250";
const char* GeneralSendMailClass::CHK_334_REPLY = "334";
const char* GeneralSendMailClass::CHK_354_REPLY = "354";
const char* GeneralSendMailClass::EMAIL_ADDR_DIV_CHR = ",";
const std::string GeneralSendMailClass::CRLF_SET = "\r\n";
const GeneralSendMailClass::EmailAddr GeneralSendMailClass::EmptyEmailAddr = "";
const char* GeneralSendMailClass::m_base64Table =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????";

void SimpleExampleFunctionUsingGeneralSendMailClass(void)
{
GeneralSendMailClass MyGeneralSendMailClass;
MyGeneralSendMailClass.Auth_Password = "MyPasswordHere"; //Not needed if server does NOT require Auth
MyGeneralSendMailClass.SendEmail(
"JoneDoe@axter.com", // Recipient Email address
"*File Test x99: Please ignore this email.", //Subject
"Test from GeneralSendMailClass. Please ignore this email.", //Email Body
"foofoo.com", //Host Name (sender's Hostname)
"MyUserID" //Sender's UserID
);
}

void Example1FunctionUsingGeneralSendMailClass(void)
{
GeneralSendMailClass MyGeneralSendMailClass;
MyGeneralSendMailClass.Auth_Password = "MyPasswordHere";//Not needed if server does NOT require Auth
MyGeneralSendMailClass.Auth_UserID = "TheUserID"; //This is usually the same as EmailSenderUserID passed to SendEmail function
std::list<std::string> ListOfAttachments; //optional list of attachments
ListOfAttachments.push_back("c:\\test10.txt");
ListOfAttachments.push_back("c:\\test11.txt");
ListOfAttachments.push_back("c:\\test12.txt");
std::string Results = MyGeneralSendMailClass.SendEmail(
"BenLaden@dip.com", // Recipient Email address
"Hello",//Subject
"You can run, but you can't hide.",//Email Body
"af.mil",
"MyUserID",
"",
NULL, //CC list
NULL, //BCC list
&ListOfAttachments);
if (Results != GeneralSendMailClass::NO_ERRORS)
{
printf("Error:\r\n");
printf(Results.c_str());
printf("\r\n\r\nPress ENTER to quit\r\n");
getchar();
}
}


int main(int argc, char* argv[])
{
SimpleExampleFunctionUsingGeneralSendMailClass();
Example1FunctionUsingGeneralSendMailClass();
return 0;
}