Add opt-in tenant-to-client bindings for invitation mail
User-engine side of EMAIL-WP-0008: USER_ENGINE_MAIL_CLIENT_BINDINGS maps tenant globs to a single client_id carried on invitation mail envelopes only. Unmatched or conflicting tenants fail as mail_binding_denied before either lane is contacted, and the outbox now records that reason instead of collapsing it to delivery_unavailable. Unset keeps legacy envelopes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 445231@bnt-lap001 Assistant-Session: 024a807e-0cc5-4f2c-bc8a-b83322d1395d
This commit is contained in:
parent
a9360842f8
commit
adf6e992a6
9 changed files with 199 additions and 2 deletions
|
|
@ -19,6 +19,7 @@ class NoRedirect(HTTPRedirectHandler):
|
|||
|
||||
|
||||
from user_engine.domain import OutboxEvent
|
||||
from user_engine.mail_bindings import load_mail_client_bindings, mail_client_for
|
||||
|
||||
_MAIL_EVENTS = {"family_member.invited", "family_invitation.resent"}
|
||||
|
||||
|
|
@ -34,12 +35,14 @@ class HTTPOutboxDeliveryAdapter:
|
|||
mail_url: str | None = None,
|
||||
mail_bearer_token: str | None = None,
|
||||
timeout_seconds: float = 5.0,
|
||||
mail_client_bindings: str | None = None,
|
||||
) -> None:
|
||||
self.event_url = event_url
|
||||
self.mail_url = mail_url
|
||||
self.event_bearer_token = event_bearer_token
|
||||
self.mail_bearer_token = mail_bearer_token
|
||||
self.timeout_seconds = timeout_seconds
|
||||
self.mail_client_bindings = load_mail_client_bindings(mail_client_bindings)
|
||||
|
||||
def __call__(self, event: OutboxEvent) -> None:
|
||||
envelope = {
|
||||
|
|
@ -57,7 +60,15 @@ class HTTPOutboxDeliveryAdapter:
|
|||
if self.mail_url and event.event_type in _MAIL_EVENTS:
|
||||
if not self.mail_bearer_token:
|
||||
raise RuntimeError("mail delivery token is required")
|
||||
self._post(self.mail_url, envelope, self.mail_bearer_token)
|
||||
mail_envelope = dict(envelope)
|
||||
if self.mail_client_bindings is not None:
|
||||
try:
|
||||
mail_envelope["client_id"] = mail_client_for(
|
||||
event.tenant, self.mail_client_bindings
|
||||
)
|
||||
except ValueError:
|
||||
raise DeliveryError("mail_binding_denied") from None
|
||||
self._post(self.mail_url, mail_envelope, self.mail_bearer_token)
|
||||
event_envelope = dict(envelope)
|
||||
event_data = dict(envelope["data"])
|
||||
if "primary_email" in event_data:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue