← All engines · Delivery
Email adapter (SMTP)
stable
v1.0.0 · last updated 2026-06-06 · source: cybercli.delivery.channels.email_adapter
§1
What it does
TLS-only SMTP delivery with vaulted credentials, per-recipient throttling, and an HTML + plain-text body the operator can theme — the only channel adapter that ships enabled by default at install time.
§2
Why you care
Email is the universal fallback every operator has wired. No matter how aggressive the operator's eventual Slack / Pushover / PagerDuty setup is, email is the channel that works on day one without API keys or webhook URLs. That's why it's the only adapter enabled by default and why the EmailAdapter ships ready-to-go.
Other AI SOC products either ship a vendor-hosted email relay (your alerts go through their domain, which can flag DMARC) or require you to wire SMTP yourself with no engine support. CyberCLI sends from your own SMTP — yours from day one, no third-party deliverability dependency.
§3
How it works
On dispatch the EmailAdapter pulls the SMTP host + port + user from config and the password from the CredentialVault (AAD = `delivery:email:smtp_password`). It establishes a TLS-only connection (STARTTLS preferred, TLS-wrap fallback), authenticates, and sends the message with both an HTML body (themed by the install's brand if configured) and a plain-text body (the screen-reader-friendly fallback).
Per-recipient throttling caps the same recipient address at one email per minute by default, configurable via `[delivery.adapters.email.throttle_seconds]`. This prevents an ack-loop runaway from drowning a recipient. Throttled sends are NOT dropped — they're logged with `notification_throttled` and the AckLoop re-tries on its next interval.
§4
Configure & observe
CLI
$ cybercli channels test <destination_id> Send a test email through the configured adapter to verify SMTP credentials + DMARC posture without waiting for a real signal.
Dashboard surfaces
Configure SMTP host, port, sender address, recipients. Vault prompts handle the password securely.
Audit row shape
notification_sentnotification_failednotification_throttled parameters.channel: email + parameters.recipient_id (hashed local-part + domain) + parameters.smtp_response_code. Plaintext recipient addresses NEVER land on the audit row; the hash + the dashboard's destination roster is enough for forensic replay.
§5
Status
Stable — TLS-only enforcement + the throttle have been on the v1 acceptance install since 2026-05-15. Per-install volumes today are well below the 1 email/minute/recipient cap.
Shipped 2026-06-07: EmailChannel.fallback_configs accepts an ordered list of additional EmailConfig server configs. On primary-server failure the channel tries each fallback in declared order; the first success wins and the rest of the chain is skipped. When every server fails, the DispatchResult.error_message joins each attempt's hostname + error with ' | ' so the audit row preserves the full failover trail. Default fallback_configs=[] preserves pre-r16 single-server behavior exactly.
Known limit: SPF + DKIM + DMARC posture validation is on the install-1 checklist as a doc but not yet a doctor check. Adding it to `cybercli doctor` is a v1.x item.
How this engine talks to the rest