# Subscribers Visitors can ask to be e-mailed about incidents. This page covers what happens between the "Get notified" button and the mail landing, what the install needs for it, and how to honour a "forget me" request. --- ## How it works ``` "Get notified" → confirmation mail → click → active subscriber incident update → one outbox row per active subscriber → pharos:notify → mail ``` 1. A visitor enters an address on the status page. The reply is always the same sentence (*If that address is new, a confirmation is on its way*) whether the address is new, pending or already confirmed, so the form cannot be used to find out who subscribed. Five sign-ups per ten minutes per IP; a hidden field catches bots. 2. The confirmation mail carries a **signed link, good for 24 hours**. Asking again sends a fresh link and voids the old one. An address that never clicks is **forgotten after 7 days**. 3. Every update on a **public** incident (posted by hand, through the API, or by a check that opened or resolved one) queues one row per active subscriber in `subscriber_notifications`. The request that posts the update never talks to a mail server. 4. `pharos:notify`, run every minute by the scheduler, sends **up to 50 mails per run** from that outbox. A failure is stored on the row with the error text and retried on later runs, **three attempts** at most. Internal and authenticated incidents never reach subscribers. ## What the install needs **The cron line.** The same single entry that runs the checks also sends the mail: ``` * * * * * cd ~/pharos && php artisan schedule:run ``` Without it, sign-ups still work and the outbox fills, but nothing goes out. **Mail settings**, on **Settings → Mail** in the admin: mailer (SMTP, sendmail, or "write to the log" while testing), host, port, encryption, username, password, and the From address and name. The password is stored encrypted and never shown again; leaving the box empty keeps it. Anything left empty falls back to the `MAIL_*` lines in `.env`, so an install configured by file keeps working: ``` MAIL_MAILER=smtp MAIL_HOST=smtp.example.net MAIL_PORT=587 MAIL_USERNAME=status@example.net MAIL_PASSWORD=... MAIL_FROM_ADDRESS="status@example.net" MAIL_FROM_NAME= ``` 587 + TLS (STARTTLS) works for most providers; a few want 465 + SSL. A blank From name signs mail with the brand name from **Branding**. Set it only if the sender should read differently. The "Effective" line under the form shows what a mail would go out with right now, database and `.env` combined. Prove it with **Send test e-mail**: it mails the signed-in administrator and shows the transport's own error text when it fails. **The switch.** The **Subscribers** screen has a master switch. Off means no "Get notified" button, sign-up and confirmation links answer 404, and no new mail is queued, but anything queued before the flip still goes out on the next `pharos:notify`, unsubscribe links keep working, and every address is kept. It is a pause, not a purge; the sidebar shows a small "off" next to Subscribers until it is switched back on. `APP_URL` must be the public address. The links in the mails are built from it, because a cron run has no request to read the host from. ## The mail By default (see **Templates** below) the subject is `[Brand] Incident name: Status` and the body is: the status label, the update text (Markdown rendered with the same escaping as the status page: anything that looks like a tag is shown, never run), the affected components, the time in the install's time zone, a button to the status page and an unsubscribe link. A plain-text alternative goes with it. ## Templates Admin → Configuration → **Mail templates**. Four templates, one per screen tab: | Template | Sent when | Tags | |---|---|---| | Subscribe confirmation | someone signs up | `{brand}` `{link}` `{hours}` `{name}` | | Incident opened | the first update of an incident | `{brand}` `{incident}` `{status}` `{message}` `{components}` `{link}` `{unsubscribe}` `{when}` `{name}` | | Incident updated | any later update that is not Resolved | same as above | | Incident resolved | an update with status Resolved | same as above | Tag meanings: `{brand}` the name from Branding · `{link}` the confirmation link on the confirmation mail, the status page on the incident mails · `{hours}` how long the confirmation link is good for · `{name}` the part of the subscriber's address before the `@` · `{incident}` the incident's name · `{status}` Investigating, Identified, Monitoring or Resolved · `{message}` the update text · `{components}` the affected components, comma-separated · `{unsubscribe}` the subscriber's signed unsubscribe link · `{when}` the update's time in the install's time zone. **Subject and body are Markdown** (`**bold**`, `*italic*`, `# heading`, `- list`, `> quote`, `[text](url)`). A link on a line of its own becomes a button. Tag values are printed exactly as typed (a `*` in an incident name stays a `*`), with one exception: `{message}` is the operator's own Markdown and is rendered as such, with the same escaping as the status page, so anything that looks like an HTML tag is shown, never run. `> {message}` quotes the whole message, not just its first line. A line whose only tag is empty is left out, so `Affects {components}` disappears when no component is affected. A tag that does not exist stays as typed. **Body, not frame.** The logo, the accent colour, the link to the status page and (on every incident mail) the unsubscribe link sit in the frame around the body and are always there. A template therefore cannot lose the unsubscribe link, and `{unsubscribe}` in the body is optional. The plain-text part is derived from the same Markdown with the links written out raw. The screen shows a live preview with a sample incident, rendered from the unsaved wording on the left. **Send test to me** mails that rendering to the signed-in admin through the configured mailer. Templates are stored as `mail.template..subject` and `.body` in the settings table; a missing row means the default. Saving and resetting are logged as `mail_template.saved` and `mail_template.reset`. **Brand pack.** Every install sees the screen, the defaults and the preview; saving, resetting and sending a test need the brand pack licence (checked on the server, not just in the form). Subjects are limited to 200 characters, bodies to 20 000, and neither may contain `