send email

sample code for sending email via SMTP.

Download emailer.zip

Synopsis:

emailer.cpp
emailer.h
smtp.cpp
smtp.h
sockett.h
smtpexception.h
smtphostinfo.h
smtpwriter.h
wsainit.h


emailer.cpp

Synopsis
#include "emailer.h"
#include "Smtp.h"

class EMailer::Private
  {
  public:
    Smtp smtp;
  };
EMailer::EMailer(const string& smtpserver)
: impl(* new EMailer::Private)
  {
  impl.smtp.SmtpServer = smtpserver;
  }
EMailer::~EMailer(void)
  {
  delete &impl;
  }
void EMailer::Subject(const string& sub)
  {
  impl.smtp.Subject = sub;
  }
void EMailer::ToAddress(const string& addr)
  {
  impl.smtp.To = addr;
  }
void EMailer::FromAddress(const string& addr)
  {
  impl.smtp.From = addr;
  }
void EMailer::Body(const string& text)
  {
  mBody += text;
  }
void EMailer::Send()
  {
  impl.smtp.Content = mBody;
  try
    {
    impl.smtp.Send();
    }
  catch(...)
    {
    }
  impl.smtp.Close();
  }


emailer.h

Synopsis
#pragma once

#include <string>
using std::string;

class EMailer
  {
  public:
    explicit EMailer(const string& smtpserver);
    ~EMailer();
    void Subject(const string& sub);
    void ToAddress(const string& addr);
    void FromAddress(const string& addr);
    void Body(const string& text);
    void Send();

  private:
    string mBody;
    class Private;
    Private& impl;
  };

smtp.cpp

Synopsis
#include <string>
#include <winsock2.h>
using namespace std;

#include "Smtp.h"

#include "WSAInit.h"
WSAInit instance;

#include "SmtpException.h"
#include "SmtpHostInfo.h"
#include "SocketT.h"
typedef SocketT<SmtpHostInfo, SmtpException> SmartSocket;
#include "SmtpWriter.h"

class Smtp::Private
  {
  public:
    SmartSocket mSocket;
  } ;

Smtp::Smtp()
: impl(* new Smtp::Private)
  {
  }
Smtp::~Smtp()
  {
  impl.mSocket.Close();
  delete &impl;
  }
void Smtp::Send()
  {
  Create();
  Connect();
  WriteHello();
  WriteFrom();
  WriteTo();
  WriteStartData();
  WriteBody();
  WriteQuit();
  }
void Smtp::Close()
  {
  impl.mSocket.Close();
  }
void Smtp::Create()
  {
  impl.mSocket.SetServer(SmtpServer);
  impl.mSocket.Create();
  }
void Smtp::Connect()
  {
  impl.mSocket.Connect();
  CheckResponse("220");
  }
void Smtp::WriteHello()
  {
  SmtpWriter writer(impl.mSocket);
  writer.Line("HELO " + impl.mSocket.GetLocalAddr());
  writer.Flush();
  CheckResponse("250");
  }
void Smtp::WriteFrom()
  {
  SmtpWriter writer(impl.mSocket);
  writer.HeaderLine("MAIL FROM", From);
  writer.Flush();
  CheckResponse("250");
  }
void Smtp::WriteTo()
  {
  SmtpWriter writer(impl.mSocket);
  writer.HeaderLine("RCPT TO", To);
  writer.Flush();
  CheckResponse("250");
  }
void Smtp::WriteStartData()
  {
  SmtpWriter writer(impl.mSocket);
  writer.Line("DATA");
  writer.Flush();
  CheckResponse("354");
  }
void Smtp::WriteBody()
  {
  SmtpWriter writer(impl.mSocket);
  writer.Body(Subject, To, From, Content);
  writer.Flush();
  CheckResponse("250");
  }
void Smtp::WriteQuit()
  {
  SmtpWriter writer(impl.mSocket);
  writer.Line("QUIT");
  writer.Flush();
  CheckResponse("221");
  }
void Smtp::CheckResponse(const string& s)
  {
  string response = impl.mSocket.Response();
  if (response.find(s) == response.npos)
    throw SmtpException("Expected: '" + s + "' actual: '" + response + "'");
  }

smtp.h

Synopsis
#pragma once
#include <string>
using std::string;

class Smtp
  {
  public:
    string Content;
    string From;
    string To;
    string SmtpServer;
    string Subject;

    Smtp();
    ~Smtp();
    void Send();
    void Close();
  
  private:
    void Create();
    void Connect();
    void WriteHello();
    void WriteFrom();
    void WriteTo();
    void WriteStartData();
    void WriteBody();
    void WriteQuit();
    void CheckResponse(const string& s);
  
    class Private;
    Private& impl;
  };

sockett.h

Synopsis
#pragma once

template <class HostInfoProvider, class SocketException>
class SocketT : public HostInfoProvider
  {
  public:
    SocketT(SOCKET& s)
      :mSocket(s)
      {
      }
    SocketT()
      : mSocket(INVALID_SOCKET)
      {
      }
    ~SocketT()
      {
      Close();
      }
    void Close()
      {
      if (mSocket == INVALID_SOCKET) return;
      ::closesocket(mSocket);
      mSocket = INVALID_SOCKET;
      }
    void Write(const string& str)
      {
      int bytestosend = str.length();
      int bytessent;
      for (const char* s = str.c_str(); bytestosend; s += bytessent)
        {
        bytessent = ::send(mSocket, s, bytestosend, 0);
        if (bytessent <= 0)
          throw SocketException("Write: failed");
        bytestosend -= bytessent;
        }
      };
    string GetLocalAddr()
      {
      struct sockaddr_in local;
      int n = sizeof(local);
      ::getsockname(mSocket, (struct sockaddr *)&local, &n);
      struct hostent* h = ::gethostbyaddr((char*)&local.sin_addr, sizeof(local.sin_addr), AF_INET);
      return h ? h->h_name : ::inet_ntoa(local.sin_addr);
      }
    void Create()
      {
      Close();
      mSocket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
      if (mSocket == INVALID_SOCKET)
        throw SocketException("Create: returned invalid socket");
      }
    void Connect()
      {
      sockaddr_in sa;
      sa.sin_family = AF_INET;
      sa.sin_port = GetPort();
      sa.sin_addr.s_addr = GetAddr();
      if (::connect(mSocket, (sockaddr *)&sa, sizeof(sa)) < 0)
        throw SocketException("Connect: connection to host failed");
      }
    string Response()
      {
      string response;
      int roundtrips = 0;
      for(;;)
        {
        char buffer[1024];
        int n = ::recv(mSocket, buffer, sizeof(buffer), 0);
        if (n == -1)
          throw SocketException("Response: socket read failed");
        response += string(buffer, n);
        if (response.find("\n") != response.npos)
          {
          return response;
          }
        roundtrips++;
        if (roundtrips > 1000)
          throw SocketException("socket read timeout");
        }
      }
  private:
    SOCKET mSocket;
  };

smtpexception.h

Synopsis
#pragma once
#include <exception>

class SmtpException : public exception
  {
  string m_str;
  public:
    SmtpException()
      :m_str("SMTP exception")
      {
      }
    SmtpException(const string& str)
      :m_str("SMTP exception: " + str)
      {
      }
    virtual const char* what() const throw()
      {
      return m_str.c_str();
      }
  };

smtphostinfo.h

Synopsis
#pragma once
#include "SmtpException.h"

class SmtpHostInfo
  {
  public:
    void SetServer(const string& server)
      {
      mServer = server;
      }
    unsigned long GetAddr()
      {
      hostent* host;
      in_addr inaddr;
      inaddr.s_addr = ::inet_addr(mServer.c_str());
      if (inaddr.s_addr == INADDR_NONE)
        host = ::gethostbyname(mServer.c_str());
      else
        host = ::gethostbyaddr((const char *)&inaddr, sizeof(inaddr), AF_INET);
      if (host == NULL)
        throw SmtpException("GetAddr: Invalid SMTP server");
      return *((u_long*)host->h_addr_list[0]);
      }
    short GetPort()
      {
      struct servent* server = ::getservbyname("smtp", "tcp");
      if (server == NULL)
        throw SmtpException("GetPort: SMTP is an unknown TCP service");
      return server->s_port;
      }
  private:
    string mServer;
  } ;


smtpwriter.h

Synopsis
#pragma once
#include <sstream>
using std::stringstream;

class SmtpWriter
  {
  public:
    SmtpWriter(SmartSocket& s)
      : mSocket(s)
      {
      }
    void Line(const string& s)
      {
      mOut << s << "\r\n";
      }
    void Flush()
      {
      mSocket.Write(mOut.str());
      }
    void HeaderLine(const string& hdr, const string& val)
      {
      NameValueLine(hdr, "<" + val + ">");
      }
    void Body(const string& subject, const string& to, const string& from, const string& content)
      {
      NameValueLine("Subject", subject);
      NameValueLine("To", to);
      NameValueLine("From", from);
      StartOfContent();
      Line(content);
      EndOfContent();
      }
  private:
    void NameValueLine(const string& name, const string& value)
      {
      Line(name + ": " + value);
      }
    void StartOfContent()
      {
      Line("");
      }
    void EndOfContent()
      {
      Line(".");
      }
  private:
    stringstream mOut;
    SmartSocket& mSocket;
  } ;

wsainit.h

Synopsis
#pragma once

class WSAInit
  {
  public:
    WSAInit()
      {
      WORD w = MAKEWORD(1,1);
      WSADATA wsadata;
      ::WSAStartup(w, &wsadata);
      };
    ~WSAInit()
      {
      ::WSACleanup();
      };
  } ;






Contact me about content on this page using john_web-at-arrizza-dot-com
For Web Master or site problems contact: webadmin-at-arrizza-dot-com
Copyright John Arrizza (c) 2001,2002,2003,2004,2005,2006,2007