Skip to main content

Set up Slack or email alerts

Goal​

You'll create an alert rule that posts to Slack and/or emails a distribution list whenever a validation run fails.

Slack and email dispatchers are shipped (worker/.../dispatch_alert.py). Microsoft Teams (FEATURE-15), generic webhooks (FEATURE-16), PagerDuty (FEATURE-17), and the incident-management bridges (Jira / Linear, FEATURE-28) ship as separate channels — see Alerts for those.

Prereqs​

For Slack​

  • A Slack incoming-webhook URL (https://hooks.slack.com/services/T…/B…/…). Create one at https://api.slack.com/apps → Create app → Incoming webhooks → enable + add to your #data-quality channel. Copy the URL.

For email​

  • The Measured Cloud deployment has SMTP configured. Check that SMTP_HOST, SMTP_USER, SMTP_PASSWORD, SMTP_FROM are set in .env (see Configuration). Without these, the dispatcher will log "smtp not configured" and skip the channel.
  • A target email or comma-separated list (oncall@example.com,data-leads@example.com).

Steps​

  1. Navigate to Alerts → Add alert rule. A rule has no free-text name — it's named after what it watches and where it sends (e.g. Nightly orders · Slack on failure), which is how it's labelled on its own page and in the alert history.

  2. Pick a scope:

    • Specific validation(s) — pick one or more validations; the rule fires on their runs.
    • All validations — fires on any validation's run in the workspace.
    • Full workspace — fires on anything in the workspace (the default). Use sparingly.
  3. Pick the severities the rule fires on — any combination of Info, Warning, and Critical (see Routing by severity).

  4. Pick a trigger:

    • on_failure — fire when the result has success = false. The common choice.
    • on_anomaly — fire when an AnomalyEvent is written for an asset in scope.
    • on_success — fire on every successful run (useful for "data landed" confirmations).
    • always — every run, regardless of outcome.
  5. Pick a channel:

    Slack:

    • Channel = slack.
    • Webhook URL = paste the Slack incoming-webhook URL.

    Email:

    • Channel = email.
    • Recipients = comma-separated email list.
  6. Save. Optionally, click Send test — Measured Cloud fires a synthetic payload to the destination so you can confirm the channel works before a real failure.

Verify​

  • The rule appears under Alerts with enabled = true.
  • Click Send test → the message shows up in Slack (or the test recipient's inbox) within a few seconds.
  • On the next real failure, you receive a notification with the failing expectation list and a deep link to the result detail.

Checking alert history​

"Did the alert actually send?" is the first question after any failure — so every alert rule keeps an alert history of its dispatch attempts.

  • Every rule at once: on the Alerts page, expand Alert history below the rules list. It lists recent firings across all of the workspace's rules, newest first — each labelled with the rule's name (<scope> · <Channel> <trigger>, e.g. Nightly orders · Slack on failure, linked to the rule) and fired by the validation whose run triggered it (linked to that validation), plus the status, channel, time, and any error. Load more walks further back.
  • One rule: click the rule's row to open its page; the Alert History card lists that rule's dispatch attempts newest-first: when it fired, the status (Sent / Failed / Pending), the channel, and — on a failure — the error message. The empty state ("This alert hasn't fired yet.") tells you at a glance whether the rule has ever triggered.
  • A rule that's enabled but whose alert history is empty has never matched a result; an alert history full of Failed rows means deliveries are breaking (check the error — a 404 usually means a revoked webhook URL).
  • The same data is available over the API at GET /api/v1/organizations/{org_id}/workspaces/{workspace_id}/alert-rules/{id}/events (one rule) and .../alert-rules/events (every rule, with the rule + validation names), both paginated {"data": [...]}. Any secret that leaked into an error message (a webhook URL's secret path, a token) is redacted before it reaches you.

Caveats​

  • Slack webhook URLs are bearer credentials. Measured Cloud stores them encrypted at rest via the per-tenant DEK (HARDEN-15); a legacy plaintext fallback is kept on the read path so existing rows keep working, and the dispatcher logs alert_destination_legacy_plaintext whenever it falls through that path. Per-tenant DEKs under a KMS-backed KEK are tracked in HARDEN-16.
  • The dispatcher retries up to 3 times with exponential backoff on transient failures (timeouts, 5xx). Persistent failures land as a Failed row in the rule's Alert History card (see above), with the error message attached.
  • One rule, one channel. To send the same alert to Slack + email, create two rules with the same scope.

@mentioning users and groups (Slack, Teams)​

When an alert fires, the message lands in the channel but doesn't ping anyone by default. To target specific people or groups, fill in the Mentions field on the alert-rule form.

Slack:

  • With a Slack bot token connected (Settings → Integrations — see Show Slack display names in mentions), the field is a picker: type a person's name and pick them from the list (arrow keys + Enter, or click). Each pick shows as a chip with the person's name; the × on a chip removes it. To mention a user group, paste its ID (S…) and choose Add … by ID.
  • Without a bot token, paste a comma-separated list of Slack member IDs (U…) or user-group IDs (S…). Find a member ID in Slack via Profile → Copy member ID; user-group IDs are in the user-group settings URL.
  • Either way, the rule stores the IDs — Measured Cloud wraps each one server-side into Slack's mention format (<@U…> / <!subteam^S…>) and prepends them to the outbound message text so the channel members get pinged. Names are only for display: the rule's page (including the read-only view a viewer sees) shows each mention by name.

Microsoft Teams:

  • Paste a comma-separated list of User Principal Names (alice@example.com). Measured Cloud wraps each one as <at>alice@example.com</at> and emits the paired msteams.entities block the Adaptive Card mention contract requires — without that block Teams would render the tag as literal text.

Other channels (email, generic webhook, PagerDuty) have no transport-level mention concept. The field is silently ignored for those rules — use the destination's own routing instead (a different to: address, a different webhook URL, a different PagerDuty service).

Routing by severity​

Each alert rule fires on an explicit set of Severities — tick any combination of Info, Warning, and Critical (default: Critical only). It's set membership, not a minimum: a rule set to just Warning does not fire on a critical result. The alerts list's Severities column shows exactly what each rule is set to. Model one rule per channel with the severities it should carry — PagerDuty on Critical, Slack #warnings on Warning, an email digest on all three. The full grading table and worked example live in Alerts → Severity routing. Shipped in FEATURE-10 + FEATURE-18; explicit sets in #146.