relay: hand outbound mail to relays and follow its status #261

Merged
jcoffey-dev merged 1 commits from relay/outbound-handover into main 2026-10-30 17:08:16 +00:00
Owner

Step 4d of the relay spec, the downstream side of outbound (RL-20, RL-24).

What it does

  • sendThrough on any enabled relay sends every non-local recipient through relays: the enabled ones not marked inboundOnly that this node is linked to, one message after another in turn. A relay that refuses for now passes the message to the next. A refusal for good (tooLarge, forbiddenFrom) fails those recipients. With no relay linked, mail waits in the queue and is retried as usual.
  • Hand-over: the message is uploaded, then Outbound/set create over the delivering node's link. Its recipients stay in this server's queue, flagged, and show "Handed to relay ‹name›", then the remote server's reply. They aren't handed over again while they wait.
  • Follow: the link asks for Outbound push, and the lowest linked node checks every message handed to that relay from any node. A final status is recorded in the queue, which sends the DSNs as it does for its own deliveries. The relay's copy is then destroyed. If the relay has lost a message (after a reset), it is handed over again. A message cancelled here is destroyed on the relay too.
  • DeliveryStatus gains mx, the host the reply came from, so DSNs and the queue name the real remote server.
  • REQUIRETLS mail isn't handed to a relay yet; it takes its usual route.

Tests

  • System test relay_link_tests, which runs the real relay binary built with the new test-mx feature (all mail goes to one local port, and it is never in a release). Jane submits to a scripted MX. The relay delivers to bob, refuses nobody (550), and the downstream sends exactly one DSN (RL-T11). The message leaves both queues. A 451 deferral stays queued here, showing the remote server's reply. The test also runs relay_tests.
  • Unit tests: rotation skipping inboundOnly, an old link leaving a newer one in place, and reply parsing.
  • smtp suite: 78 passed, 3 ignored. Also fmt, clippy on the touched crates (no new warnings), and the fork checks.

Not in this PR (in the spec as still to come in step 4): the named inbuxaRelay route type, TLS-RPT reports from the relay's outbound.tls events, and REQUIRETLS through relays. A message handed to a relay that is then deleted waits here until it expires.

To build the test relay: cargo build -p inbuxa-relay --features test-mx.

Step 4d of the relay spec, the downstream side of outbound (RL-20, RL-24). **What it does** - `sendThrough` on any enabled relay sends every non-local recipient through relays: the enabled ones not marked `inboundOnly` that this node is linked to, one message after another in turn. A relay that refuses for now passes the message to the next. A refusal for good (`tooLarge`, `forbiddenFrom`) fails those recipients. With no relay linked, mail waits in the queue and is retried as usual. - Hand-over: the message is uploaded, then `Outbound/set` create over the delivering node's link. Its recipients stay in this server's queue, flagged, and show "Handed to relay ‹name›", then the remote server's reply. They aren't handed over again while they wait. - Follow: the link asks for `Outbound` push, and the lowest linked node checks every message handed to that relay from any node. A final status is recorded in the queue, which sends the DSNs as it does for its own deliveries. The relay's copy is then destroyed. If the relay has lost a message (after a reset), it is handed over again. A message cancelled here is destroyed on the relay too. - `DeliveryStatus` gains `mx`, the host the reply came from, so DSNs and the queue name the real remote server. - REQUIRETLS mail isn't handed to a relay yet; it takes its usual route. **Tests** - System test `relay_link_tests`, which runs the real relay binary built with the new `test-mx` feature (all mail goes to one local port, and it is never in a release). Jane submits to a scripted MX. The relay delivers to `bob`, refuses `nobody` (`550`), and the downstream sends exactly one DSN (RL-T11). The message leaves both queues. A `451` deferral stays queued here, showing the remote server's reply. The test also runs `relay_tests`. - Unit tests: rotation skipping `inboundOnly`, an old link leaving a newer one in place, and reply parsing. - smtp suite: 78 passed, 3 ignored. Also fmt, clippy on the touched crates (no new warnings), and the fork checks. **Not in this PR** (in the spec as still to come in step 4): the named `inbuxaRelay` route type, TLS-RPT reports from the relay's `outbound.tls` events, and REQUIRETLS through relays. A message handed to a relay that is then deleted waits here until it expires. To build the test relay: `cargo build -p inbuxa-relay --features test-mx`.
jcoffey-dev added 1 commit 2026-10-30 16:16:23 +00:00
relay: hand outbound mail to relays and follow its status
ci / fork-checks (pull_request) Skipped
ci / build (pull_request) Skipped
github/ci (branch) GitHub Actions
ci / github (pull_request) Successful in 10m26s
dd2554aa82
With sendThrough on, every non-local recipient is handed to a linked
relay that may send, in turn, skipping inboundOnly ones; with none
linked the mail waits in the queue (RL-20, RL-24). The queue marks the
recipients as handed to the relay and shows its replies. The lowest
linked node follows Outbound by push, records each final status so the
queue sends the DSNs, and destroys the relay's copy.

DeliveryStatus gains mx, the host a reply came from. The relay's
test-mx feature sends all mail to one local port for the system test,
which now covers hand-over, delivery, one DSN for a refusal (RL-T11),
and a deferral shown in the queue.
jcoffey-dev merged commit a1fd6ff4c5 into main 2026-10-30 17:08:16 +00:00
jcoffey-dev deleted branch relay/outbound-handover 2026-10-30 17:08:17 +00:00
Sign in to join this conversation.