SMTP
Synopsis
Creates an SMTP server that receives email messages. Supports authentication, TLS encryption through either STARTTLS or implicit TLS, and multiple workers with 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>
reuse: <boolean>
workers: <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 | Skip peer certificate verification. Use only for testing. |
* = 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 |
|---|---|---|---|
reuse | N | false | Enable multi-worker mode |
workers | N | Quarter of the CPU count | Number of worker processes when reuse is enabled. Never below 1, capped at the CPU count, and reduced further on memory-constrained hosts. |
max_buffer_size | N | 128MB | Ingest buffer admission cap. Also sets this listener's eager heap reservation |
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, which commits 384 MiB of heap per listener worker before any data arrives — 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.
Multiple Workers
When reuse is enabled, the server uses multiple worker processes which maintain a separate SMTP listener and process messages independently. Messages are automatically converted to JSON.
The worker count is capped at the number of available CPU cores, and reduced further on memory-constrained hosts.
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.
High-Volume
SMTP server tuned for high email volumes using multiple workers:
Optimizing for high message volumes... | |
Pipelines
Applying preprocessing pipelines to incoming emails:
Applying custom processing to emails... | |
Pipelines are processed sequentially and can modify or drop messages before ingestion.