carlos / platform Public

tenant email spec: the SMTP tenant header is X-SES-TENANT, not X-SES-TENANT-NAME

Verified at implementation and independently re-fetched in review against
the live SES tenants page. The spec's guess was wrong; designing the tenant
as one method on the provisioner seam is what made that a one-line
correction rather than a model change.

Records the precondition the same page states and that is easy to get
backwards: a tenant needs a verified identity AND a configuration set
associated before it can send, and SES checks that on every send. An
unassociated tenant is harmless only while nothing emits the header, so the
send path must not start emitting it until associations are wired.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Paul Campbell a79053722b5c3d18e9c6a9e175fedc5abee7bbf8 parent e1cba7c
1 file changed, +21 −8
  • docs/superpowers/specs/2026-08-19-tenant-email-design.md +21 −8
diff --git a/docs/superpowers/specs/2026-08-19-tenant-email-design.md b/docs/superpowers/specs/2026-08-19-tenant-email-design.md
index 8e214ff46..86d5060ba 100644
--- a/docs/superpowers/specs/2026-08-19-tenant-email-design.md
+++ b/docs/superpowers/specs/2026-08-19-tenant-email-design.md
@@ -79,14 +79,27 @@ created on first use. This is what makes one account's reputation stop at
its own boundary and what makes a per-account pause meaningful to SES
itself rather than only to us.
-The tenant layer is **additive and seam-shaped**, not load-bearing. SES
-Tenant Management is recent enough that the exact attribution mechanism
-for an SMTP send (believed to be an `X-SES-TENANT-NAME` header) **MUST be
-verified against live AWS documentation at implementation time, not taken
-from this document**. It is designed as one method on the seam in §5 so
-that a wrong guess costs one function rather than the model. If tenant
-attribution over SMTP turns out to be unavailable, v1 ships without the
-tenant layer and loses nothing in §4's isolation.
+The tenant layer is **additive and seam-shaped**, not load-bearing.
+
+**VERIFIED 2026-08-19** (implementation, then independently re-fetched in
+review, against `docs.aws.amazon.com/ses/latest/dg/tenants.html`): SES
+tenant management is real and present in `sesv2` v1.66.6. This document's
+original guess of an `X-SES-TENANT-NAME` header was **WRONG** — the actual
+SMTP attribution header is **`X-SES-TENANT`**. Designing the tenant as one
+method on §5's seam is what made that a one-line correction rather than a
+model change.
+
+**A hard precondition the same page states, which is easy to get backwards:**
+a tenant must have at least one verified identity AND one configuration set
+associated to it (`CreateTenantResourceAssociation`) before it can send, and
+SES validates that association on every send. So while nothing emits
+`X-SES-TENANT`, an unassociated tenant is harmless — but **the send path
+MUST NOT begin emitting `X-SES-TENANT` until associations are wired, or
+every send fails.** Creating the tenant is safe and idempotent; referencing
+it is not, until then.
+
+If tenant attribution over SMTP had turned out to be unavailable, v1 would
+have shipped without the tenant layer and lost nothing in §4's isolation.
**Identity ↔ a domain, per region.** The default identity for an app is
**the app's own host** — `seapointish.bag.oncarlos.com` — not the account