Skip to content

feat: notification channel seam + optional SMTP email (env opt-in) #362

Open

Description

@ajianaz

Summary

Introduce a notification-channel seam in the alert engine and add an optional SMTP email adapter, configured entirely via env — absent env = disabled = zero behavior change.

Why

  • Alert delivery is currently webhook-only, hardwired in alert.rs (reqwest POST). Email is the standard second channel (GlitchTip ships it out of the box) and the fleet already runs Stalwart SMTP.
  • Owner requirement: email must be opt-in via env so default deployments stay zero-config.

Design (seams)

  • New seam in the alert engine: trait NotificationChannel { async fn deliver(&self, signal: &AlertSignal) -> Result<()> }.
  • Existing webhook logic becomes the first adapter; SMTP (via lettre, rustls TLS) the second. Two adapters = the seam is real, not hypothetical.
  • Config (all optional): TRAPFALL_SMTP_HOST, TRAPFALL_SMTP_PORT, TRAPFALL_SMTP_USER, TRAPFALL_SMTP_PASS, TRAPFALL_SMTP_FROM, TRAPFALL_ALERT_EMAIL_TO. Missing TRAPFALL_SMTP_HOST = adapter never constructed (zero overhead).
  • Secrets stay env-only; never persisted to DB, never logged.
  • SSRF hardening is webhook-specific; SMTP transport does not need it — but credential redaction in logs still applies.

Acceptance criteria

  • Webhook behavior byte-for-byte unchanged when SMTP env is unset (regression tests prove it)
  • Email delivered for alert signals when env set; send failure logs + respects cooldown, never blocks the webhook path
  • Adding Config fields requires 3-place update rule followed (struct + defaults + parse + from_env + tests_base_cfg)
  • cargo clippy --workspace -- -D warnings clean; env table added to README/docs
  • Depends on fix: underscore package names for internal crate deps #1 (AlertSignal enum) — merge order 1 → 3

Non-goals

  • Per-user notification preferences, HTML templates, other channels (Telegram, PagerDuty, etc.)

Notes for implementer

  • Branch from fresh origin/develop. No AI attribution in commits/PR (fleet standard).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions