smtp
Portable SMTP/ESMTP client using the sockets library for plaintext
connections and the process library with OpenSSL for implicit TLS
and STARTTLS connections. Requires a backend supporting sockets.
Requirements
The openssl (version 3.0.0 or later) command must be available on
the system PATH.
On macOS, this command can be installed using e.g. Homebrew:
$ brew install openssl
Or using MacPorts:
$ sudo port install openssl
On Ubuntu, this command can be installed using:
$ sudo apt install openssl
On RedHat distributions (8.x and later):
$ sudo dnf install openssl
For older RedHat distributions:
$ sudo yum install openssl
On Windows, the openssl command can be installed using e.g.
Chocolatey:
> choco install openssl
API documentation
Open the ../../apis/library_index.html#smtp link in a web browser.
Loading
To load all entities in this library, load the loader.lgt file:
| ?- logtalk_load(smtp(loader)).
Testing
To test this library predicates, load the tester.lgt file:
| ?- logtalk_load(smtp(tester)).
The default tests use a loopback mock SMTP server and do not deliver email.
Usage
The primary API is the stateless send/5 predicate. It opens a
connection, negotiates the SMTP session, sends one message, issues
QUIT, and closes all socket or process resources before returning:
| ?- Message = smtp_message(
'alice@example.com',
['bob@example.com'],
['Subject'-'Hello'],
'Olá, mundo!'
),
smtp::send('smtp.example.com', 587, Message, Result, [
security(starttls),
auth('alice@example.com'-'secret')
]).
For applications sending several messages in one session, use
connect/4, connection-based send/4, and disconnect/1. The
connection handle is opaque and caller-owned; the library does not store
global session state.
Messages and results
Messages use the term:
smtp_message(EnvelopeFrom, Recipients, Headers, Body)
Recipients is a mailbox atom or a non-empty list of mailbox atoms.
Headers is a list of Name-Value pairs. Bodies are text
represented by an atom, a chars(Chars) term, or a codes(Codes)
term.
All bodies are encoded as UTF-8 and transferred using MIME Base64 encoding. Input CRLF, bare CR, and bare LF line endings are normalized to CRLF before encoding, and Base64 output is folded at 76 characters per line. The library adds the following headers when they are not supplied by the caller:
MIME-Version: 1.0Content-Type: text/plain; charset=UTF-8Content-Transfer-Encoding: base64
Caller-supplied MIME headers are preserved when compatible. Header names
are matched case-insensitively. Conflicting or duplicate MIME headers
are rejected before opening a connection. A caller-supplied
Content-Type may select a different media type, such as
text/html, but must declare the UTF-8 charset.
Unicode Subject and Comments values are automatically serialized
as RFC 2047 UTF-8 Base64 encoded words. Encoded words are limited to 75
characters and long values are folded between encoded words without
splitting a Unicode character. ASCII values, including caller-supplied
encoded words, are preserved unchanged. Other header values remain
restricted to ASCII.
Results use the term:
smtp_result(FinalResponse, AcceptedRecipients, RejectedRecipients)
Responses use smtp_response(Code, Lines). Rejected recipients are
represented by Recipient-smtp_response(Code, Lines).
FinalResponse is not_sent when no recipient was accepted or when
require_all_recipients(true) prevents sending.
Options
Connection options:
security(plain)(default),security(tls), orsecurity(starttls)helo(Name)auth(User-Password)allow_insecure_auth(Boolean)(defaultfalse)openssl_executable(Executable)(defaultopenssl)server_name(default),server_name(none), orserver_name(Name)verify_peer(Boolean)(defaulttrue)ca_file(File)openssl_arguments(Arguments)
Transaction options:
require_all_recipients(Boolean)(defaultfalse)header(Name, Value), which may be repeated
Port numbers never select a security mode automatically.
Security
Implicit TLS and STARTTLS use openssl s_client. STARTTLS uses
OpenSSL’s -starttls smtp support: OpenSSL consumes the initial
plaintext greeting, EHLO, and STARTTLS exchange, after which this
library sends the required EHLO over the encrypted connection. The
OpenSSL interactive command interpreter is disabled so that SMTP
commands such as RCPT, RSET, and QUIT are forwarded
unchanged.
Peer and hostname verification are enabled by default. Authentication
supports the advertised PLAIN and LOGIN mechanisms, preferring PLAIN.
Authentication on a plaintext connection is rejected unless
allow_insecure_auth(true) is explicitly specified.
Limitations
The current version does not generate RFC 2047 encoded words for display
names, structured fields, or arbitrary extension fields. MIME multipart
bodies, attachments, SMTPUTF8 envelopes, quoted-printable transfer
encoding, 8BITMIME, PIPELINING, CHUNKING, DSN, automatic retries,
connection pooling, and operation timeouts are not implemented.
Automatic retry after DATA is deliberately omitted because loss of
the final reply makes delivery status ambiguous and retrying can
duplicate mail.