SMTP module
Emails the issued certificate artefact to one or more recipients after every successful renewal. Useful for key-ceremony hand-off, compliance archive mailboxes, and ops DLs that don't have an API integration. Not a notification — the SMTP module ships the certificate bytes themselves (PEM + chain, optionally private key or a passphrase-protected PKCS#12 bundle), the same way SSH ships PEM files to a box.
01Overview
- Transport: SMTP over STARTTLS (port 587), SMTPS / implicit TLS (465), or plaintext (25, dev only).
- Auth: PLAIN, LOGIN, or none (open relay / internal MTA).
- Payload: PEM (cert + chain), PEM + unencrypted private key, or a passphrase-protected PKCS#12 bundle (AES-256 + SHA-256 HMAC via go-pkcs12 Modern2023).
- Recipients: TO / CC / BCC lists, RFC 5322 validated. One email per target carries all three lists.
- Rollback: not supported. Email cannot be recalled.
- Self-contained targets: each target owns its own relay coordinates + sender identity + recipient set. Matches the IIS / Vault pattern.
02Prerequisites
- Network egress from the backend to the relay host on the chosen port.
- SMTP AUTH credentials (when
auth_method≠none) — created as a module credential of typesmtp_password. - For PKCS#12 payload mode: a second credential of type
smtp_pkcs12_passphraseholding the bundle's passphrase. - Correct SPF / DKIM / DMARC on the sender's domain (see Deliverability). Without alignment, receivers silently spam-mark the message.
03Create the module credential(s)
- Settings → Distribution → Credentials → New.
- Type: SMTP password (
smtp_password). Secret: the raw relay AUTH password. Save. - If a target will use PKCS#12 payload mode, add a second credential of type SMTP PKCS#12 passphrase (
smtp_pkcs12_passphrase) — its secret is the passphrase you'll share out-of-band with the recipient.
Both credential secrets are stored as envelope-encrypted blobs, never in plaintext on disk or in audit logs.
04Create an SMTP target
- Settings → Distribution → Targets → New. Target type: SMTP (Email).
-
Relay section:
- Host — relay hostname (e.g.
smtp.sendgrid.net,mail.example.com). - Port — 587 for STARTTLS (default), 465 for SMTPS, 25 for plaintext.
- TLS mode — STARTTLS requires the upgrade (blocks downgrade), SMTPS wraps from handshake, plaintext warns loudly and is dev-only.
- Skip TLS verify — operator opt-in for self-signed internal relays. Leave off for anything external.
- Auth method — PLAIN / LOGIN / none. CRAM-MD5, NTLM, OAuth2 / XOAUTH2 are out of scope in v1.
- Username — required when auth_method ≠ none; password comes from the linked credential.
- Timeout (s) — per-send; default 30, max 600.
- Host — relay hostname (e.g.
-
Message identity:
- From address — RFC 5322 mailbox. Domain must align with SPF / DKIM / DMARC.
- From name — display name in the
From:header. Optional, max 128 chars.
-
Recipients:
- TO — required, at least one. Max 50 entries.
- CC / BCC — optional. Use BCC for privacy (recipients don't see each other).
-
Payload:
pem(default) — fullchain PEM only. No private key on the wire. The safe default.pem_and_key— fullchain + the private key, both plaintext. UI shows a red banner. Only pick when you fully trust the SMTP path.pkcs12— single.p12attachment encrypted with the passphrase from thesmtp_pkcs12_passphrasecredential. Share the passphrase out-of-band.
- Subject prefix (optional) — prepended to the default subject, e.g.
[PROD]. - Save → health check dials the relay + walks the TLS policy +
EHLO/NOOP.
05Execution flow
- Worker parses + validates the target's SMTP spec (relay, recipients, payload mode, credential slots).
- Builds the attachments: PEM, PEM + key, or PKCS#12 bundle. The subject is
[{prefix}] CertAutoPilot: certificate for {CN} issued, expires {NotAfter}; body is a fixed English template (CN, SANs, issuer, validity, serial, SHA-256 fingerprint, attachment list). - Dials the relay with the configured TLS mode + AUTH if applicable.
- Sends one email per target containing the full TO / CC / BCC recipient set.
- Emits a success or a classified error (
SMTP_CONNECT,SMTP_TLS,SMTP_AUTH,SMTP_TRANSIENT,SMTP_PERMANENT,SMTP_VALIDATION,SMTP_PAYLOAD).
Every SMTP hop (the relay, any forwarder, the recipient's IMAP server) can read the plaintext key. Use pkcs12 for recipients who need the key — it encrypts the bundle with a passphrase you hand over separately. Reserve pem_and_key for scenarios where you completely trust the delivery path (e.g. a loopback MTA into an air-gapped archive box).
06Deliverability — SPF / DKIM / DMARC
CertAutoPilot only sets the SMTP envelope. Whether the mail lands in the recipient's inbox depends entirely on the sender domain's email policy.
- SPF — the TXT record for the
from_addressdomain mustinclude:the relay's SPF or list the sending IP. Mismatch → spam / reject. - DKIM — if the relay signs (SendGrid, Mailgun, Postmark, Google Workspace), publish the DKIM public-key TXT record at
selector._domainkey.<domain>. If the relay doesn't sign, rely on SPF alignment alone. - DMARC —
p=rejectwith neither SPF nor DKIM aligned means silent delivery failure. Start atp=nonewhile validating, move to quarantine/reject once DMARC reports come back clean. - Bounces — the SMTP module is fire-and-forget. Bounce / deferred delivery only surfaces in the relay's audit log, never in the distribution status. Use the relay's dashboard for observability.
07Rollback
Not supported — email cannot be recalled. The distribution record's RollbackAvailable is false and the UI hides the Rollback button. Manual revocation on the CA is the only post-send remediation path if a certificate was sent in error.
08Error codes
| Code | Class | Retry? | Meaning |
|---|---|---|---|
SMTP_CONNECT | network | yes | TCP dial / DNS failure. Check host, port, firewall. |
SMTP_TLS | auth | no | TLS handshake rejected or cert unverified. Fix trust chain or set tls_skip_verify. |
SMTP_AUTH | auth | no | 535 authentication rejected. Rotate the smtp_password credential + verify username. |
SMTP_TRANSIENT | io_transient | yes | 421 / 450 / 451 / 452 — relay throttled or temp error. |
SMTP_PERMANENT | io_permanent | no | 550 / 552 / 554 — relay denied, quota, or final reject. |
SMTP_VALIDATION | validation | no | 500 / 501 / 503 / 553 — malformed message or recipient. |
SMTP_PAYLOAD | validation | no | PEM decode or PKCS#12 encode failed before dial. |
09Troubleshooting
"dial tcp: connection refused" — SMTP_CONNECT
The backend host can't reach the relay on the configured port. Verify network / firewall (nc -vz host 587). Some cloud providers block outbound 25 by default — use 587 or 465 instead, or a relay that explicitly allows port 25 egress.
"tls: handshake failure" or "x509: certificate signed by unknown authority" — SMTP_TLS
Relay's TLS certificate isn't trusted by the system CA bundle. Install the relay's CA, or set tls_skip_verify=true if it's a self-signed internal relay. For SMTPS (port 465) double-check you're not targeting a STARTTLS-only port.
"535 5.7.8 authentication failed" — SMTP_AUTH
Username or password wrong. Some relays (Google Workspace legacy, M365 pre-OAuth) also reject AUTH unless app-specific passwords are enabled. v1 doesn't support OAuth2 / XOAUTH2 — use a service account with a dedicated app password, or choose a relay that accepts PLAIN / LOGIN.
"550 5.7.1 relay access denied" — SMTP_PERMANENT
The relay refuses to forward mail from this sender / to this recipient. Check the relay's accepted domains + SPF alignment. Hosted providers (SendGrid, Mailgun) require explicit sender-domain verification before they'll relay external recipients.
Mail delivers but lands in spam
Almost always a deliverability issue, not an SMTP problem. Check the DMARC aggregate report (rua=) for the sender domain; confirm SPF include: matches the relay, DKIM signature passes, and the DMARC policy isn't p=reject with broken alignment.