The decision the issue asked for: gitbay's log names the mail, not the person.
Of the three options, logging the recipient's user id needs a column the queue
does not have — notifications is (id, recipient, subject, body, attempts, ...) with no user, and adding one means a migration plus a change at all three
enqueue sites. Hashing gives an operator something they cannot act on, and an
address hashes into a small enough space to be worth little. The queue row id is
already a stable handle, already in QueueMailRow, and already actionable.
So: notification dead-lettered mail=<id> attempts=<n>, and the address stays in
the database where /admin shows it to an instance admin. One rule for every mail
type, since notifications, dependency reports and login links all drain this one
queue — this was the only site that logged an address at all.
One thing the issue did not raise: a relay's rejection normally quotes the address
it rejected (550 5.1.1 <x@y>: Recipient address rejected), and that error was
being logged next to the recipient field. Removing the field alone would have
moved the leak, not closed it, so the error is redacted for the log. The
unredacted text still goes to the queue row, so nothing diagnostic is lost — the
error class, which is what an operator acts on, survives redaction intact.
/admin's Mail table gains the id column, so a logged id is findable in the UI
rather than only in the database.
TestRedactAddresses covers the rejection forms and checks non-address errors
(connection refused, x509) pass through unchanged;
TestRedactLeavesNoAddress asserts no address survives, whatever the relay said.
Recorded in the Threat-Model page's "what gitbay never does" list, so a future mail type inherits the rule instead of rediscovering it, and in Admin beside the queue docs with the operator path from a log line back to the row.
Closes #173