Masked email built: implementation status, deferral and known limits (ME-1 to ME-19)

This commit is contained in:
2026-09-18 16:40:14 -07:00
parent d319f013ec
commit 31b8ca8ed5
2 changed files with 30 additions and 1 deletions
+1 -1
View File
@@ -276,7 +276,7 @@ is written.
| # | Feature | What an operator gets | Notes | | # | Feature | What an operator gets | Notes |
|---|---|---|---| |---|---|---|---|
| 1 | Multi-tenancy | Tenants with their own domains, admins, quotas and queue visibility | Needed for anybody hosting mail for others. ihasmail already has a Tenants screen. Built 2026-09-18 in `crates/features`; status in `features/multi-tenancy.md`. | | 1 | Multi-tenancy | Tenants with their own domains, admins, quotas and queue visibility | Needed for anybody hosting mail for others. ihasmail already has a Tenants screen. Built 2026-09-18 in `crates/features`; status in `features/multi-tenancy.md`. |
| 2 | Masked email | Per-sender disposable addresses that deliver to the account | Existing addresses must keep delivering (§3.4). Spec: `features/masked-email.md`. | | 2 | Masked email | Per-sender disposable addresses that deliver to the account | Existing addresses must keep delivering (§3.4). Built 2026-09-18 in `crates/features`; status in `features/masked-email.md`. |
| 3 | Undelete | Deleted mail held for a set period and restorable | Existing archived items must stay restorable. Spec: `features/undelete.md`. | | 3 | Undelete | Deleted mail held for a set period and restorable | Existing archived items must stay restorable. Spec: `features/undelete.md`. |
| 4 | Branding and templates | Operator logo, and the text of calendar alarm and invitation emails | INBUXA's branding is the default. Spec: `features/branding-and-templates.md`. | | 4 | Branding and templates | Operator logo, and the text of calendar alarm and invitation emails | INBUXA's branding is the default. Spec: `features/branding-and-templates.md`. |
| 5 | AI spam classification | An optional model's opinion as one spam signal, and a Sieve function that asks a model | Local and auditable model only: no hosted API by default. Spec: `features/ai-spam-classification.md`. | | 5 | AI spam classification | An optional model's opinion as one spam signal, and a Sieve function that asks a model | Local and auditable model only: no hosted API by default. Spec: `features/ai-spam-classification.md`. |
+29
View File
@@ -277,6 +277,35 @@ Stalwart-facing (SPEC.md §5).
12. **(compat)** INBUXA's existing masks all resolve by stored address and 12. **(compat)** INBUXA's existing masks all resolve by stored address and
deliver after cutover, and read back identically through `x:`. deliver after cutover, and read back identically through `x:`.
## Implementation status
Built 2026-09-18 from this spec, clean-room, under the multi-tenancy hand-off
brief's rules. The rules live in `crates/features` (`inbuxa-features`, module
`masked_email`); the JMAP glue in `crates/jmap/src/inbuxa/`, with Fastmail's
object type in `crates/jmap-proto/src/object/fastmail_masked_email.rs`;
upstream files carry hooks marked `inbuxa:`. Acceptance tests 1 to 11 pass as
`tests/src/system/masked_email.rs`, with ME-9, ME-10, ME-11 and `/changes`.
- **ME-1 to ME-15, ME-17 to ME-19:** built.
- **ME-16:** built for the `x:` API, which stores a client-supplied
`createdBy`. The server-set name is **deferred** until sign-in goes through
OAuth (contract C-8): with Basic auth there's no client name, so a mask
created through the Fastmail API has none.
- **ihasmail changes** belong to ihasmail-inbuxa and aren't part of this
repository.
- **Test 12 (compat)** is written as `masked_email_compat`, ignored, and unrun
until a copy of INBUXA's data with masks made on it is provided. Its doc
comment says how to run it.
- **Known limits, not requirements of this spec:**
- A pending mask past its 24 hours is removed the next time anything reads
it or mail arrives for it, not by a timer. Nothing can see it in between,
so the effect is the same (ME-8).
- Creating an account or alias doesn't consult the mask index, so an
account could be given an address a mask holds; the account then wins
delivery. A random 12-character mask address makes this unlikely.
- The `x:` API's create response carries only the new id, as upstream's
registry responses do. The address is read with `/get`.
## Observed ## Observed
Settled on 2026-09-18 against INBUXA's live Enterprise server (Stalwart Settled on 2026-09-18 against INBUXA's live Enterprise server (Stalwart