internal/milter/sign.go: a milter on two sockets (cmd/panel/signer.go):
sign.sock for 465/587, the key of the domain the SASL login belongs to
(Bindings.DomainOf, the sender_login_maps Postfix reads), and
sign-local.sock for the panel's own sendmail(1) mail, the server's name.
go-msgauth/dkim v0.7.0, relaxed/simple, OpenDKIM's dkim_should_signhdrs[]
(libopendkim/dkim.c:223-246) in message order plus From once more; keys
and selectors from the KeyTable the panel writes, a key path outside the
key directory refused; strict - whatever cannot be signed is deferred.
From the sources: Postfix 3.10.13 milter8.c:2329-2400 hands a folded
header \n-separated, so the signer joins its lines with CRLF; inserts are
1-based in cleanup_ins_header() (cleanup_milter.c:1193), so index 0 is the
top, where OpenDKIM puts its own (opendkim.c:3673). go-milter v0.4.1 calls
no Abort when a connection ends, so a watchdog closes go-msgauth's
streaming signer after an hour and a late end of message is deferred.
Postfix: smtpd_milters = sender check, signer, OpenDKIM, journal;
non_smtpd_milters = the signer's local socket, OpenDKIM - both sign every
message until stage 2. disable_mime_output_conversion=yes (default off,
mail_params.h:3088): an 8-bit message is no longer re-encoded after it is
signed.
Tests: unit tests sign and verify folded, tab-led and space-free headers,
an added From:, a changed body, two messages on a connection, odd bodies,
and five cases deferred. e2e: the sink image has python3-dkim (dkimpy
1.1.8-2) and the stand's DNS; on an application's message and on a
notification the two signatures must agree on h=, bh=, c=, s=, a= and each
must pass dkimverify. On the server: make e2e exit 0 (714 s), go vet + go
test 27 packages ok.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The pages of the mockups accepted in 87fa0a4, built from the kit's partials
(written by a Sonnet agent into the working tree, reviewed here):
- Account: "Send me notifications" in the Profile form, saved with the
profile; an unticked box is off.
- Server > Settings: the instance switch (box 03), and box 04 Notification
mail with the DKIM and SPF records of the server's own name, drawn with the
record partial of a domain's DNS page and checked in DNS. Sending rate
limits are box 02 in the left column. A record that is not in place is
tagged as a warning, not a failure: notifications are sent without it.
- Server > Health: card 06 Notification mail with the state of each record
and a link to Settings, beside Configuration (07); part of the polled
fragment; Re-check DNS forces it too. Overview does not run this check.
- help.go: the Notifications topic and the clauses in Settings and Your
account, word for word with help.html.
If the server's key cannot be read the pages still render: the DKIM record
is left out and SPF is shown unchecked.
e2e: the administrator gets a mailbox behind the sink and the server's DKIM
record from Settings is published; the level-2 refusal of the next step must
then arrive as a notification from postmaster@mail.e2e.test, signed as that
name with the key Settings shows, and must not be a row of the Outbound log.
The rotation step now waits for Postfix to be running: it follows a step that
restarts the container, and logrotate's `postfix reload` failed in between.
On the test server, for this tree: go vet clean, go test ./... 23 packages
ok, make e2e ok (147 s); the notification reached the sink 28 s after the
refusal.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>