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
    
    
    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, class IDns * const dns = nullptr) = 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 iomux | The IIoMux instance the smtp will be registered to. | 
            | class ISocketProvider * tcpSocketProvider | The socket provider for the TCP connection. | 
            | class ISocketProvider * tlsSocketProvider | The socket provider for the TLS connection. | 
            | class IInstanceLog * const log | The IInstanceLog instance used for loging purposes. | 
            | class IDns * const dns | A IDns instance that provides DNS resolution. | 
        
        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 * from | The sender's email address. | 
            | const char * fromName | The sender's name on UTF-8. | 
            | const char * subject | The subject for the email on UTF-8. | 
            | const char * host | Resolvable DNS name or an IP address literal e.g. [123.255.37.2] of the SMTP client. | 
            | const char * server | Resolvable DNS name or IP-address of used SMTP server. | 
            | const char * userSmtp | The sender's user, if authentication is required. | 
            | const char * password | The 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 * attachmentChunk | The chunk of the file that will be attached. | 
            | int sChunk | The size of the chunk. | 
            | bool lastChunk | This indicates if this is the last chunk of the attachment (true) or there are still more (false). | 
            | dword fileIndex | The 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) = 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 * attachmentUrl | The filename 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 * rcpt | The 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 * rcpt | The 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 * rcpt | The 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 * data | The text that will be sent on the body. | 
            | const char * format | The text format i.e., text/html or text/plains. | 
            | const char * charset | The 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 * user | Used 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;
}