mail-address-semantics/workplans/MAS-WP-0003-provider-live-test.md
tegwick 2a94672239 MAS-WP-0003-T03: skip consumer Outlook.com (covered by M365)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 252470@bnt-lap001
Assistant-Session: ad628c8f-4be2-4979-94c9-76c7ed6f8241
2026-10-18 11:02:51 +02:00

6.5 KiB

id type title domain repo status owner topic_slug created updated state_hub_workstream_id
MAS-WP-0003 workplan MAS live provider test on a real subdomain communication mail-address-semantics active claude coulomb-social 2026-10-08 2026-10-18 8e9069c6-5c32-5c56-aded-49c8fdc2b66b

MAS live provider test on a real subdomain

Follow-up to MAS-WP-0002. The MTA half of the review question which characters or address forms were rewritten or rejected? was answered against a real Postfix (experiments/postfix-probe/, docs/experiment-review.md). This workplan answers the provider half. It has to be done before the MAS-WP-0002 decision gate.

coulomb.social mail is hosted by IONOS, so the test needs its own subdomain (for example mas.coulomb.social) with its own MX.

Choose and provision the test subdomain

id: MAS-WP-0003-T01
status: done
priority: high
state_hub_task_id: "48926a68-e5bb-5d7c-910f-12b38560b48f"

Needs the operator. Pick the subdomain. Add an MX (and A) record at IONOS pointing to railiance01 (92.205.62.239). Allow inbound TCP 25 on railiance01. Record the choice as a decision.

  • 2026-10-08: DNS done. mas.coulomb.social has MX 10 to itself and A 92.205.62.239. Inbound TCP 25 is still closed (connection timed out from the workstation; nothing listens on 25 and ufw allows only SSH and 2224). The port-25 exposure is a live production change and needs the founder's go.
  • 2026-10-18: founder go for A-D (recorded 2026-10-08 in deploy/railiance/manifests.yaml) executed. Port 25 is served by the k3s mas-smtp LoadBalancer (klipper hostPort, so ufw is bypassed the same way as Traefik 80/443). EHLO answers 250 from the workstation and the node. coulombcore cannot connect, most likely because its provider blocks outbound 25.

Deploy Postfix + gateway + ticket service + statute

id: MAS-WP-0003-T02
status: done
priority: high
state_hub_task_id: "17e4ee15-faac-5103-b62a-65a890d2cd56"

Deploy the probe configuration on railiance01, using local-domain-safe settings, TLS and the usual relay restrictions. Serve the statute (with the namespace set to the subdomain) at https://<sub>/.well-known/mas through Traefik. Verify the deployment with mas discover <sub>. Outbound replies need a relay with SPF/DKIM for the subdomain; until that exists, keep replies in the outbox only.

  • 2026-10-18: deployed to namespace mas with image docker.io/library/mas-live:wp0003-20261018, side-loaded into k3s containerd (k3s ctr images import), not pushed to a registry. A local smoke test found that the committed entrypoint could not run: Postfix smtpd dies without a reject-class entry in smtpd_relay_restrictions. It also ignores access-map results for !/% local-parts unless allow_untrusted_routing=yes. Both are fixed. The relay regexp now permits @mas.coulomb.social only, and the list ends in reject. Live checks: the Let's Encrypt cert is issued, mas discover mas.coulomb.social is valid (P1, P2 enabled, type ticket, mode callback), and all four T03 addresses plus x%y@ are delivered to the mas pipe. Relaying (x@gmail.com, x!y@gmail.com, a@gmail.com@mas..., a@mas...@gmail.com) is refused with 554, and the queue is empty. The evidence log holds 5 smoke events from a@test.example; exclude them when analysing T03/T04. Read the evidence with: kubectl -n mas exec deploy/mas-mx -- cat /var/lib/mas/events.jsonl.

Provider send matrix

id: MAS-WP-0003-T03
status: progress
priority: high
state_hub_task_id: "b2af3eb2-0d4b-5cea-b033-99d47c938298"

Needs the operator to send from their accounts. Send from Gmail (web and mobile), Outlook.com and one corporate gateway to:

  • ticket!callback@
  • ticket=ID@
  • ticket=ID+comments@
  • ticket=RE=2026-4711@

Then reply to a service message sent from ticket=ID@. For each combination, record whether the provider's compose form accepts the address and what envelope recipient arrives.

  • 2026-10-18, Gmail web (subjects "Testmail 1-4"): the compose form accepted all four addresses unquoted. Each arrived 08:40-08:41Z in its own SMTP session (209.85.x, STARTTLS, BDAT). The envelope recipient and header To were byte-identical to what was typed: no quoting, no rewriting, no stripping of !, = or the +comments facet. The gateway classified them as expected: ticket!callback P2 function/callback → 201 created; ticket=ID and ticket=RE=2026-4711 P1 resource → 202; ticket=ID+comments P1 resource, facet comments → 202.
  • 2026-10-18, Gmail mobile (subjects "Test 2.1-2.4", 08:44-08:46Z): the result is identical to Gmail web. All four addresses were accepted unquoted and arrived byte-identical, with the same classification and app statuses (201/202/202/202).
  • 2026-10-18, Outlook mobile app with a corporate Microsoft 365 account (sender domain binect.de, subjects "Test 3.1-3.4", 08:47-08:50Z): mail was delivered by Exchange Online Protection (40.107.149.x, STARTTLS, BDAT), one session per message. This counts as the corporate gateway. The result is identical to Gmail. All four addresses were accepted unquoted and arrived byte-identical, with the same classification and app statuses (201/202/202/202).
  • 2026-10-18, Outlook desktop client with the same Microsoft 365 account (binect.de, subjects "Test 4.1-4.4", 08:57-08:59Z): mail was delivered by Exchange Online from another pool (52.101.171.x). The result is identical: all four addresses arrived byte-identical, with app statuses 201/202/202/202. The compose client makes no difference within M365.
  • Consumer Outlook.com: skipped (operator decision 2026-10-18; no account). Consumer Outlook.com runs on the same Exchange Online infrastructure as M365, so outbound handling is covered by the two M365 runs. Not covered: the Outlook-on-the-web compose form (only the native apps were used). Still open: the reply test (blocked: no outbound mail).

Forwarding and list paths

id: MAS-WP-0003-T04
status: todo
priority: medium
state_hub_task_id: "97c88b4f-14c3-5f6c-8f31-6b9fc3afd236"

Send via one forwarding service (SRS) and one mailing list (VERP). Check whether = collides with SRS0/VERP encoding, and whether facets survive or are stripped.

Close the review

id: MAS-WP-0003-T05
status: todo
priority: high
state_hub_task_id: "63e86851-9c7d-5ce8-977f-5d09268d9dcc"

Fold the results into docs/experiment-review.md. Turn the spec gaps (quoted equivalence, resource-type case, type-intake semantics for ticket!MODE) into spec change proposals. Then take the MAS-WP-0002 decision gate.