SMTP
Synopsis
Creates an SMTP server that receives email messages. Supports authentication, TLS encryption through either STARTTLS or implicit TLS, automatic message handling, and JSON conversion.
For details, see Appendix.
Schema
- id: <numeric>
name: <string>
description: <string>
type: smtp
tags: <string[]>
pipelines: <pipeline[]>
status: <boolean>
properties:
address: <string>
username: <string>
password: <string>
allow_insecure_auth: <boolean>
port: <numeric>
timeout: <numeric>
tls:
status: <boolean>
mode: <string>
require_tls: <boolean>
cert_name: <string>
key_name: <string>
passphrase: <string>
min_tls_version: <string>
max_tls_version: <string>
client_ca_name: <string>
client_auth_required: <boolean>
insecure_skip_verify: <boolean>
Configuration
The following fields are used to define the device:
Device
| Field | Required | Default | Description |
|---|---|---|---|
id | Y | Unique identifier | |
name | Y | Device name | |
description | N | - | Optional description |
type | Y | Must be smtp | |
tags | N | - | Optional tags |
pipelines | N | - | Optional pre-processor pipelines |
status | N | true | Enable/disable the device |
Connection
| Field | Required | Default | Description |
|---|---|---|---|
address | N | "0.0.0.0" | Listen address |
port | Y | Listen port | |
username | N | - | Authentication username |
password | N | - | Authentication password |
allow_insecure_auth | N | false | Advertise AUTH on connections that are not encrypted |
timeout | N | 15 | Connection timeout in seconds |
AUTH PLAIN is the only mechanism offered, and it is advertised only when a username is configured. It carries credentials as base64 rather than encrypted, so it is withheld from unencrypted connections unless allow_insecure_auth is true.
TLS
| Field | Required | Default | Description |
|---|---|---|---|
tls.status | N | false | Enable TLS encryption |
tls.cert_name | Y* | cert.pem | TLS certificate |
tls.key_name | Y* | key.pem | TLS private key |
tls.passphrase | N | - | Passphrase for an encrypted private key |
tls.min_tls_version | N | tls1.2 | Minimum accepted TLS version (tls1.0, tls1.1, tls1.2, tls1.3) |
tls.max_tls_version | N | - | Maximum accepted TLS version. When unset, the highest mutually supported version is negotiated. |
tls.client_ca_name | N | - | CA bundle used to verify client certificates (mTLS) |
tls.client_auth_required | N** | false | Require connecting clients to present a valid certificate. When false, a client certificate is verified only if one is presented. |
tls.insecure_skip_verify | N | false | Has no effect on a listener. It applies only where the Director connects to a server, never to the connections it accepts: a client certificate is checked only through tls.client_ca_name and tls.client_auth_required. Changing it restarts the listener and nothing else. |
* = Required when tls.status is true.
** = Requires tls.client_ca_name. If tls.client_auth_required is true or tls.client_ca_name is set and the named CA cannot be loaded, the configuration is rejected and the device fails to start.
tls.min_version is a deprecated alias for tls.min_tls_version, honored only when tls.min_tls_version is unset. Use tls.min_tls_version in new configurations.
TLS material fields (cert_name, key_name, ca_name, client_ca_name) accept any of the following:
- File name — resolved relative to the service root directory. Nested paths such as
certs/prod/server.pemare supported. - Absolute path — honored only if it resolves inside the service root. Any path that escapes the root is refused.
- Inline PEM content — used verbatim when the value contains
-----BEGIN. - Environment variable —
${ENV_VAR}. - Vault reference —
$secret{id=...}or$secret{store=...,ref=...}.
SMTP can carry TLS two ways, so it reads two keys no other device has:
| Field | Required | Default | Description |
|---|---|---|---|
tls.mode | N | starttls | How TLS is carried. starttls connects in the clear and upgrades in place (RFC 3207, ports 25 and 587); implicit encrypts from the first byte (SMTPS, port 465) |
tls.require_tls | N | true | Refuse MAIL, RCPT and DATA with 530 5.7.0 Must issue a STARTTLS command first until the connection is encrypted |
The mode is not inferred from the port, so a sender on a non-standard port needs tls.mode set explicitly. An unrecognized value is rejected rather than falling back — the listener refuses to start rather than guess the transport — and that check runs even when tls.status is false.
STARTTLS is advertised, not compelled, which is what tls.require_tls enforces: with it disabled, a sender can decline the upgrade and submit in cleartext on a port configured for TLS. It has no effect under tls.mode: implicit, where the connection is never cleartext, and is inert when tls.status is false.
Performance
| Field | Required | Default | Description |
|---|---|---|---|
max_buffer_size | N | 128MB | Ingest buffer admission cap. Also sizes this listener's ingest buffers: 3/8 of this value at start, growing to at most 3x |
This device does not apply reuse or workers. It serves its port from one listener, whatever they are set to, and both keys are still accepted rather than refused. When workers is set to anything other than 1, a Verbose log line says The listener serves SMTP on one socket, so it runs 1 worker instead of the N configured., with N the configured count. Throughput is not capped by this: SMTP sessions are served concurrently, one per connection, and their writes fan out across the ingest buffer's shards.
In Director versions before v2.4.0, a device whose workers resolved above 1 never stayed listening. That included every device left at the default on a Director with 8 or more CPUs, and any device configured with workers: 2 or more. Each extra worker failed to bind the port already taken by the first, which stopped the device; the Director restarted it every minute, and clients saw connection refused. Such a device now listens on one listener, with no change to its configuration. A device created in the web interface sends workers: 1 with reuse off, so it runs one listener on those versions as well.
max_buffer_size is the ingest-buffer admission cap, and is distinct from any buffer_size field above, which sizes the network read buffer. Left unset it is 128MB, whose buffers take 48 MiB of heap per listener worker at start and grow to at most 384 MiB as bursts need the room — and with reuse: true a device runs one worker per listener. Size strings are binary, and 32MB and 32MiB are exact synonyms.
See Listener Memory Sizing for the arithmetic, the sizing table, and what happens when the cap is exhausted.
Details
Emails
The server captures and processes email headers, sender information, recipient information, message content, attachments, and remote client information.
JSON Conversion
All email messages are automatically converted to JSON format with the following fields:
| Field | Description |
|---|---|
From | Sender address |
To | Recipient addresses |
Subject | Email subject |
Body | Message body |
Hostname | Hostname the server greeted with |
LocalAddr | Address the server accepted the connection on |
RemoteAddr | Client address |
Only the subject is retained from the message headers; the remaining headers are not carried through.
Certificate Rotation
When tls.cert_name and tls.key_name resolve to files under the service root, the listener reloads them once the file modification time advances, so a certificate replaced in place is picked up without a restart. If a reload fails, the last certificate loaded successfully stays in service rather than the listener dropping TLS mid-rotation.
Material supplied inline, or through an environment variable or a vault reference, is read once when the device starts and does not rotate.
Examples
The following are commonly used configuration types.
Basic
Minimal SMTP server listening on port 25:
Creating a simple SMTP server... | |
Secure
SMTP server upgrading through STARTTLS, with credential authentication:
Configuring STARTTLS and authentication... | |
The listener binds in the clear, advertises STARTTLS in its EHLO response, and upgrades the connection in place. With require_tls enabled, a sender that does not upgrade cannot submit mail. Ports 25 and 587 are conventional for this mode.
Implicit TLS
SMTP server encrypted from the first byte on the conventional SMTPS port:
Configuring implicit TLS on port 465... | |
STARTTLS is never advertised in this mode because the connection is already encrypted, and require_tls is not read.
Mutual TLS
SMTP server requiring client certificates, with an encrypted private key and vault-sourced material:
Verifying client certificates against a CA bundle... | |
passphrase decrypts a PKCS#8 or legacy PEM-encrypted private key. Resolution failures — a missing vault entry, a wrong passphrase, an unreadable path — are reported when the configuration is validated rather than surfacing later as a handshake error.
Pipelines
Applying preprocessing pipelines to incoming emails:
Applying custom processing to emails... | |
Pipelines are processed sequentially and can modify or drop messages before ingestion.