Closed beta

Changelog.

Every meaningful change ships here. SDK + API release notes start at the Phase 1 launch.

Phase 1.10 — per-event Metered tier code-side wiring + content sweep

Per-event Metered tier is now code-supported end-to-end. workspaces.tier enum gains 'metered'; TIER_CAPS adds a no-monthly-cap entry; tierOf() recognizes lookup_key mailsai_metered_per_event; stripe-webhook stops silently coercing unknown lookup_keys to Pro (auditable security fix); billing-meters-sync cron now POSTs usage records to Stripe via subscriptionItems.createUsageRecord(action:'set') for every metered workspace daily; /billing/portal accepts price_lookup_key so customers can checkout into Metered directly. Dashboard /billing card re-synced to current prices (Pro $20 / Scale $99 / Metered $0.001/send + $0.002/inbound (+$0.003 opt-in classify), coming soon), with the Outbound pool sequenced as Phase 2 roadmap. Classifier system prompt extends to six injection categories (tool_invocation added) so marketing parity holds. Content sweep across glossary per-call-mpp, blog per-call-mpp-pricing, 7 vs/comparisons pages, 5 integration guides, blog/mcp-native-email — Phase 3 references flipped to live-at-launch, vs/loops pricing refreshed Pro $29 → $20 / Scale $199 → $99, outdated outbound-pool rate copy removed (/pricing is the single source of truth), app.mails.ai/keys → api.mails.ai/keys in 6 files, fake CVE-2026-XXXX placeholder removed (replaced with real MSRC + OWASP LLM01 references). DEPLOY.md Stage 3.2 documents the Stripe products + the metered Price construction (aggregate_usage=last_during_period).

Pricing v2.1 — per-event Metered promoted to Day 1 + monthly tier price reductions

Free / Pro / Scale tiers + the per-event Metered tier ship together at Phase 1 launch. Pro $29 → $20 (matches Resend Pro at parity). Scale $199 → $99 (5× Pro instead of 7×; still ~2× premium on inbound parsing vs Postmark). Outbound pool sequenced as Phase 2 roadmap. Metered $0.001/send + $0.002/inbound (+$0.003 opt-in classify), coming soon, with no monthly minimum — quiet months cost $0. Free tier: 3,000 events/mo + 1 agent. Stripe lookup_keys unchanged for monthly tiers.

Phase 1.9 — public-deploy preparation + dispatch-scheduled cron wired

DEPLOY.md (new) — 7-stage public-domain deploy checklist: Turso prod DB → AWS SES out of sandbox (24-72hr async) → Stripe Live keys + webhook → Anthropic API key → Cloudflare DNS (CNAME + SPF + DKIM + DMARC + optional MX) → Vercel Pro project + env vars + custom domain → post-deploy verification (health probe, first sign-in, mint API key, smoke suite, Stripe webhook test, cron health). vercel.json gets /api/cron/dispatch-scheduled at * * * * * so scheduled-sends and draft-dispatches fire in prod (was Phase 1.7-hardened but never wired to a Vercel cron — total 4 crons now, Pro tier required). .env.example completed with MAILS_DASHBOARD_PUBLIC + MAILS_WEBHOOK_DEV_HOSTS NEVER-set-in-prod notes. README.md refreshed from months-stale 'Phase 1 day-1 scaffold ships 5 of 16 tables' to current reality (21 tables, 70+ routes, full dashboard). Three milestone tags now on GitHub: phase-1.7-hardening, phase-1.8-prelaunch, phase-1.9-deploy-prep.

Phase 1.8 — pre-launch hardening (verify-page XSS guard + err.message scrub + 6 security headers)

verify-page (magic-link consumer): isSafeRelativeUrl strict allowlist on the post-signin redirect (no //, no /\, ASCII-only regex); jsSafeEncode percent-encodes single quotes so encodeURIComponent + JS-single-quoted-string interpolation can't escape. Three probes verified: next=https://evil.com/ stripped, next=/'); alert(1); // stripped, next=/messages preserved. errors.ts: toResponse masks err.message to 'Internal server error' in production for non-ApiError throws; full error still logged server-side with request_id (affects ~20 routes via the shared funnel). next.config.ts: 6 headers on every route (HSTS 1y, X-Content-Type-Options nosniff, X-Frame-Options DENY, Referrer-Policy strict-origin-when-cross-origin, Permissions-Policy 10 deny-all directives, CSP with 'unsafe-inline' on script/style for Next.js hydration but tight everywhere else — connect-src 'self', frame-ancestors 'none', object-src 'none'). 11/11 Playwright + 61/61 stress + 33/33 smoke green. Tag: phase-1.8-prelaunch.

Phase 1.7 — security hardening (SSRF mitigation + fail-closed internal endpoints + Stripe-webhook signature required)

Webhook delivery: lib/net.assertPublicHost rejects loopback / private / link-local IPs before fetch — defense in depth against SSRF via customer-registered webhook URLs (MAILS_WEBHOOK_DEV_HOSTS env opens dev exemption, NEVER set in production). All /api/internal/* routes (SES bounce/complaint/delivery/inbound, Stripe webhook) fail-closed: missing shared secret returns 503, not silent accept. Stripe webhook now enforces stripe-signature header verification outside mock mode; missing STRIPE_WEBHOOK_SECRET in prod = 503. Tag: phase-1.7-hardening.

Phase 1.6 — dashboard scaffold (auth, agents, drafts, threads, events, messages, suppression, webhooks, logs, onboarding)

Full Next.js App Router dashboard at api.mails.ai. Magic-link auth (request → verify → session cookie), workspace onboarding with slug validation + reserved-slug guard + atomic create + membership + audit, ⌘K command palette, workspace switcher, /agents (list + create + detail + inbox view), /api-keys (create modal with mode + scopes, show-once plaintext, hash storage, revoke), /drafts (CRUD + send), /threads (full conversation view + reply composer wired to /api/v1/messages/[id]/reply), /events (structured reply event list + SSE live badge + detail with redeliver), /messages (list + detail with full timeline), /suppression (lookup + allowlist add/revoke + global list), /webhooks (create with event-type multi-select + signing-secret reveal-once + test-fire + replay), /logs (audit log with category pills), /billing (usage card + plan grid), /settings, /domains (Phase 2 stub).

Comparisons + integrations surfaces shipped

Two new content surfaces now live. /vs ships with four head-to-head comparisons (AgentMail, Resend, SendGrid, Postmark) — each with an honest matrix of where mails.ai goes deeper and where the comparison vendor leads. /integrations ships with four guides (Claude Code, Cursor, OpenAI Agents SDK, Anthropic SDK) — each with one-snippet setup, full code examples for both MCP-native and SDK paths where applicable. New CompareTable and InstallCard components, new TopNav entries (Integrations under Product, Compare under Resources). Sitemap extended automatically.

Four new blog posts on the architecture stack

Behavioral pool routing — how spam can't economically live on Clean infrastructure. Prompt injection in inbound email is a real RCE class — here's how mails.ai scans for it. Per-event metered pricing — why monthly tiers force you to over-commit. MCP-native email — `from mails import agent` becomes the default agent comms primitive. Each post is FAQ-rich, code-rich, with a Schema.org Article + FAQPage JSON-LD and per-post OG image generated at build.

Blog scaffold + first post (structured reply events)

Content-as-data engine for the blog. Each post is one TSX file in lib/blog/posts/ exporting meta + Body — registry update is one line. /blog index, dynamic /blog/[slug] with generateStaticParams + dynamicParams=false (closed-set 404 behavior), per-post OG image, FAQPage JSON-LD on posts that have FAQs, sitemap auto-extension. First post: Structured reply events — why your agent should never read raw email.

Interactive classifier playground + dashboard preview

Click-and-type classifier on the home page — drop in any email body and watch the same intent classifier, entity extraction, injection scan, and pool routing that ships in production. Browser-framed workspace mockup with sidebar, metric tiles, 14-day sparkline, per-agent reputation bars, and recent structured reply events. Mobile hamburger nav with full slide-in panel. Per-page hero glyphs.

Submenu navigation + ambient background + brand silo

Product ▾ and Resources ▾ dropdowns with hover-open and accent-tinted items. Ambient drifting gradient mesh behind every page (90s cycle, reduced-motion safe). Brand silo locked — sister brands no longer named on any public surface.

Per-page OG images + FAQPage JSON-LD + Related cross-links

Every topic page now has its own social-card OG image with page-specific eyebrow, headline, and footer chips. FAQPage Schema.org markup on /pricing, /architecture, and /manifesto for Google rich-snippet eligibility. 2-up Related cross-link cards before every closing CTA so visitors keep moving through topic pages.

Multipage refactor + pixel-perfect typography

Site split into 5 pages — /pricing, /use-cases, /architecture, /manifesto, plus a tighter home with new ExploreMore teaser grid. Hero h1 descender chop fixed across 6 headings. New IntersectionObserver-based ScrollReveal component. Mouse-follow spotlight on ExploreMore cards.

Visual ambition + brand voice cleanup

Animated 14-line structured-reply-event console (LiveDemo). Four named agents — Sarah, Marcus, Atlas, Cipher — each with their own SVG mockup. Closing install-terminal CTA.

Closed beta posture + Website v1

Site shipped with 10 polish rounds: cinematic lamp, flickering grid, floating envelopes, large type, aurora hero, TypeScript / Python / MCP code tabs, animated routing dots, bento Features, tiered pricing. Waitlist mechanism stripped — /signup is the placeholder until launch. Outbound pool sequenced as Phase 2.

Back home