---
title: 'Email'
description: 'Email notifications for incident lifecycle milestones (opened, auto-resolved, closed) with multipart HTML + plain-text bodies.'
section: 'Integrations'
canonical_url: 'https://yorkermonitoring.com/docs/integrations/email'
---

# Email

Yorker sends incident notifications by email via AWS SES. Email is the **low-noise** channel: inboxes shouldn't be a running timeline, so only the lifecycle milestones that matter for async followers are routed by default.

For the underlying model (lifecycle states, event types, scoped hypothesis), see [Incidents](/docs/concepts/incidents).

## Set up

1. Go to **Settings > Notification Channels**, create an **Email** channel, and add one or more recipient addresses.
2. Or via the API:

```bash
curl -X POST https://yorkermonitoring.com/api/notification-channels \
  -H "Authorization: Bearer $YORKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "on-call-email",
    "channel": {
      "type": "email",
      "addresses": ["oncall@example.com", "sre-team@example.com"]
    }
  }'
```

| Field       | Required | Description                                       |
| ----------- | -------- | ------------------------------------------------- |
| `addresses` | yes      | At least one valid email address                  |

## What gets sent

Email dispatches on **three** events by default:

- `opened`: full context mail with observations, hypothesis, ruled-out list, and an **Acknowledge in Yorker** button
- `auto_resolved`: resolution mail
- `closed`: close-reason mail

`acknowledged`, `severity_changed`, `note_added`, `alert_attached`, and `reopened` are **not** routed to email by default. They'd turn the inbox into a timeline; use Slack or webhooks for timeline-style updates.

Every mail is multipart: an HTML body for rich clients and a plain-text alternative for others. The HTML body is styled dark (`#000` background, `#111827` card) and includes:

- Event type badge (color-coded: red for opened, teal for resolved/closed)
- Incident ID, severity, affected checks, locations, shared failing domains
- Hypothesis summary
- Ruled-out list
- **Acknowledge in Yorker** call-to-action

Subject line format:

```
Yorker Incident — CRITICAL — Checkout API outage
Yorker Incident Auto-Resolved — Checkout API outage
Yorker Incident Closed — Checkout API outage
```

CR/LF characters are stripped from every subject (header-injection guard) and the line is capped at 200 characters after render.

## Template overrides

All three parts (subject, HTML body, plain-text body) can be overridden per event type.

### Edit in the web UI

Open **Settings > Notification Channels** and click **Templates** next to the email channel. The editor has three tabs (`subject` / `html` / `text`), so you can author each part independently and see a live rendered preview:

- The HTML tab previews in a sandboxed iframe with no same-origin access, so user-supplied markup can't escape into the settings UI
- The subject tab shows a live rendered preview. The 200-character cap is enforced after render at dispatch time; the editor's character counter reflects template source length, not rendered length, so keep rendered subjects concise
- The **fixture selector** picks which canonical incident context to render against (single HTTP failure, multi-location burst, browser check, MCP)
- The **library** sidebar includes a branded incident-digest HTML example you can drop in as a starting point
- **Send test** delivers to the channel's addresses via SES using the active fixture (60-second cooldown per channel)

### Edit via the API

```bash
curl -X PUT https://yorkermonitoring.com/api/notification-channels/nch_abc \
  -H "Authorization: Bearer $YORKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "incidentTemplate": {
      "channelType": "email",
      "overrides": {
        "opened": {
          "subject": "[{{upperCase incident.severity}}] {{incident.title}}",
          "html": "<h1>{{incident.title}}</h1><p>{{payload.hypothesis.summary}}</p><p><a href=\"{{incident.triageUrl}}\">View in Yorker</a></p>",
          "text": "{{incident.title}}\n\n{{payload.hypothesis.summary}}\n\n{{incident.triageUrl}}"
        }
      }
    }
  }'
```

A render failure on any of the three parts falls back to the default version of **that** part, keeping the other overridden parts. Dispatch does not fail on a bad template.

The HTML body part renders with Handlebars' default `{{...}}` **HTML escaping enabled**, so user-supplied strings in `incident.title`, `payload.hypothesis.summary`, etc. are safely escaped. The subject and text parts render with escaping disabled (plain text).

Helper output is escaped too: `{{jsonBody x}}` is HTML-escaped by default. Use `{{{jsonBody x}}}` (triple-stash) only when you consciously need raw JSON interpolation into the HTML body; the double-stash form is always safe.

Helpers and render context are the same as the [Slack integration](/docs/integrations/slack).

## SES requirements

Yorker uses your platform's shared SES sender. Self-hosters must provision SES credentials via the `AWS_SES_REGION` / `AWS_REGION`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `SES_FROM_ADDRESS` environment variables. Dispatch fails with a logged error if SES is not configured.

## Disabling

Set `incidentSubscribed: false` on the channel to fall back to the legacy per-alert email dispatch (one mail per alert, no aggregation).
