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_methodnone) — created as a module credential of type smtp_password.
  • For PKCS#12 payload mode: a second credential of type smtp_pkcs12_passphrase holding 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)

  1. Settings → Distribution → CredentialsNew.
  2. Type: SMTP password (smtp_password). Secret: the raw relay AUTH password. Save.
  3. 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

  1. Settings → Distribution → TargetsNew. Target type: SMTP (Email).
  2. 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.
  3. 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.
  4. Recipients:
    • TO — required, at least one. Max 50 entries.
    • CC / BCC — optional. Use BCC for privacy (recipients don't see each other).
  5. 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 .p12 attachment encrypted with the passphrase from the smtp_pkcs12_passphrase credential. Share the passphrase out-of-band.
  6. Subject prefix (optional) — prepended to the default subject, e.g. [PROD].
  7. Save → health check dials the relay + walks the TLS policy + EHLO / NOOP.

05Execution flow

  1. Worker parses + validates the target's SMTP spec (relay, recipients, payload mode, credential slots).
  2. 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).
  3. Dials the relay with the configured TLS mode + AUTH if applicable.
  4. Sends one email per target containing the full TO / CC / BCC recipient set.
  5. Emits a success or a classified error (SMTP_CONNECT, SMTP_TLS, SMTP_AUTH, SMTP_TRANSIENT, SMTP_PERMANENT, SMTP_VALIDATION, SMTP_PAYLOAD).
pem_and_key sends the private key UNENCRYPTED

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_address domain must include: 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.
  • DMARCp=reject with neither SPF nor DKIM aligned means silent delivery failure. Start at p=none while 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

CodeClassRetry?Meaning
SMTP_CONNECTnetworkyesTCP dial / DNS failure. Check host, port, firewall.
SMTP_TLSauthnoTLS handshake rejected or cert unverified. Fix trust chain or set tls_skip_verify.
SMTP_AUTHauthno535 authentication rejected. Rotate the smtp_password credential + verify username.
SMTP_TRANSIENTio_transientyes421 / 450 / 451 / 452 — relay throttled or temp error.
SMTP_PERMANENTio_permanentno550 / 552 / 554 — relay denied, quota, or final reject.
SMTP_VALIDATIONvalidationno500 / 501 / 503 / 553 — malformed message or recipient.
SMTP_PAYLOADvalidationnoPEM 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.