# Notification channels

For a step-by-step phone connection, see [Connect the App](connect-app.md).

## Configure in the console

1. Open **Notifications** and choose Bark, Pushover, Webhook or Mailwake App.
2. Fill the selected channel's fields below. For Mailwake App, first [pair the phone](connect-app.md), then choose the receiving phone.
3. Choose the preview, notification language and retry count. A retry count of 0 makes one attempt.
4. Save, then explicitly send a test notification. Check the phone or webhook receiver and the delivery result.

The settings apply to all mailboxes. Changing settings preserves queued work according to its existing delivery plan; verify future behavior with a new message.

## Channel configuration

Configure the global channel through `/api/v1/settings/delivery`, sending its current `revision`. Channel, preview, retry count and notification language apply to all mailboxes. All credentials are encrypted and write-only; omitted credential fields keep their saved values when the target is unchanged. Changing a saved Bark endpoint requires re-entering its device key.

| Channel    | Parameters                                                                                                                 | Credentials                                                                |
| ---------- | -------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| `bark`     | `bark.endpoint`, default `https://api.day.app`                                                                             | `bark.key`                                                                 |
| `pushover` | none                                                                                                                       | `pushover.token`, `pushover.user`                                          |
| `webhook`  | HTTPS, query allowed                                                                                                       | `webhook.url` and `webhook.secret` (at least 32 non-whitespace characters) |
| `native`   | Official production push delivery service by default; override with `MAILWAKE_RELAY_URL`; pair phones in App authorization | Locally generated, encrypted outpost identity                              |

Webhook URLs are write-only because paths and queries may contain routing credentials. `preview` accepts `off` or `subject`; `retry_count` accepts 0–9 and defaults to 0; `language` accepts the [nine catalog codes and their regional aliases](api.md#languages-and-error-codes) and defaults to `en`. Bark and Pushover show only the subject with `subject`; Webhook retains structured sender and subject, while its `message` also contains only the subject. `off` (and an empty subject) uses the localized “New mail” message. Titles stay `{display name} · {folder}`; Bark groups by that same truncated title. Test notification text is unchanged. API input `sender_subject` returns 400 `config_preview_invalid`. For third-party channels, switching from `subject` to `off` atomically removes sender and subject from all pending and failed records; later enqueues also follow the saved privacy policy. Native push always records sender and subject while preserving the third-party preview preference.

Bark history retention follows the Bark app's save-history setting for both mail and test notifications.

### Webhook payload

The outpost sends a `POST` with a JSON body and never follows redirects:

```json
{
  "version": 1,
  "id": "3f9c…",
  "test": false,
  "mailbox_id": "mbx_example",
  "account": "Work mailbox",
  "folder": "Clients",
  "sender": "anna@example.org",
  "subject": "Re: Q4 proposal",
  "received_at": "2026-09-28T10:32:00Z",
  "title": "Work mailbox · Clients",
  "message": "Re: Q4 proposal"
}
```

`mailbox_id` is the stable mailbox ID; `account` is its display name at enqueue time. Bark, Pushover and Webhook ordinary notifications use the title `{display name} · {folder}` in all supported languages. Renaming or deleting a mailbox preserves the identity metadata of already queued tasks. Test notifications use separate text and omit mailbox fields.

`sender` and `subject` appear only with the `subject` preview. `title` and `message` are localized and ready to forward to ntfy, Gotify and similar services. The display name and folder are sent even with preview off; choose a label suitable for sharing with your notification provider.

| Header                 | Meaning                                                                       |
| ---------------------- | ----------------------------------------------------------------------------- |
| `X-Mailwake-Event`     | Event ID, equal to `id`; unchanged across retries, use it to deduplicate      |
| `X-Mailwake-Timestamp` | Send time in Unix seconds                                                     |
| `X-Mailwake-Signature` | `sha256=` followed by the hex `HMAC-SHA256(secret, "<timestamp>.<raw body>")` |

Verify the signature with the same secret using a constant-time comparison, and reject timestamps more than five minutes away:

```python
import hashlib, hmac, time

def verify(secret: bytes, timestamp: str, body: bytes, signature: str) -> bool:
    expected = "sha256=" + hmac.new(secret, timestamp.encode() + b"." + body, hashlib.sha256).hexdigest()
    return abs(time.time() - int(timestamp)) <= 300 and hmac.compare_digest(expected, signature)
```

Any 2xx response counts as accepted. 429 and 5xx follow the retry setting; other statuses end the attempt and record a failure.

Saving notification settings validates fields, addresses, pairing state and revision without sending a test. Use the explicit test button after saving. Native tests use the push delivery service’s fixed free test endpoint and share the App test quota; ordinary email notifications require Native Push entitlement.
