SMTP

Smtp interface provides the service to send emails using the Simple Mail Transfer Protocol. To create an ISmtp instance, at first an instance of ISmtpProvider, ISocketProvider (TCP) and ISocketProvider (TLS) must be created. This need to be done by calling CreateSmtpProvider(), CreateTCPSocketProvider() and CreateTLSSocketProvider(tcpSocketProvider). An ISmtpProvider can be used to create multiple ISmtp instances. To read more about the ISocket, please check: ISocket.

When a new TaskSmtpSend is started, the connection with the SMTP server is established using TCP. If the server allows STARTTLS, the connection will be upgraded to TLS. Otherwise TCP will continue to be used.

File information

Filecommon/interface/smtp.h

Public functions CreateSmtpProvider

Classes ISmtpProvider
ISmtp
ISmtpSend

Code Examples Initialize the Provider
Create the ISmtp instance
Send Emails

Functions

Functions to initialize

class ISmtpProvider * CreateSmtpProvider();
CreateSmtpProvider
Creates an instance of the ISmtpProvider.

Return value

The actual ISmtpProvider instance. That instance can be freed as soon as it no longer is used by calling the C++ delete operator.

Classes

ISmtpProvider

class ISmtpProvider {
public:
    virtual ~ISmtpProvider() {}
    virtual class ISmtp * CreateSmtp(class IIoMux * iomux, class ISocketProvider * tcpSocketProvider, class ISocketProvider * tlsSocketProvider, class IInstanceLog * const log) = 0;
};

Overview

This class provides ISmtp instance to manage the task to send emails.

Public functions

CreateSmtpProvider
Returns a new ISmtp instance.

Parameters

class IIoMux * const iomuxThe IIoMux instance the smtp will be registered to.
class ISocketProvider * tcpSocketProviderThe socket provider for the TCP connection.
class ISocketProvider * tlsSocketProviderThe socket provider for the TLS connection.
class IInstanceLog * const logThe IInstanceLog instance used for loging purposes.

Return value

An ISmtp instance that can be used to manage the task to send emails.

Remarks

The application should store a pointer to it.

ISmtp

class ISmtp {
public:
    virtual ~ISmtp() {}
    virtual class ISmtpSend * CreateSend(const char *from, const char *fromName, const char *subject, const char *host, const char *server, const char *userSmtp, const char *password) = 0;
    virtual void SendChunk(const char *attachmentChunk, int sChunk, bool lastChunk, dword fileIndex) = 0;
};

Overview

This class provides ISmtpSend task to send an email.

Public functions

CreateSend
Returns a new SMTP Provider.

Parameters

const char * fromThe sender's email address.
const char * fromNameThe sender's name on UTF-8.
const char * subjectThe subject for the email on UTF-8.
const char * hostResolvable DNS name or an IP address literal e.g. [123.255.37.2] of the SMTP client.
const char * serverResolvable DNS name or IP-address of used SMTP server.
const char * userSmtpThe sender's user, if authentication is required.
const char * passwordThe sender's password, if authentication is required.

Return value

An ISmtpSend task that can be used to send an email.
SendChunk
Returns a new SMTP Provider.

Parameters

const char * attachmentChunkThe chunk of the file that will be attached.
int sChunkThe size of the chunk.
bool lastChunkThis indicates if this is the last chunk of the attachment (true) or there are still more (false).
dword fileIndexThe number that identifies the attached file (starting on 0 and ending with the number of files been attached minus 1).

Remarks

This must be called inside TaskProgress if at least one file has been attached to the email.

ISmtpSend


    class ISmtpSend : public ITask {
    public:
    virtual void AddAttachment(const char *attachmentUrl, const char * mimeType = nullptr) = 0;
    virtual void AddTo(const char *rcpt) = 0;
    virtual void AddCc(const char *rcpt) = 0;
    virtual void AddBcc(const char *rcpt) = 0;
    virtual void AddBody(const char *data, const char *format, const char *charset) = 0;
    virtual void Start(class UTask * user) = 0;
    };

Overview

This class implements the task to send an email.

Public functions

AddAttachment
Adds a new attachment to the email.

Parameters

const char * attachmentUrlThe filename of the attachment that will be sent.
const char * mimeTypeThe MIME type of the attachment that will be sent.

Remarks

It should be called once per attachment.
AddTo
Adds a new receiver to the recipients list.

Parameters

const char * rcptThe receiver's email address.

Remarks

It should be called at least once before Start(). The email will be sent to every rcpt if they are reachable (for example, it could be unreachable if your SMTP server is on "Relay Access denied" mode). If none of the receivers is reachable, the email will not be sent.
AddCc
Adds a new receiver to the recipients list. The email will be sent as a Carbon Copy to this receiver.

Parameters

const char * rcptThe receiver's email address.

Remarks

It should be called at least once before Start(). The email will be sent to every rcpt if they are reachable (for example, it could be unreachable if your SMTP server is on "Relay Access denied" mode). If none of the receivers is reachable, the email will not be sent.
AddBcc
Adds a new receiver to the recipients list. The email will be sent as a Blind Carbon Copy to this receiver.

Parameters

const char * rcptThe receiver's email address.

Remarks

It should be called at least once before Start(). The email will be sent to every rcpt if they are reachable (for example, it could be unreachable if your SMTP server is on "Relay Access denied" mode). If none of the receivers is reachable, the email will not be sent.
AddBody
Adds the body to the email.

Parameters

const char * dataThe text that will be sent on the body.
const char * formatThe text format i.e., text/html or text/plains.
const char * charsetThe text charset i.e., ISO-8859-1 or UTF-8.

Remarks

This function must be called at least one. If the email should not have a body, this function must still be called with and empty string as body and valid format and charset values.
Start
Starts the task that sends the email.

Parameters

class UTask * userUsed for the callbacks for task completion.

Remarks

Several ISmtpSend tasks can be called at once and the emails will be queued.

Code Examples

Initialize the Provider

#include "common/interface/smtp.h"
...
ISmtpProvider * smtpProvider = CreateSmtpProvider();
...
AppService * service = new AppService(iomux, localSocketProvider, tcpSocketProvider, tlsSocketProvider, ..., smtpProvider, &serviceArgs);
...
delete smtpProvider;

Create the ISmtp instance

app::app(IIoMux * const iomux, ISocketProvider * localSocketProvider, IWebserverPluginProvider * const webserverPluginProvider, IDatabaseProvider * databaseProvider, class Service * service, ISmtpProvider * smtpProvider, AppInstanceArgs * args) :
AppInstance(service, args)
{
    this->smtp = smtpProvider->CreateSmtp(iomux, tcpSocketProvider, tlsSocketProvider, this, "145.253.157.7");
    this->logFlags |= LOG_SMTP; // to show the flags generated by the SMTP class
}
app::~app()
{
    if (webserverPlugin) delete webserverPlugin;
    if (smtp) delete smtp;
}

Send Emails

SendEmail::SendEmail(class App * app): taskSmtp(this, &SendEmail::SmtpSendComplete, &SendEmail::SmtpSendFailed, &SendEmail::SmtpSendProgress)
{        
    ...
}
SendEmail::~SendEmail()
{
    ...
}
void SendEmail::Send()
{
    ISmtpSend * emailTask = appInstance->smtp->CreateSend("sender@innovaphone.com", "SenderName", "Subject", "sophos", "sophos.innovaphone.com", "usersmtp", "password");
    emailTask->AddTo("receiver@innovaphone.com");
    emailTask->AddTo("otherreceiver@innovaphone.com");
    emailTask->AddBody("Body of the email...", "text/html", "ISO-8859-1");
    emailTask->AddAttachment("test.txt");
    emailTask->AddAttachment("Fish.png");
    emailTask->AddAttachment("rfc821.pdf");
    bufferrb = (char*)malloc(sizeof(char) * 4096);
    emailTask->Start(&taskSmtp);
}
void SendEmail::SmtpSendComplete(class TaskSmtpSend * task)
{
    ...
}
void SendEmail::SmtpSendFailed(class TaskSmtpSend * task)
{
    ...
}
void SendEmail::SmtpSendProgress(class TaskSmtpSend * task, dword progress)
{
    //SmtpSendProgress will be called for every attachment added. For each attachment it will be called until lastChunk will be set as true.
    //progress indicates the number of the attachment requested by the task.
    //It starts with "0" for the first filename added.
    
    appInstance->smtp->SendChunk(ReadFiles(progress), len, lastChunk, progress);  
}
char * SendEmail::ReadFiles(dword file) //Example function to get the attachments chunks.
{
    char * path = (char*)"";
    switch (file)
    {
    case 0:
        path = (char*)"/path/test.txt";
        break;
    case 1:
        path = (char*)"/path/Fish.png";
        break;
    case 2:
        path = (char*)"/path/rfc821.pdf";
        break;
    default:
        break;
    }
    if (!opened)
    {
        opened = true;
        pFile = fopen(path, "rb");   
        fseek(pFile, 0, SEEK_END);
        lSize = ftell(pFile);
        rewind(pFile);
        lastChunk = false;
        bytesRead = 0;
    }
    if (!feof(pFile))
    {
        len = 0;
        len = fread(bufferrb, 1, 4096, pFile);
        bytesRead += len;
        if (bytesRead >= lSize) lastChunk = true;
    }
    if (lastChunk)
    {
        opened = false;
        fclose(pFile);
    }
    return bufferrb;
}