Introduction

Overview

For the most part, the libESMTP API is a relatively thin layer over SMTP protocol operations, that is, most API functions and their arguments are similar to the corresponding protocol commands. Further API functions manage a callback mechanism which is used to read messages from the application and to report protocol progress to the application. The remainder of the API is devoted to reporting on a completed SMTP session.

Although the API closely models the protocol itself, libESMTP relieves the programmer of all the work needed to properly implement RFC 5321 (formerly RFC 2821, formerly RFC 821) and avoids many of the pitfalls in typical SMTP implementations. It constructs SMTP commands, parses responses, provides socket buffering and pipelining, where appropriate provides for TLS connections and provides a failover mechanism based on DNS allowing multiple redundant MSAs. Furthermore, support for the SMTP extension mechanism is incorporated by design rather than as an afterthought.

There is limited support for processing RFC 5322 message headers. This is intended to ensure that messages copied to the SMTP server have their correct complement of headers. Headers that should not be present are stripped and reasonable defaults are provided for missing headers. In addition, the header API allows the defaults to be tuned and provides a mechanism to specify message headers when this might be difficult to do directly in the message data.

libESMTP does not implement MIME [RFC 2045] since MIME is, in the words of RFC 2045, orthogonal to RFC 5322. The developer is expected to use a separate library to construct MIME documents or the application should construct them directly. libESMTP ensures that top level MIME headers are passed unaltered and the header API functions are guaranteed to fail if any header in the name space reserved for MIME is specified, thus ensuring that MIME documents are not accidentally corrupted.

API

The libESMTP API is a relatively small and lightweight interface to the SMTP protocol and its extensions. Internal structures are opaque to the application accessible only through API calls. The majority of the API is used to define the messages and recipients to be transferred to the SMTP server during the protocol session. Similarly a number of functions are used to query the status of the transfer after the event. The entire SMTP protocol session is performed by a single function call.

Usage

To use the libESMTP API, include the following header files

#include <auth-client.h>
#include <libesmtp.h>

Declarations for deprecated symbols must be requested explicitly; define the macro LIBESMTP_ENABLE_DEPRECATED_SYMBOLS before including libesmtp.h. for example

#define LIBESMTP_ENABLE_DEPRECATED_SYMBOLS
#include <libesmtp.h>

Internally libESMTP creates and maintains structures to track the state of an SMTP protocol session. Opaque pointers to these structures are passed back to the application by the API and must be supplied in various other API calls. The API provides for a callback functions or a simple event reporting mechanism as appropriate so that the application can provide data to libESMTP or track the session’s progress. Further API functions allow the session status to be queried after the event. The entire SMTP protocol session is performed by only one function call.

Opaque Pointers

All structures and pointers maintained by libESMTP are opaque, that is, the internal detail of libESMTP structures is not made available to the application. Object oriented programmers may wish to regard the pointers as instances of private classes within libESMTP.

Three pointer types are declared as follows

typedef struct smtp_session *smtp_session_t;
typedef struct smtp_message *smtp_message_t;
typedef struct smtp_recipient *smtp_recipient_t;

Thread Safety

LibESMTP is thread-aware, however the application is responsible for observing the restrictions below to ensure full thread safety.

Do not access a smtp_session_t, smtp_message_t or smtp_recipient_t from more than one thread at a time. A mutex can be used to protect API calls if the application logic cannot guarantee this. It is especially important to observe this restriction during a call to smtp_start_session().

Signal Handling

It is advisable for your application to catch or ignore SIGPIPE. libESMTP sets timeouts as it progresses through the protocol. In addition the remote server might close its socket at any time. Consequently libESMTP may sometimes try to write to a socket with no reader. Catching or ignoring SIGPIPE ensures the application isn’t killed accidentally when this happens during the protocol session.

Code similar to the following may be used to do this

#include <signal.h>

void
ignore_sigpipe (void)
{
  struct sigaction sa;

  sa.sa_handler = SIG_IGN;
  sigemptyset (&sa.sa_mask);
  sa.sa_flags = 0;
  sigaction (SIGPIPE, &sa, NULL);
}