inbuxa Relay: ingest with session context, and live verdicts #254

Merged
jcoffey-dev merged 1 commits from relay/ingest into main 2026-10-30 06:59:14 +00:00
Owner

The third server-side part of docs/spec/features/relay.md ("Live mode",
"Handing held mail down", "Ingest with session context"):

  • The link service asks for Inbound push as well as Relay, so the relay
    is live while a node is linked (RL-12). It claims up to eight
    messages at a time with a 300 s lease (RL-15), downloads each on its
    own connection, and unseals it with the downstream's sealing key
    (RL-21).
  • smtp::inbound::relayed plays the relay's session through this
    server's own handlers: connect (rate limits, scripts, milters),
    EHLO, MAIL FROM, each RCPT TO, then DATA, on port 25 with the
    original sender's address, port and HELO (RL-23). SPF, reverse IP,
    DMARC, DNSBL, the spam filter, the AI classifier, Sieve and the
    directory see the real facts. The relay's TLS shows in the Received
    header and in is_tls, and a new expression variable, relay, is the
    relay's name (id 92, in the connect, EHLO, MAIL FROM and RCPT
    contexts, with its schema label).
  • Live: this server's reply is the verdict. Accepted, the message is
    destroyed on the relay and the sender hears 250; refused, the relay
    gives the sender this server's reply.
  • Held: spam over the reject threshold goes to Junk with
    X-Inbuxa-Relay: held, over reject threshold, never refused or
    dropped (RL-17). Recipients refused for good get a DSN only when the
    sender passed SPF or DMARC here (RL-18); a refusal for now is tried
    again after the lease.
  • Every message taken is recorded before the relay is told, and one
    offered again is destroyed without a second delivery (RL-16). The
    records are forgotten after heldMaxAge and a day, and with the relay.
  • On the relay, a message waiting for its verdict stays pending when
    claimed, so the downstream knows to answer it (spec table updated).
  • The spec records the external-directory decision: such domains list
    only the accounts already seen, with no catch-all.
  • The link system test now sends mail through the real inbuxa-relay:
    live delivery before 250, a live refusal (too many Received headers)
    that reaches the sender as 450 4.4.6 with nothing kept, and a message
    held while the link was off, delivered once when it came back.

Checks run locally: both relay system tests, the SMTP inbound suites
(all pass except asn and milter_client_test, which need outside network
and are ignored by default), the relay crate tests, the new unit tests
in smtp, services and features, rustfmt, clippy on the changed files,
expr-schema --check, and the fork checks.

Not covered by a test yet: the RL-18 DSN itself (it needs an SPF or
DMARC pass, so real DNS), and a message offered again after a node dies
mid-ingest (RL-T5). A message being judged when its link drops can be
delivered twice if another link claims it before the first records it.

The third server-side part of docs/spec/features/relay.md ("Live mode", "Handing held mail down", "Ingest with session context"): - The link service asks for Inbound push as well as Relay, so the relay is live while a node is linked (RL-12). It claims up to eight messages at a time with a 300 s lease (RL-15), downloads each on its own connection, and unseals it with the downstream's sealing key (RL-21). - smtp::inbound::relayed plays the relay's session through this server's own handlers: connect (rate limits, scripts, milters), EHLO, MAIL FROM, each RCPT TO, then DATA, on port 25 with the original sender's address, port and HELO (RL-23). SPF, reverse IP, DMARC, DNSBL, the spam filter, the AI classifier, Sieve and the directory see the real facts. The relay's TLS shows in the Received header and in is_tls, and a new expression variable, relay, is the relay's name (id 92, in the connect, EHLO, MAIL FROM and RCPT contexts, with its schema label). - Live: this server's reply is the verdict. Accepted, the message is destroyed on the relay and the sender hears 250; refused, the relay gives the sender this server's reply. - Held: spam over the reject threshold goes to Junk with X-Inbuxa-Relay: held, over reject threshold, never refused or dropped (RL-17). Recipients refused for good get a DSN only when the sender passed SPF or DMARC here (RL-18); a refusal for now is tried again after the lease. - Every message taken is recorded before the relay is told, and one offered again is destroyed without a second delivery (RL-16). The records are forgotten after heldMaxAge and a day, and with the relay. - On the relay, a message waiting for its verdict stays pending when claimed, so the downstream knows to answer it (spec table updated). - The spec records the external-directory decision: such domains list only the accounts already seen, with no catch-all. - The link system test now sends mail through the real inbuxa-relay: live delivery before 250, a live refusal (too many Received headers) that reaches the sender as 450 4.4.6 with nothing kept, and a message held while the link was off, delivered once when it came back. Checks run locally: both relay system tests, the SMTP inbound suites (all pass except asn and milter_client_test, which need outside network and are ignored by default), the relay crate tests, the new unit tests in smtp, services and features, rustfmt, clippy on the changed files, expr-schema --check, and the fork checks. Not covered by a test yet: the RL-18 DSN itself (it needs an SPF or DMARC pass, so real DNS), and a message offered again after a node dies mid-ingest (RL-T5). A message being judged when its link drops can be delivered twice if another link claims it before the first records it.
jcoffey-dev added 1 commit 2026-10-30 06:15:59 +00:00
inbuxa Relay: ingest with session context, and live verdicts
ci / fork-checks (pull_request) Skipped
ci / build (pull_request) Skipped
github/ci (branch) GitHub Actions
ci / github (pull_request) Successful in 10m25s
93f814a408
The third server-side part of docs/spec/features/relay.md ("Live mode",
"Handing held mail down", "Ingest with session context"):

- The link service asks for Inbound push as well as Relay, so the relay
  is live while a node is linked (RL-12). It claims up to eight
  messages at a time with a 300 s lease (RL-15), downloads each on its
  own connection, and unseals it with the downstream's sealing key
  (RL-21).
- smtp::inbound::relayed plays the relay's session through this
  server's own handlers: connect (rate limits, scripts, milters),
  EHLO, MAIL FROM, each RCPT TO, then DATA, on port 25 with the
  original sender's address, port and HELO (RL-23). SPF, reverse IP,
  DMARC, DNSBL, the spam filter, the AI classifier, Sieve and the
  directory see the real facts. The relay's TLS shows in the Received
  header and in is_tls, and a new expression variable, relay, is the
  relay's name (id 92, in the connect, EHLO, MAIL FROM and RCPT
  contexts, with its schema label).
- Live: this server's reply is the verdict. Accepted, the message is
  destroyed on the relay and the sender hears 250; refused, the relay
  gives the sender this server's reply.
- Held: spam over the reject threshold goes to Junk with
  X-Inbuxa-Relay: held, over reject threshold, never refused or
  dropped (RL-17). Recipients refused for good get a DSN only when the
  sender passed SPF or DMARC here (RL-18); a refusal for now is tried
  again after the lease.
- Every message taken is recorded before the relay is told, and one
  offered again is destroyed without a second delivery (RL-16). The
  records are forgotten after heldMaxAge and a day, and with the relay.
- On the relay, a message waiting for its verdict stays pending when
  claimed, so the downstream knows to answer it (spec table updated).
- The spec records the external-directory decision: such domains list
  only the accounts already seen, with no catch-all.
- The link system test now sends mail through the real inbuxa-relay:
  live delivery before 250, a live refusal (too many Received headers)
  that reaches the sender as 450 4.4.6 with nothing kept, and a message
  held while the link was off, delivered once when it came back.
jcoffey-dev merged commit 09ae23ae48 into main 2026-10-30 06:59:14 +00:00
jcoffey-dev deleted branch relay/ingest 2026-10-30 06:59:15 +00:00
Sign in to join this conversation.