Smtp interface provides the service to send and receive 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.
In addition, the SMTP server for receiving emails supports both UTF-8 and Latin-1 (ISO-8859-1) character encodings. The emails can be configured to utilize either encodings.
File | common/interface/smtp.h |
Public functions |
CreateSmtpProvider |
Classes |
ISmtpProvider ISmtp ISmtpSend ISmtpListen USmtpListen USmtpReceive ISmtpReceive |
Code Examples |
Initialize the Provider Create the ISmtp instance Send Emails Receive Emails |
class ISmtpProvider * CreateSmtpProvider();
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;
};
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. |
class ISmtp {
public:
enum ContentTypes {
ContentTextHtml,
ContentTextPlain,
ContentUnknown
};
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;
};
The ContentTypes
enumeration defines the various content types that can be used in email messages. This helps in specifying the format of the content being received in the email.
Represents HTML content in the email body.
Represents plain text content in the email body. This type is used when the email content is in plain text format without any special formatting.
Represents an unknown content type. This can be used as a default value or when the content type cannot be determined.
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. |
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). |
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;
};
const char * attachmentUrl | The filename of the attachment that will be sent. |
const char * rcpt | The receiver's email address. |
const char * rcpt | The receiver's email address. |
const char * rcpt | The receiver's email address. |
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. |
class UTask * user | Used for the callbacks for task completion. |
class ISmtpListen {
public:
virtual class ISmtpReceive * CreateReceive(const char * user, const char * password, const char * domain) = 0;
virtual void Shutdown() = 0;
};
const char * user | The username of the receiver for authentication. |
const char * password | The password of the receiver for authentication. |
const char * domain | The domain name of the receiver for authentication. |
class USmtpListen {
public:
virtual void SmtpListenResult(class ISmtpReceive * smtpRecv) = 0;
virtual void SmtpListenShutdownComplete() = 0;
virtual class ISmtpReceive * CreateSmtpReceive() = 0;
};
class ISmtpReceive * smtpRecv | The ISmtpReceive instance resulting from listening. |
class USmtpListen {
public:
virtual void SmtpReceiveCancelComplete() = 0;
virtual void CallRecvBody() = 0;
virtual void SmtpHeader() = 0;
virtual void SmtpBody(char * buffer, int length, bool complete) = 0;
};
char * buffer | The buffer in which the email body is written. |
int length | The size, in bytes, of the data segment to be received from the ISmtpReceive class. |
bool complete | Indicates whether the current data segment is the final part of the email body. If "complete" is false, "RecvBody" must be called again to receive subsequent data segments. If "complete" is true, it signifies that the current batch is the last segment of the email body. Note that a true value for "complete" does not imply the absence of remaining attachment data. |
class USmtpListen {
public:
virtual void Cancel() = 0;
virtual void Receive() = 0;
virtual void Accept(USmtpReceive * receive) = 0;
virtual char * GetTo() = 0;
virtual char * GetFrom() = 0;
virtual char * GetSubject() = 0;
virtual char * GetDate() = 0;
virtual char * GetFileName() = 0;
virtual enum ISmtp::ContentTypes GetContentType(const char ** type = 0) = 0;
virtual void RecvBody(char * mBuffer, int len) = 0;
virtual void RecvAttachment(char * mBuffer, int len) = 0;
};
USmtpReceive * receive | The USmtpReceive instance created n the beginning of receiving emails. |
char * mBuffer | The buffer in which the email body data will be written. This most not be a nullptr. |
int len | The amount of bytes to be received from the ISmtpReceive. Given that the data is to be stored in mBuffer, it is essential for mBuffer to have a size that is at least equal to len. |
char * mBuffer | The buffer in which the attachment data will be written. This most not be a nullptr. |
int len | The number of bytes to be received from the ISmtpReceive service. Since the data is to be stored in mBuffer, mBuffer should be at least as large as len.
#include "common/interface/smtp.h"
...
ISmtpProvider * smtpProvider = CreateSmtpProvider();
...
AppService * service = new AppService(iomux, localSocketProvider, tcpSocketProvider, tlsSocketProvider, ..., smtpProvider, &serviceArgs);
...
delete smtpProvider;
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;
}
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;
}
// Class ForReceiving
class ForReceiving {
public:
void Start() {
if (!smtpListen) {
smtpListen = smtp->CreateListen(this);
}
}
class ISmtpReceive* CreateSmtpReceive() {
return smtpListen->CreateReceive("inno-fax", "fax123", "fax2.innovaphone.com");
}
void SmtpListenResult(class ISmtpReceive* smtpReceive) {
if (!receiveMail) {
receiveMail = new ReceiveMail(app, database, smtpReceive);
} else {
smtpReceive->Cancel();
}
}
private:
class ISmtpListen* smtpListen = nullptr;
class ReceiveMail* receiveMail = nullptr;
// Other member variables
};
// Class ReceiveMail
class ReceiveMail {
public:
void Start() {
smtpReceive->Accept(this);
}
void SmtpHeader() {
const char* from = smtpReceive->GetFrom();
const char* to = smtpReceive->GetTo();
}
void CallRecvBody() {
smtpReceive->RecvBody(buffer, length);
}
void SmtpBody(char* buffer, int length, bool complete) {
char* dataIn = buffer;
const char * contentType = 0;
smtpReceive->GetContentType(&contentType);
if (contentType && !strcmp(contentType, "application/pdf")) {
//change the state here
}
smtpReceive->RecvBody(buffer, length);
}
private:
class ISmtpReceive* smtpReceive;
char buffer[4096];
// Other member variables
};