# Notifications

The bell icon in the topbar opens a dropdown of unread notifications. Settings tab governs which categories generate panel + email notifications (login attempts, account events, license, updates, security, system).

Notifications are deduped on the server side: the same upstream WHost version cannot trigger two "Update available" emails; the same OS security count cannot re-emit until the count actually grows.

**Notification settings** (`/admin/settings/notifications`). The save replaces the stored event matrix and template list with what it receives; an event id or a template for an event outside the fourteen-row matrix is refused with `422` instead of being dropped (a dropped row would have emptied the matrix). The **Use External SMTP** switch mirrors the stored relay: it is on when a host is stored, and switching it off clears the host, username and password with the next Save — the local mail service takes over. The sender fields (host, username, From name, From e-mail) refuse control characters. **TLS** negotiates STARTTLS on whatever port is set, port 25 included; a relay that does not offer it fails the send rather than getting the message in the clear. With **TLS** or **SSL/TLS** the relay's certificate must chain to the server's trust store and be valid for the host entered; a self-signed or expired certificate fails the send (the server's own mail service on `localhost` is encrypted without that check). The password field keeps the stored password while it shows the masked value only as long as the host, port, username and encryption stay as they were saved: change any of them and type the password again, or the Save and the test e-mail answer `400 SMTP_PASSWORD_REQUIRED`. A save that only changes the SMTP password writes a `notification_settings_updated` audit row (`smtp_password_changed`), and a notification e-mail the relay refuses writes a `notification_email_failed` audit row naming the recipient and the relay — the agent log is no longer the only trace. A limiter answer on Save, on a template Save or on the test e-mail is reported as an error, and a failed settings read shows an error state instead of the defaults, so a Save can never overwrite the stored settings with them. The SMTP password is kept in `agent.conf` (`admin.notification_smtp_password`, readable by root only) rather than in the preferences file, so it survives an agent restart; the API and the panel show a stored password as the same row of twelve dots whatever it is (neither its length nor any of its characters), and clearing the field removes it from the file as well.

**E-mail templates** (Templates tab). Every event ships with a default e-mail in the common layout. Above the message, on the white page, sit the brand's logo and the server's name. The message itself is a card tinted by the event's level (reddish for a failure, amber for a warning, green for a completed job, blue for a notice): a status line in the event's colour, the affected domain, service or address as the heading, the details in white fields with rounded corners (two to a row, one to a row on a phone), the error or the release notes in a field of their own and, on a failure or a warning, what to do together with the button to the control panel in a field of its own. The brand is the licensed whitelabel's company name and logo, else WHost's; the footer names it. Only a PNG or JPEG logo goes out as an image: mail clients show no SVG or WebP, so such a logo leaves the company name in its place. The logo travels inside the message as an embedded image, so it shows even when the panel's address cannot be reached from the internet or the mail client blocks remote images. Host and domain names in the message are links in the colour of the text around them, so a mail client that turns bare names into links (Gmail) does not paint them blue. The sign-in code, the password reset link and the SMTP test message use the same layout. The editor opens the template in force; a template you change is marked **Customized** in the list, and **Reset to default** puts the default text back into the editor. Only a template that differs from its default is stored, so the events you have not changed follow the default when an update changes it; a template an earlier release stored without an edit is passed over and leaves the file with the next save. **Preview** fills the variables with sample values. The panel next to the editor lists the event's variables; `{{hostname}}`, `{{server_ip}}` (the server's public address as configured; empty when none is set), `{{site_ip}}` (the account's own address when the message is about an account that has one, else the server's), `{{panel_url}}`, `{{login_url}}` (the recipient's sign-in page: `/admin` on the operator's copy, `/client` on an account's) and `{{year}}` work in every template. A variable the event does not supply stays visible as `{{name}}` in the preview and in the sent mail. Values are inserted as text, so markup inside an error message or a suspension reason is shown, not interpreted. In the subject a value stays on one line: the line breaks of a multi-line suspension reason become spaces there. The account's copy of a failed-backup e-mail says the backup did not finish without the server's error text; the operator's copy carries the error.

The inbox keeps the newest 500 records. Mark-read, mark-all-read and delete act on the operator's inbox only — a tenant's record is never touched by them (the firewall page's "mark all read" follows the same rule). **Clear All** in the inbox deletes every record of the operator's inbox after a confirmation — admin-targeted and broadcast records; a tenant's own records stay — and writes a `notifications_cleared` audit row; it is not a mark-all-read. The bell badge shows the inbox-wide unread count, not the count of the rows the dropdown lists, and a record marked read from the bell is read on the inbox page at once. The list answer's `total` is the size of the inbox, `unread_count` the unread part of it. A record the panel switch or the event matrix suppresses is not stored: the push answers `stored: false` with no `id`. The event matrix on the notification settings page starts with the panel column on for every event; switching a row's panel column off silences that alert in the inbox (the agent log still records the event as suppressed).

**Endpoints used:** `GET /admin/notifications`, `POST /admin/notifications`, `POST /admin/notifications/{id}/read`, `POST /admin/notifications/read-all`, `DELETE /admin/notifications/{id}`, `DELETE /admin/notifications` (Clear All), `GET/PUT /admin/notifications/settings`, `POST /admin/notifications/test-email`.

---
