logicspike/docs

Communication

Phase B — tenant mail (a separate, later request)

Not part of the first request. Start this only after Phase A has an answer, and ideally after 30 to 60 days of clean sending on the approved account (the reasoning is in README.md §1).

Tenant mail means newsletters, mailbox (user-to-user) mail, form notifications and replies, flows/automation mail, chat mail, tenants' custom sending domains and the shared mail.vlozi.app lane. It is a different kind of sending: the recipients are chosen by tenants, so the platform needs controls over who may send and to whom, not just over its own templates.

What must exist first

The in-code switch SES_TENANT_SENDING stays unset until every item below is real, not planned.

Control State today Needed
Tenant sending approval: a new workspace cannot send campaigns until reviewed; first campaigns manually reviewed None Build
Consent attestation on import and a ban on purchased lists, enforced in product and in the Terms Terms mention it; no attestation step Build
Content and URL screening of campaign bodies None Build
Per-tenant daily caps and warm-up Mailbox shared lane has caps; newsletter is paced per campaign only Extend
Staff tenant suspend that comms and the gateway both enforce The reputation breaker pauses sending; no manual ban Build
Reputation circuit breaker enforcing (REPUTATION_ENFORCE=true) Built; records and warns only Turn on, after the ops pages are proven
Bounce-only account suppression, tenant-scoped complaints (ses-account-suppression.mjs) Built; not run Run at this phase
Retention and erase job for logs, bodies and webhook payloads None; the Privacy page promises one Build, or change the promise
Data Processing Addendum for tenants (they are controllers of their subscribers' data) None Draft
Tenant sending-vetting policy (internal) None Draft
Unconsented list (Vlozi's own ~503 contacts from the 2026-07-10 bulk import) never mailed Present and mailable: the import stamped confirmed_at by assertion. The live Anti-spam page already promises no unconsented lists (gap-log G61) Decided 2026-10-05: revoke consent, keep the rows (apps/newsletter-service/scripts/revoke-unconsented-import.mjs, dry run first). They become unmailable but stay in the list and can later go through the re-permission flow
in.vlozi.app DNS and MX, plus INBOUND_DOMAIN The name does not exist in DNS (checked 2026-10-05), so reply routing (reply+…) and mailto unsubscribe cannot work. There is no separate "mailto" switch: the mailto List-Unsubscribe entry appears when INBOUND_DOMAIN is set on both comms and newsletter, and apps/communication/.dev.vars says vlozi.app, not in.vlozi.app, so the production value must be read from where it was set Create the name, set INBOUND_DOMAIN to it on comms and newsletter, then confirm a campaign's List-Unsubscribe carries the mailto: entry
Reject unknown recipients at SMTP time instead of accepting and dropping The Cloudflare catch-all hands mail to the comms worker (confirmed by the 2026-10-06 role-address tests), which drops an address nobody owns with no bounce. The resolver must first tell "no such mailbox" apart from "lookup failed", or a transient error becomes a permanent rejection Build (gap-log G11, G12)
Role addresses on mail.vlozi.app Tenant mail is sent from that domain, so mail operators will write to its role addresses. Vlozi's workspace may claim those names there (gap-log G49); the vlozi.app ones already exist Create abuse and postmaster on mail.vlozi.app in the Vlozi workspace before tenant sending is enabled

Options once the controls exist

  1. A second SES production-access request that describes these controls, referencing the clean record from Phase A.
  2. A separate AWS account for tenant mail (an AWS Organization member). It limits the blast radius: a tenant problem cannot suspend the account that carries login codes. Costs: a second quota to earn and a second set of identities and DNS.
  3. Another provider for tenant mail, keeping SES for platform mail. Resend is already integrated for vlozi.app only; tenant domains and the shared lane would need provider support and event webhooks.

Decide with real numbers (Phase A volume, bounce and complaint rates, how many tenants are asking for it).

If SES keeps refusing even Phase A

Tenant mail does not have to wait on AWS. Route the tenant lane through another provider and keep SES for platform mail only. That is a separate piece of work (provider selection per lane, webhooks for that provider, domain verification per provider).

When you do write the second request

  • Show each control above working, with evidence.
  • State the real numbers from the approved account: volume, bounce rate, complaint rate, for how long.
  • Describe who may send (vetted workspaces only), what they may send (consented lists, content screened), and what happens when it goes wrong (pause, suspend, suppression, escalation).
  • Keep it consistent with the published Terms, Acceptable Use and Anti-Spam policies, which must already say the same.
Communication