Status: Draft for the founder to review, fill in the one blocker below, and submit as a new AWS Support case (do not reply on the denied/resolved thread). Context: Denied twice (2026-07-11, 2026-07-19) with no specific reason given ("due to security reasons, we are unable to provide specific details"). This package exists because two prior detailed, best-practice-compliant submissions still got boilerplate denials — see §0 for the one concrete mismatch found in the account itself, and the checklist in §2 for everything that's changed since the last attempt.
0. Likely why the last two were denied
Two things in the account/site were inconsistent with the written case — either one is enough for an automated or manual reviewer to bounce the request without explaining why:
- Mail Type mismatch. The original AWS request declared
Mail Type: TRANSACTIONAL(visible in the case's structured metadata), but every follow-up message described opt-in newsletters as part of the use case too — which is commercial/marketing mail, not transactional. A reviewer cross-checking the declared category against the narrative sees a platform asking for "transactional" access while describing bulk marketing sends. Fix: the new request should either declare the mail type honestly (mixed, majority-transactional) if the SES console/API offers that option, or explicitly lead the narrative with "primarily transactional; a minority of opt-in marketing newsletters" right under the mail-type line so there's no surprise. - Public site claimed the wrong mail provider.
vlozi.app's About, Security, Status, and Privacy Policy pages all stated mail is sent via "Resend" — stale copy left over from before the SES migration (commitdfd1b9a, 2026-07-04). A privacy policy that names the wrong sub-processor for email delivery is a real accuracy problem independent of AWS, and if a reviewer (or their automated crawler) checked the site, it would not match the SES-based case being reviewed. This has been fixed — see §2.
Neither of these is provably the rejection reason (AWS didn't say), but they're the only two hard inconsistencies between what was claimed and what a reviewer could independently verify. Everything else in the prior submissions was accurate and followed AWS's own published best practices.
1. Ready-to-submit case text
Submit as a new case (Service: SES Sending Limits, Region: ap-south-1), not a
reply to the resolved one. Fill in the one bracketed blocker before sending.
Mail Type: Transactional (primary use case) — see note on marketing volume below.
Website URL: https://vlozi.app
Hello,
This is our third submission for SES production access in
ap-south-1. The first two (2026-07-04, 2026-07-16) were denied without a specific reason ("due to security reasons, we are unable to provide specific details"). Since the last submission we've closed every gap we could independently identify and verify — listed below — and we're asking specifically: if anything here still falls short, please name it so we can fix it same-day, rather than resolving the case again without feedback we can act on.About us. Vlozi (https://vlozi.app) is a multi-tenant SaaS platform for small businesses — a blog, newsletter, chatbot, and social-posting dashboard billed by usage. Pre-launch: no live paying tenants yet, so the volume estimates below are conservative first-90-days targets, not historical data.
What we send and how much.
- Transactional (~90% of volume): one-time passcodes, account/security notices, form and lead-capture confirmations, booking confirmations — every message is triggered in real time by the recipient's own action on our platform or a customer's.
- Marketing (~10% of volume): opt-in newsletters our tenants send to their own confirmed subscribers. We are requesting production access primarily for the transactional majority; we disclose the marketing minority here so the use case matches what a reviewer will actually see in sampled traffic.
- Volume requested: 2,000 emails/day, 5 msg/sec to start (~60,000/month ceiling) — a deliberately small, capped ask. We'll request increases only after demonstrating clean sending history at this tier.
Domain verification.
vlozi.appandmail.vlozi.app(our dedicated tenant-mail subdomain, isolated from the root domain's reputation) are both DKIM-verified (Easy DKIM, RSA-2048) inap-south-1, with DMARC published (p=quarantine; pct=100; rua=mailto:dmarc@vlozi.app) [confirm this matches what was actually published per §3.1 below before sending]. Unverified domains cannot send through our platform — every tenant's custom sending domain goes through the same DKIM verification gate before we allow a send from it.List hygiene. Newsletter subscribers are collected only through our tenants' own opt-in signup forms, gated by double opt-in (a confirmation email is sent first; the address is not mailable until the recipient clicks the confirmation link) and by Cloudflare Turnstile bot verification on the signup endpoint. We never purchase, rent, or scrape lists.
Bounce & complaint handling (automated, not manual). We subscribe to SES bounce/complaint events via Amazon SNS, verified against Amazon's signing certificate before we trust the payload. On a hard bounce or complaint, the address is added to a suppression list and a per-tenant subscriber kill-switch within seconds — our send path checks suppression before every single send and short-circuits on a hit. We also enforce our own pre-emptive thresholds (auto-pause a tenant's sending at 5% bounce rate) tighter than the account-level 10% bounce / 0.5% complaint threshold SES itself pauses on.
Unsubscribe. Every campaign carries an RFC 8058 one-click
List-Unsubscribe/List-Unsubscribe-Postheader plus an in-body link. Unsubscribes take effect immediately, platform-wide.Abuse reporting.
abuse@andpostmaster@are live, monitored mailboxes on bothvlozi.appandmail.vlozi.app.Physical mailing address (CAN-SPAM): [INSERT — a registered business address or a personal mailing address is both acceptable under CAN-SPAM; this must be filled in before submitting, see §3.3].
Example content:
- Transactional: "Your Vlozi login code is 123456." / "You received a new form submission." / "Your booking is confirmed for [date]."
- Marketing: tenants' own branded updates to their confirmed subscriber lists, each with the footer described above (unsubscribe link + physical address).
We're happy to provide screenshots of rendered emails, DNS records, or anything else that helps this review — please just tell us what's missing.
Thank you, [Founder name], Vlozi
2. Technical checklist — current status
Everything below is either already true, or was shipped in this session (marked NEW) specifically to close a gap AWS's own guidance calls out.
| Control | Status |
|---|---|
DKIM (RSA-2048) on vlozi.app |
✅ Verified |
DKIM (RSA-2048) on mail.vlozi.app |
✅ Verified |
| DMARC published | ⚠️ Live but p=none (monitor-only) — tighten before resubmitting, see §3.1 |
| SNS-verified bounce/complaint automation → suppression + kill-switch | ✅ Live (apps/communication) |
| Account-level auto-pause guardrail (tighter than SES's own) | ✅ Live |
| RFC 8058 one-click unsubscribe | ✅ Live |
| Double opt-in on newsletter signup | ✅ Live (nl_settings.doubleOptIn) |
| Bot protection on public form submissions (Turnstile) | ✅ Live (forms-service) |
| Bot protection on public newsletter signup (Turnstile) | ✅ NEW — apps/newsletter-service/src/routes/public.route.ts, activates once TURNSTILE_SECRET_KEY is provisioned (§3.4) |
abuse@ / postmaster@ monitored mailboxes |
❌ Not yet routed — action needed, see §3.2 |
| CAN-SPAM physical address in every send | ⚠️ Mechanism exists ({{ org.address }} in the footer, comms_sender_settings.org_* columns) but unset for Vlozi's own tenant — action needed, see §3.3 |
| Public site accurately names the mail sub-processor | ✅ NEW — About/Security/Status/Privacy pages corrected from "Resend" to "AWS SES" |
| Non-blocking transactional fallback if SES stays sandboxed | ✅ NEW — Resend re-added as a send-only fallback provider (EMAIL_PROVIDER=resend), scoped to platform-owned domains only. See apps/communication/src/providers/resend-provider.ts. Not a substitute for SES approval — it has no bounce/complaint webhook, so it's meant as a short-term safety net, not a long-term parallel path. |
3. What's still on you (things I can't do from here)
3.1 Tighten DMARC (DNS change — needs Cloudflare zone write access I don't have)
Current: _dmarc.vlozi.app = v=DMARC1; p=none; rua=mailto:...@dmarc-reports.cloudflare.net
(Cloudflare-managed, monitor-only). mail.vlozi.app has no record of its own, so it
inherits this via DMARC's organizational-domain fallback — same effective policy.
Change the vlozi.app TXT record (covers both domains) to:
v=DMARC1; p=quarantine; pct=100; rua=mailto:dmarc@vlozi.app; adkim=s; aspf=sDKIM alignment is already solid on both domains, so this is low-risk — it just makes the policy match what's already true in practice. Do this before resubmitting to AWS so the case narrative in §1 is accurate.
3.2 Route abuse@ and postmaster@ (Cloudflare Email Routing — needs dashboard access)
Cloudflare → vlozi.app zone → Email → Email Routing → add two rules:
abuse@vlozi.app→ forward to an inbox you monitorpostmaster@vlozi.app→ forward to an inbox you monitor
Repeat for mail.vlozi.app if Cloudflare lets you scope routing rules to that
subdomain independently (it already has its own MX records pointed at Cloudflare's
routing infra, so it should).
3.3 Set Vlozi's own organization address
Dashboard → Communications → Identity (this is the same settings screen every tenant
uses — apps/seller-dashboard/.../newsletter/pages/settings). You told me you don't
have a registered business entity or address ready yet — that's fine, CAN-SPAM
accepts a personal mailing address for a sole proprietor, no registration required.
Whatever you enter here also fills the [INSERT] blank in §1.
3.4 Provision the Resend fallback (only if you want it live, not just built)
- Create/verify a Resend account + verify
vlozi.appthere (Resend's own DKIM flow). wrangler secret bulkintoapps/communication:RESEND_API_KEY=re_...andEMAIL_PROVIDER=resend(omitEMAIL_PROVIDERor set it tosesto keep SES as default — only flip toresendif SES sending is actually blocked).- Provision a Turnstile widget (Cloudflare dashboard → Turnstile) for the newsletter
signup form, set
TURNSTILE_SECRET_KEYas a comms secret, and add the widget's client-side script + sitekey to wherever tenants embed their subscribe form (mirrors the pattern forms-service already uses).
3.5 If this third submission is also denied without specifics
You confirmed the account has Developer/Business support — use it. Phone or chat escalation to an SES specialist tends to surface actual, actionable feedback that the async case queue won't. Ask specifically for the SES team, reference this being the third denial with no stated reason, and ask what a specialist needs to see to approve a 2,000/day capped request.
4. Summary of code shipped this session
| File | Change |
|---|---|
apps/communication/src/providers/resend-provider.ts |
New — Resend send-only fallback client (C1 bounded retry, same contract as ses-provider.ts) |
apps/communication/src/index.ts |
dispatchSend now branches to Resend when EMAIL_PROVIDER=resend + RESEND_API_KEY are set, restricted to vlozi.app/mail.vlozi.app sends |
apps/communication/test/resend-provider.test.ts, test/send-resend-fallback.test.ts |
New tests — 387/387 communication tests pass |
apps/newsletter-service/src/lib/turnstile.ts |
New — mirrors forms-service's Turnstile verifier |
apps/newsletter-service/src/routes/public.route.ts, src/schemas/newsletter.schema.ts |
/public/subscribe now checks Turnstile when TURNSTILE_SECRET_KEY is configured (no-op until then — existing embeds keep working) |
apps/website/app/{about,security,status,privacy}/page.tsx |
Corrected stale "Resend" claims to "AWS SES" |
Communication: 387/387 tests pass. Newsletter-service: 394/394 tests pass.