The server side of the deliverability check (inbuxa-drafts specs/deliverability.md, approved 2026-10-05). Admin UX roadmap item 7; the console page follows in inbuxa-admin.
What each sending node checks, about itself
Its addresses (DL-1, DL-2): the connection strategy's source addresses, or what its EHLO name resolves to when none are set (production's case: each node leaves from its own namespace). It never asks a third party what its address is.
Reverse DNS (DL-5): PTR, whether it resolves back, whether it's the EHLO name.
Blocklists (DL-4, DL-6, DL-12): Spamhaus ZEN, SpamCop, Barracuda, UCEPROTECT L1, Mailspike, PSBL for addresses; Spamhaus DBL, SURBL, URIBL for domains. Each list's answer is read by its own code table: a refusal (Spamhaus 127.255.255.254 to a public resolver, URIBL 127.0.0.1) or an undefined code is refused, never listed.
Per domain (DL-7 to DL-11): SPF for each address; each DKIM key, by signing a message that's never sent and verifying it as a receiver would (missing vs different); DMARC policy and alignment modes; MTA-STS record, fetched policy, mode, and MX not covered; TLS-RPT present.
Certificates (DL-13): EHLO names and the server's MX names that point at the node.
The report holds facts only; the console grades them.
When (DL-14 to DL-16): daily at a minute in the first hour (UTC) that's the node's own; two minutes after start if never run or overdue; lookups 5 s timeout, 8 at once. Check now wakes it on every node through a new BroadcastEvent::DeliverabilityCheck (wire code 14); a node asked again within 10 minutes keeps its report.
API
inbuxa:DeliverabilityReport/get (one per node), and /set create = Check now: returns at once with the node's last checkedAt; the console polls. Updates and destroys refused.
inbuxa:DeliverabilitySettings/get / /set (update): disabledLists, and the read-only lists (name, zone, scope, lookup link, note, e.g. Barracuda's resolver registration).
Tenant administrators get their tenant's domains only, no addresses or certificates (DL-20).
Permissions:sysDeliverabilityGet (685), sysDeliverabilityUpdate (686), sysDeliverabilityCheck (687), in the schema and enums*.rs. Get is in the superuser and tenant defaults, the other two superuser only and always off under a tenant ceiling; all granted once to existing admin roles (Get to tenant admin roles).
Choices against the spec, written back into it: Check now is a fork-owned create on the report rather than an x:Action variant (as the fork's other jobs are, and no hand-edits to generated action code), and it's queued rather than synchronous since a run is dozens of lookups.
Also: privacy catalog entries, a SPEC.md §4 line, settings changes go through the audit log.
Checked locally
cargo test --workspace --locked --no-run, cargo build -p inbuxa --locked.
Unit tests: inbuxa-features (lists, settings, tenant filter), services (daily slot), plus common, registry, jmap_proto.
System tests, --test-threads=1: new deliverability_tests (simulated DNS for every check above, JMAP get/set, Check now, tenant admin limits), security_acceptance_tests, sharing_policy_tests. Run in parallel in one process, two servers collide in the harness; serially all pass.
name-check, notice-check, context-check, privacy-check, expr-schema, fork tool unit tests.
Only new files are rustfmt'd; existing files keep their formatting.
The server side of the deliverability check (inbuxa-drafts `specs/deliverability.md`, approved 2026-10-05). Admin UX roadmap item 7; the console page follows in inbuxa-admin.
**What each sending node checks, about itself**
- **Its addresses (DL-1, DL-2):** the connection strategy's source addresses, or what its EHLO name resolves to when none are set (production's case: each node leaves from its own namespace). It never asks a third party what its address is.
- **Reverse DNS (DL-5):** PTR, whether it resolves back, whether it's the EHLO name.
- **Blocklists (DL-4, DL-6, DL-12):** Spamhaus ZEN, SpamCop, Barracuda, UCEPROTECT L1, Mailspike, PSBL for addresses; Spamhaus DBL, SURBL, URIBL for domains. Each list's answer is read by its own code table: a refusal (Spamhaus `127.255.255.254` to a public resolver, URIBL `127.0.0.1`) or an undefined code is *refused*, never *listed*.
- **Per domain (DL-7 to DL-11):** SPF for each address; each DKIM key, by signing a message that's never sent and verifying it as a receiver would (missing vs different); DMARC policy and alignment modes; MTA-STS record, fetched policy, mode, and MX not covered; TLS-RPT present.
- **Certificates (DL-13):** EHLO names and the server's MX names that point at the node.
The report holds facts only; the console grades them.
**When (DL-14 to DL-16):** daily at a minute in the first hour (UTC) that's the node's own; two minutes after start if never run or overdue; lookups 5 s timeout, 8 at once. **Check now** wakes it on every node through a new `BroadcastEvent::DeliverabilityCheck` (wire code 14); a node asked again within 10 minutes keeps its report.
**API**
- `inbuxa:DeliverabilityReport/get` (one per node), and `/set` create = Check now: returns at once with the node's last `checkedAt`; the console polls. Updates and destroys refused.
- `inbuxa:DeliverabilitySettings/get` / `/set` (update): `disabledLists`, and the read-only `lists` (name, zone, scope, lookup link, note, e.g. Barracuda's resolver registration).
- Tenant administrators get their tenant's domains only, no addresses or certificates (DL-20).
**Permissions:** `sysDeliverabilityGet` (685), `sysDeliverabilityUpdate` (686), `sysDeliverabilityCheck` (687), in the schema and `enums*.rs`. Get is in the superuser and tenant defaults, the other two superuser only and always off under a tenant ceiling; all granted once to existing admin roles (Get to tenant admin roles).
**Choices against the spec, written back into it:** Check now is a fork-owned create on the report rather than an `x:Action` variant (as the fork's other jobs are, and no hand-edits to generated action code), and it's queued rather than synchronous since a run is dozens of lookups.
**Also:** privacy catalog entries, a SPEC.md §4 line, settings changes go through the audit log.
**Checked locally**
- `cargo test --workspace --locked --no-run`, `cargo build -p inbuxa --locked`.
- Unit tests: inbuxa-features (lists, settings, tenant filter), services (daily slot), plus common, registry, jmap_proto.
- System tests, `--test-threads=1`: new `deliverability_tests` (simulated DNS for every check above, JMAP get/set, Check now, tenant admin limits), `security_acceptance_tests`, `sharing_policy_tests`. Run in parallel in one process, two servers collide in the harness; serially all pass.
- name-check, notice-check, context-check, privacy-check, expr-schema, fork tool unit tests.
- Only new files are rustfmt'd; existing files keep their formatting.
Deliverability spec (inbuxa-drafts specs/deliverability.md), the server
side. Every node that sends mail checks itself once a day, at its own
minute in the first hour (UTC), and when an administrator asks:
- its outgoing addresses (the connection strategy's, or what its EHLO
name resolves to), their reverse DNS and whether it resolves back,
and nine blocklists, read by each list's own codes so a refused
query is never taken for a listing (DL-1 to DL-6);
- for every domain: SPF for each address, each DKIM key (by signing a
message that's never sent and verifying it as a receiver would),
DMARC, the MTA-STS policy against the MX, TLS reporting, and the
domain blocklists (DL-7 to DL-12);
- whether it holds a certificate for its EHLO and MX names (DL-13).
It keeps one report per node, facts only; the console grades them.
- inbuxa:DeliverabilityReport: /get, and a create that asks every node
to check now, broadcast as DeliverabilityCheck (DL-15). A tenant
administrator gets their own domains only (DL-20).
- inbuxa:DeliverabilitySettings: which built-in lists are left out, and
the lists themselves (DL-6).
- sysDeliverabilityGet, sysDeliverabilityUpdate, sysDeliverabilityCheck;
a tenant ceiling always turns the last two off.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
The server side of the deliverability check (inbuxa-drafts
specs/deliverability.md, approved 2026-10-05). Admin UX roadmap item 7; the console page follows in inbuxa-admin.What each sending node checks, about itself
127.255.255.254to a public resolver, URIBL127.0.0.1) or an undefined code is refused, never listed.The report holds facts only; the console grades them.
When (DL-14 to DL-16): daily at a minute in the first hour (UTC) that's the node's own; two minutes after start if never run or overdue; lookups 5 s timeout, 8 at once. Check now wakes it on every node through a new
BroadcastEvent::DeliverabilityCheck(wire code 14); a node asked again within 10 minutes keeps its report.API
inbuxa:DeliverabilityReport/get(one per node), and/setcreate = Check now: returns at once with the node's lastcheckedAt; the console polls. Updates and destroys refused.inbuxa:DeliverabilitySettings/get//set(update):disabledLists, and the read-onlylists(name, zone, scope, lookup link, note, e.g. Barracuda's resolver registration).Permissions:
sysDeliverabilityGet(685),sysDeliverabilityUpdate(686),sysDeliverabilityCheck(687), in the schema andenums*.rs. Get is in the superuser and tenant defaults, the other two superuser only and always off under a tenant ceiling; all granted once to existing admin roles (Get to tenant admin roles).Choices against the spec, written back into it: Check now is a fork-owned create on the report rather than an
x:Actionvariant (as the fork's other jobs are, and no hand-edits to generated action code), and it's queued rather than synchronous since a run is dozens of lookups.Also: privacy catalog entries, a SPEC.md §4 line, settings changes go through the audit log.
Checked locally
cargo test --workspace --locked --no-run,cargo build -p inbuxa --locked.--test-threads=1: newdeliverability_tests(simulated DNS for every check above, JMAP get/set, Check now, tenant admin limits),security_acceptance_tests,sharing_policy_tests. Run in parallel in one process, two servers collide in the harness; serially all pass.