Files
selfpost/docs/plans/panel-notifications.md
T
mixandClaude Opus 5.5 ce7b09a65c
test / test (push) Canceled after 0s
release: 2.3.0: the panel writes to its users
panel-notifications (docs/plans/panel-notifications.md, 10/10), at the
owner's word (2026-10-12, "Да").

  - Four things are reported by e-mail, each once: a sending domain's
    DNS record that does not match, a level-2 rate limit refusing mail,
    the TLS certificate about to expire, a message more than three days
    in the queue. Global users are told all of it, domain users about
    their own domains.
  - Sent from postmaster@<SELFPOST_HOSTNAME> and signed with a DKIM key
    of the server's own name, which the panel generates.
  - Account has the user's switch, Server > Settings the instance's and
    the two DNS records to publish, Server > Health their state.
  - An account e-mail may now be at a public mail host.
  - Migrations 0004 and 0005.

Upgrading: publish the two records Server > Settings shows for the
hostname (a DKIM key and "v=spf1 a -all"); until then notifications are
sent and may be filed as spam. Every user with an e-mail starts with
notifications on. non_smtpd_milters now names OpenDKIM.

Accepted and recorded in security.md: an application can have a message
signed as the server's own name by writing it into From: (roadmap
candidate from-header-binding).

Cut: CHANGELOG [Unreleased] -> [2.3.0]; image pin 2.3.0 in compose,
README, guide; version table, roadmap, plan status. No tag: the owner
tags when he decides to (2026-10-11), so there is no image of this
version until then.

On the test server, on f09b60a: go vet ./... ok, go test ./... ok
(23 packages), make e2e ok.

Full detail: CHANGELOG.md (2.3.0).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 17:08:37 +03:00

7.0 KiB
Raw Blame History

Plan: panel-notifications

Status: shipped in 2.3.0 (2026-10-12); agreed the same day - the design questions were closed with the owner and he took it into work ("Делаем")
Date: 2026-10-12
Version: 2.3.0 MINOR (one migration; opt-out by a switch).


Goal

The panel writes to its administrators when something needs them, instead of waiting to be opened.

Decisions (owner, 2026-10-12)

Events of the first version

Four, each of them something the panel can already tell and a person has to act on:

Event Who is told
A sending domain's DNS record stopped matching (SPF, DKIM, DMARC) global users, and domain users the domain is assigned to
A level-2 rate limit refused mail the same, for the domain of the limit
The TLS certificate is about to expire global users
A message has been in the queue for more than three days global users

Three days, not one (owner: "one day is not that much"): Postfix keeps a message five, so two are left to act before it bounces. The threshold is a constant, not a setting.

Left for later: a process or milter socket down (a relay in that state often cannot send), an inbound upstream unreachable, DMARC failures appearing (noisy). Mail held in quarantine is not an event: quarantine is an idea outside the roadmap.

Sender and path

From postmaster@<SELFPOST_HOSTNAME>, submitted locally. Not from one of the sending domains (owner): with several domains the choice is arbitrary, and a message about the certificate has no business coming from a domain.

These messages have to arrive (owner: "we need the best deliverability for them"), so the server's own name gets what a sending domain has:

  • a DKIM key for the hostname, generated by the panel, with which notifications are signed - no domain has to be chosen for it. An SPF record alone would pass DMARC, but not after the user's mailbox forwards the message on, and large receivers treat unsigned mail more strictly;
  • an SPF record for the hostname, v=spf1 a -all.

The records themselves are under Server › Settings (owner: "the DNS records go to Settings, Health has only the status"), in a box of their own drawn with the record component of a domain's DNS page: host, value to publish, copy buttons, state. Server › Health has a card of its own, Notification mail, with the state of each record and a link to Settings. A DMARC record for the hostname is not asked for: the name inherits its parent domain's policy, and with SPF and DKIM aligned it passes any. Without the records notifications are still sent, and the card warns.

Notifications are the panel's own mail: they are not rows of the Outbound log and count against no level-2 limit.

A relay that cannot send cannot say so; none of the four events is "the relay is down", and that is why.

Who chooses what

  • One switch for the instance under Server › Settings.
  • One checkbox per user under Account, "send me notifications" - on when the profile has an e-mail. No choice per event: four events, none of them noise. Per-event choice comes when there are more and some are.
  • A user without an e-mail gets nothing.

When a message is sent

A background check once an hour for DNS, certificate and queue.

Event Sent "Cleared" message
DNS mismatch after two checks in a row found it (it has held for an hour). A resolver that did not answer is not a mismatch after two good checks in a row
Certificate 14 days before expiry, and again 3 days before if it is still the same certificate none
Level-2 limit refused mail at the first refusal of a sending domain's applications, then at most once a day for that domain (one subject per domain, as built: what the refused row says of its domain is the client's own word, so the registry is asked) none
Queue older than three days when such a message appears one, when none is left

Event state is kept in the database, so a restart announces nothing a second time.

To settle while building

  • How the panel submits: sendmail as the unprivileged panel user, and what that needs of the image.
  • Whether a notification carries a link to the panel - there is no setting for the panel's own address.
  • Where the refusal of a level-2 limit is noticed: in the journal milter as it refuses, or from the rejected rows of the send log on the hourly check.
  • Schema: the user's checkbox, the instance switch, the event state table.

Screens

Not drawn. The Notifications box was taken out of the account and settings mockups on 2026-10-10 (owner: 2.0 ships no box for a feature that is not built). Drawing them again - one checkbox on Account, one switch on Server › Settings, the SPF check on Server › Health - is the first step, shown to the owner before any code (panel-redesign.md § Enforcement).

Implementation checklist

  • Mockups: Account checkbox, Settings switch and records, Health status card, help topic; accepted by the owner 2026-10-12 (design: commit)
  • Migration and store: user flag, instance switch, event state
  • Sending: local submission from postmaster@<hostname>, message text (sendmail as the panel user; signed through non_smtpd_milters with a key of the server's own name; no link in the text - the panel does not know its own address)
  • Background checker: DNS, certificate, queue; the rules of When a message is sent
  • Level-2 refusal event (from the rejected rows of the send log, looked at every minute)
  • Panel: Account, Settings, Health card, help
  • guide.md, architecture.md, security.md, schema-migrations.md
  • go vet, go test, e2e: a level-2 refusal reaches a mailbox as a signed notification (on the test server: vet ok, 23 packages ok, e2e ok; "once" and "clears" are held by the unit tests of internal/notify)
  • Technical review — Opus (2026-10-12; no Critical. Fixed: refusals counted by the registered domain and only under a limit, with an index of their own; account e-mails may be at public mail hosts; "said" means sent; DNS checks must be 45 minutes apart; the notifier's own mail is not a queue subject and a cut or unreadable listing is no listing; the tables must name the selector the panel shows; an unanswered a/mx lookup is not an SPF mismatch; a pass stops between domains at shutdown; days are rounded as a person counts. Left as found: a recipient whose copy failed while another's went out is not retried; a certificate that lives under 14 days is reported at each renewal)
  • Security review — Fable (2026-10-12; no Critical. Fixed: the limit notification was built on the domain a client writes in MAIL FROM - a mail cannon and a way to write to another tenant's users; a ceiling of 60 messages an hour; security.md corrected on who can submit locally and on what the account e-mail now is. Recorded as accepted, with a roadmap candidate: an application can have a message signed as the server by writing its name into From: - the header is not held against the login, for sending domains either)