Subscribers
A published status page carries a form where a reader can leave an e-mail address. This page is about what that subscription actually does — for the reader who signed up, and for the operator who wonders what their subscribers are receiving.
What reaches a subscriber’s inbox
Section titled “What reaches a subscriber’s inbox”After the confirmation e-mail, the only thing that reaches a subscriber is an update you post. A monitor going down does not. An incident opening does not. A component turning red does not.
The fan-out hangs off the insertion of a public update, and it takes its recipients from that update’s own page. A subscription is therefore a way to hear what you have chosen to say about an outage — not a way to be paged when one starts.
Editing an update notifies nobody. Correcting a typo, adding a detail or moving the update to another state sends nothing at all. To tell your subscribers something new, post a new update.
A subscriber who never confirmed receives no updates. Every fan-out skips them, for every update, indefinitely — the confirmation e-mail is the only thing that address is ever sent. Confirmation is not a courtesy step you can wave through on their behalf.
The two links in the e-mail
Section titled “The two links in the e-mail”A confirmation link works exactly once. The first visit confirms the subscription; every visit
after that answers 404, and so does a token that was never issued. Nothing the reader sees tells
those two apart. That is deliberate — a confirmation link is not a way to find out whether an
address is subscribed to a page.
A confirmation link does not expire. Nothing in the confirm path looks at how old the token is, so a reader who finds the e-mail a month later can still use it, provided nobody used it first.
Unsubscribing deletes the subscription; it does not pause it. The row is removed. There is no paused or opted-out state to return from.
Coming back means confirming again. A later subscribe from the same address is a new subscription, stored unconfirmed like any other, and it needs its own confirmation click before anything reaches that inbox.
The three silences
Section titled “The three silences”Six different outcomes give the reader the same answer. An unknown page, a page that is not
published, an address that has already confirmed, an address that was sent a confirmation too
recently, an address that is due another one, and a genuinely new subscription all end in the same
202 Accepted with the same body. That is deliberate — the form cannot be used to find out whether
a status page exists, or whether an address is already on one.
The rate limit is the one answer the handler itself writes that is not the shared 202.
Submitting the subscribe form too often for the same page is refused with a 429. Those two codes
are the only ones the subscribe handler writes, and it raises nothing of its own — a failure in the
database call beneath it is answered 500 by the shared error handler, as anywhere else in the API.
A malformed address is refused before the handler runs at all. The route checks the body
against its own schema first, and that schema is stricter than the type="email" check the
subscribe form renders: me@localhost and a@b.c are submitted happily by a browser and answered
400 invalid request here. That refusal comes from the shared error handler, not from the
subscribe path, so none of the six outcomes above is reached.
The limit is counted per page and per requesting origin, never per e-mail address. Two different addresses submitted from one origin draw on the same budget, and one address submitted from two origins draws on two.
A confirmation e-mail can be sent again, at most once every fifteen minutes. Submitting the same address on the same page again re-sends the confirmation, carrying the same link the first one carried rather than a new one — so an e-mail that arrives late still works. Inside those fifteen minutes the submit stores nothing new and sends nothing, and an address that has already confirmed is never sent one again. Somebody who lost the first e-mail can ask for another, and where they submit from makes no difference — the window is not counted per origin.
The window is counted per status page and per mailbox, and it limits how often rather than how
many in total. The same mailbox submitted on two of your status pages has a separate window on
each. Capitalisation is not what separates them: the address is lower-cased before it is stored or
matched, so A@B.com and a@b.com land in the same window on the same page. And an address that
keeps being submitted keeps being sent one confirmation every fifteen minutes, for as long as the
submits keep coming — the window paces the confirmations rather than putting a ceiling on them.
Delivery gives up. A send that fails is retried, and each retry waits longer than the one before
— the delay doubles with every attempt. After a fixed number of attempts the notification is marked
failed instead of pending, and a failed notification is never picked up again. That one
subscriber does not get that one update, ever.
With no e-mail provider configured, the product goes quiet in two different places. A subscribe
still stores the row and never sends the confirmation; and queued update notifications are never
leased at all, so they sit pending rather than turning failed. Both of those depend on how an
installation is configured, not on anything a reader or an operator does.
When the page goes away
Section titled “When the page goes away”Deleting a status page deletes its subscribers. Every subscription to that page is removed with it — the rows belong to the page through a foreign key that cascades, so there is no leftover list to restore or to re-attach to a new page.
What the operator can see
Section titled “What the operator can see”No operator screen can read a subscriber’s address. The database grants the application role exactly six columns on the subscriber table — the identifiers, the confirmed flag and the two timestamps. The e-mail address is not one of them, so a direct query for it is refused by the database rather than filtered by the product.
One database function hands the address back, and it exists so that an e-mail can be addressed. The worker that drains the queue leases due notifications through a function that runs with its owner’s privileges rather than the caller’s, and every leased row arrives carrying its recipient and that subscriber’s unsubscribe token. It takes a batch size and nothing else. Only two other functions the application may call name a subscriber’s address at all, and both belong to the subscribe form: they take one and write it down. Those three are the whole of it.
And an operator cannot help with a lost confirmation. Nothing an operator can reach reads the address, so there is nothing for a support screen to act on. The subscriber is not stuck, though: submitting the same address on the form again is what sends them another one.
Subscribing is free on every plan. Nothing on the subscribe path reads an entitlement — not the public routes, and not either of the two database functions behind them. A page on the Free plan collects subscribers exactly like a page on any other.
The two surprises
Section titled “The two surprises”Unpublishing a page stops the URL and the e-mail, but it keeps everything else. An unpublished
page answers 404 to readers, and posting an update to it reaches nobody. Only the last of the four
layers between that update and the queue looks at whether the page is published: the route that
loads the page, the statement that writes the update and the row-level policy that guards that write
all ignore it, and the fan-out that turns the update into queued e-mail is the one that joins the
page and queues nothing while it is unpublished. So the update is still written down and still on
the timeline when you publish again — and publishing again sends no backlog, because nothing was
queued in the meantime. The subscriptions are still there too. Deleting the page is the only thing
that takes them.
Two spellings of one address are one subscription, and the spelling is not kept. A@B.com and
a@b.com reach the same row: the address is lower-cased on the way in, and a unique index on the
page and the lower-cased address refuses a second spelling outright. So there is one confirmation
link and one unsubscribe link, and unsubscribing takes the subscription rather than half of it. What
you typed survives only as the To: of the confirmation that was sent; the stored address is
lower-cased. Where a page already held both spellings they were merged into one, and the survivor is
whichever confirmed first — so an unsubscribe link already sitting in somebody’s inbox keeps
working — with the other removed along with anything it had queued.