mail-address-semantics/workplans/MAS-WP-0003-provider-live-test.md
tegwick 5bcf966d7b MAS-WP-0003-T03: record Gmail send results
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 10:42:02 +02:00

5.3 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 (one client; web or mobile not yet recorded): 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. Still open: the second Gmail client, Outlook.com, the corporate gateway, and 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.