mas_modes.mailer.Mailer is the only outbound path (own SQLite + lock), shared by the ticket service and both EmailMode roles. Over the cap mail is held and reported (send-cap-reached, held); held mail is purged after email-held-duration-max (7d) and not stored beyond emails-held-storage-max (100MB). The ticket service's legacy outbox is imported once so the live count carries over (checked on a copy of the live DB: 4 sent). Entrypoint passes the cap and both limits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 5787@bnt-lap001 Assistant-Session: 5db26b82-138b-40cc-9856-4d5eb0f752fd
3 KiB
Reuse surface
This repository is the email building block for a multimodal communication framework that is yet to be designed (INTENT.md, Mode reference implementation). This page says what such a framework can depend on, and how stable each part is.
Depend on these
| Part | Where | Stability |
|---|---|---|
| MAS address spec | mas-v0.1-spec/ (v0.1.1), mas-v0.2-spec/ (draft) |
v0.1.1 stable. v0.2 draft until a second implementation passes its corpus (MAS-WP-0009) |
| Mode contract | mas-modes-v0.1-spec/ |
v0.1 draft. Changes are versioned; messages carry mas_modes_version |
| Gateway event | mas-modes-v0.1-spec/schema/mas-event-v0.1.schema.json |
v0.1. Events carry mas_event_version |
| Conformance corpora | the bundles' conformance/ |
Normative for their version. Consume them unchanged |
mas_core |
parse (no I/O), discover (exact host), resolve (pure), generate / for_destination |
Python reference library |
mas_gateway |
MTA pipe and provider webhook → event |
Reference adapter. The event is the interface, not the code |
| Postfix profile | integrations/postfix/ |
Tested against Postfix 3.7 (tests/test_postfix_profile.py) |
Integrating as an outside master
Configure the resource type as slave (mas_modes.email_mode.RoleConfig),
point master_url at your system, set master_peer to your peer id, and
exchange a key with the email operator. Every request in both directions is
signed (CONTRACT.md section 7; mas_modes.signing, standard library only).
You then:
- receive
case.intakeandcase.message, each carrying a gateway event; - answer
case.assignwith your own case id; email adopts it asTYPE=ID@domain; - send replies with
mail.send(in_reply_toa recorded message); principle 10 can refuse them, and over the deployment's one send cap they are held (held: true) instead of sent; - decide per case on
autonomous_sendandtransfers:block, or a mode webhook with that mode'speer. The peer must be one the email operator has a key for; - own every timeout; end a handoff with
handoff.cancel.
Integrating a mode
Implement the mode endpoint in CONTRACT.md: accept handoff.request,
handoff.update and handoff.cancel only when signed by email, and post
handoff.status, signed with your peer id, to exactly the status_url of
that handoff (it carries a per-handoff token), with an increasing seq.
Never send timed-out.
mas_modes/stubs/callback.py is a complete example.
Examples only, not products
examples/ticket_service/: the reference ticket service, used as the store for email-mastered cases.mas_modes/stubs/: the callback stub and the stub outside master. They never contact a person or a service.mas_modes/email_mode.py: the reference email side. It authenticates every peer (section 7), but it is single-process with SQLite, has no key rotation, and serves plain HTTP. Put it behind TLS before exposing it beyond loopback. The contract is the interface.