# Flowmails v0.1 — llms-full.txt # Updated: see 2026-08-04 # Flowmails — full site content for AI agents > Machine-readable companion to the public site at /. > Last updated: 2026-07-12. Site version: v0.1. > This file is the single source of truth for the entire public > Flowmails site, formatted as one Markdown document. For an index > with one-line descriptions per page, see [/llms.txt](/llms.txt). > Coding agents integrating `@flowmails/flowmails-sdk` should > install the `flowmails-sdk` skill instead — > `npx skills add wms-why/flowmails-sdk-plugin@flowmails-sdk`. --- # Flowmails — home ## Tagline > Self-hosted email API on Cloudflare — your inbox, outbox, and > webhooks in your own D1. ## What Flowmails is Flowmails is a Cloudflare-native email routing platform. Every account you onboard creates a per-account Worker in **your** Cloudflare account, writes inbound mail to **your** D1 database, stores attachments in **your** R2 bucket, and uses Cloudflare Email Services for outbound. There is no shared multi-tenant table, no SMTP relay to operate, and no separate control plane. ## Why teams pick Flowmails The platform is chosen by teams that can't outsource the inbox — product teams shipping transactional mail from a Cloudflare-native stack, support teams that need per-localpart routing and an audit trail, agencies that manage many domains under one dashboard, and regulated teams that want their email data to live inside their own Cloudflare account. ## Runtime at a glance Inbound: Cloudflare Email Routing → per-account Worker → D1 + attachments on R2. Outbound: `POST /api/email/send` on the same Worker → Cloudflare Email Services → recipient SMTP. Routing: per-domain route tables (literal matcher → mailbox localpart → D1 row). There is no shared multi-tenant table and no SMTP relay to operate. ## How it works (three steps) 1. **Connect a Cloudflare account.** You bring a scoped API token that grants Flowmails the minimum permissions it needs (zone read, Email Routing, Worker / D1 / R2 writes inside one zone). Tokens can be audited and revoked from your Cloudflare dashboard. 2. **Pick a zone and approve Email Routing.** Choose a domain you already host on Cloudflare. Flowmails creates the catch-all and the per-localpart rules, you approve them, and Cloudflare flips the MX record automatically. 3. **Send or receive.** Inbound mail lands in the D1 inbox view inside Flowmails. Outbound mail goes through the same Worker via `POST /api/email/send`. Your data never leaves your account. Total time from token to first inbound message: about a minute. ## Four guarantees the platform is built on 1. **Self-hosted in your Cloudflare account.** Every Worker, every D1 row, every R2 object lives in the Cloudflare account you connected. There is no Flowmails-owned copy of your email data. 2. **Custom-domain inbound routing.** Per-domain route tables let you map each localpart (`support@`, `info@`, `abuse@`) to a specific mailbox or forward. Catch-all fallback is explicit, not default. 3. **Outbound via Cloudflare Email Services.** Outbound mail is sent from your domain through Cloudflare's own Email Services — no third-party SMTP relay, no shared sending IP. 4. **REST API + webhooks.** Every dashboard action has a REST equivalent. Webhooks stream inbound events for automation. ## Use cases - **Product teams** shipping transactional mail (order confirmations, password resets, receipts) from a Cloudflare- native stack — Workers, D1, R2 already, email should fit the same model. - **Support teams** that need per-localpart routing (`support@`, `billing@`, `abuse@`) and a queryable audit trail in their own D1 instead of an opaque shared inbox. - **Agencies** managing many domains under one dashboard, with per-domain route templates and bring-your-own Cloudflare token. - **Regulated teams** (EU residency, GDPR data export) that need email data to live inside their own Cloudflare account and to be exportable as a SQL dump on demand. ## What the AI draft-and-reply feature looks like Coming Q3 2026: drafting, auto-reply, and summarization run on Workers AI by default. Prompt templates, the messages used as context, and the resulting drafts all stay inside your D1. AI can be disabled per-domain or wired to a different model provider. ```json { "model": "@cf/meta/llama-3-8b-instruct", "scope": "domain:yourdomain.com", "prompt": "draft reply to support ticket #8421", "data_residency": "your-d1" } ``` ## FAQ **What can I do with the API?** Anything the dashboard can do. List and search messages, send a new message, manage routing rules, rotate API keys, and subscribe to webhook events for inbound mail. The API is REST over HTTPS with bearer-token auth and works from Workers, Node, Python, or curl. **How is the AI draft and reply feature scoped?** When it launches in Q3 2026, drafting and auto-reply run on Workers AI by default. Your prompt templates, the messages used as context, and the resulting drafts all stay inside your D1. You can disable AI per-domain or wire a different model provider. **Can I migrate away from Flowmails later?** Yes. Because the data is in your D1, exporting is a SQL dump. There is no proprietary schema lock-in — the table layout is documented and stable. **Which Cloudflare plan do I need?** A free Cloudflare account can route a small domain. Production senders should be on a paid plan because Cloudflare Email Services has its own pricing independent of Flowmails. Flowmails' own pricing covers the platform layer. --- # Flowmails — pricing ## TL;DR Three self-hosted plans, billed by the platform layer. Cloudflare's own Email Services cost is billed by Cloudflare directly to your account — there is no markup. ## Plans | Tier | Price | Domains | Route templates | API keys | Highlights | |-----------|----------------------|--------------------------|-----------------|----------|------------| | Base | Free forever | up to 1 custom domain | 3 templates | 1 key | REST API, webhooks, D1-backed inbox/outbox | | Pro | $19 / month | up to 10 domains | 25 templates | 10 keys | + AI draft & reply bundle, custom R2 subdomain, priority queue | | Enterprise| $199 / month | unlimited | unlimited | unlimited | + SSO, audit logs, 99.9 % SLA, white-label branding, dedicated Slack | Pricing is provider-agnostic. The full live list of accepted payment methods (Waffo / Creem / PayPal) is rendered in the trust strip on [/price](/price) and tracked by the `VITE_BILLING_PROVIDERS` build-time env var mirrored in `wrangler.jsonc#vars`. ## What's included on every plan Every plan — including Base — includes the Cloudflare-native routing layer, the REST API, and the templates library. You are buying an operating model and a managed dashboard, not just a domain forwarder. ## Pricing FAQ **What happens during onboarding?** You connect a Cloudflare account with a scoped API token, pick a zone you already host on Cloudflare, and approve the Email Routing rules. The Worker and D1 database are provisioned in your account — typically in under a minute. **Do plans include the routing runtime?** Yes. Every plan — including Base — includes the Cloudflare-native routing layer, the REST API, and the templates library. **Is the Base plan really free forever?** Yes, with a cap of 1 custom domain, 3 custom route templates, and 1 API key. The data still lives in your own D1, so you can upgrade to Pro or Enterprise without migrating anything. **When should a team move up to Enterprise?** Enterprise fits teams managing 10+ domains, who need SSO, audit logs, a 99.9 % uptime SLA, white-label branding, and priority support with a shared Slack channel. **Are there overage charges?** On Pro, AI reply drafts are bundled at 500 / month with no overage — upgrade to Enterprise for the 5,000 / month bundle and $0.05 / call overage. Cloudflare's own Email Services pricing is billed by Cloudflare directly and is independent of Flowmails pricing. --- # Flowmails — docs (SDK reference) The complete SDK reference lives under [/docs](/docs). For coding agents integrating `@flowmails/flowmails-sdk`, install the `flowmails-sdk` skill (`npx skills add wms-why/flowmails-sdk-plugin@flowmails-sdk`) — it auto-injects the SDK contract into every session. The sections below are a condensed overview for AI agents that want to understand *what* the SDK does without writing code against it. ## Overview The SDK is a thin, dependency-free TypeScript client. One constructor, one method, one wire endpoint. Five minutes from `pnpm add` to a delivered transactional message — no SMTP server, no API token rotation, no per-request signing ceremony. Available endpoints in v0.1: - `POST /api/v1/messages` — send a transactional message. Bearer-auth with an SDK key. Returns `{ id, status: "queued" }` on 201. - `GET /health` — no-auth liveness probe, returns `{ ok: true }`. Anything outside `/api/v1/*` and `/health` returns plain-text `Not Found` with status 404. ## Install ```bash pnpm add @flowmails/flowmails-sdk # or npm install @flowmails/flowmails-sdk # or yarn add @flowmails/flowmails-sdk ``` The package carries zero runtime dependencies — it uses `fetch` and `Uint8Array`, so it runs in Node 18+, Cloudflare Workers, Bun, Deno, and the browser without a polyfill. ## Quick start ```ts import { Flowmails } from "@flowmails/flowmails-sdk"; const fm = new Flowmails({ apiKey: process.env.FLOWMAILS_API_KEY!, // baseURL: "https://sdk.flowmails.net", // default // maxRetries: 2, // default }); const result = await fm.send({ from: "support@yourdomain.com", to: "customer@example.com", subject: "Order #1234 confirmed", text: "Thanks for your order — we'll ship it tomorrow.", }); console.log(result); // { id: "msg_8421", status: "queued" } ``` ## Constructor options | Option | Type | Notes | |-------------|---------------------|-------| | apiKey | `string` | Required. `fm_<32+hex>` minted in the dashboard. | | baseURL | `string` | Default `https://sdk.flowmails.net`. | | maxRetries | `number` | Auto-retry 5xx / 408 / 429. Default 2. Set 0 to disable. | | requestId | `string` | Sends `X-Flowmails-Request-Id` on every request. | | fetch | `typeof fetch` | Inject a fetch implementation (Workers, tests). | ## Payload shape ```ts interface SendOptions { from: string; // required, on bound domain fromName?: string; // optional display name to: string | string[]; // one recipient or array replyTo?: string; subject: string; // 1..998 chars text?: string; // optional iff html present html?: string; // optional iff text present attachments?: SendAttachment[]; } interface SendAttachment { filename: string; content: string | Uint8Array; // Uint8Array → base64 inside SDK mimeType?: string; // defaults to application/octet-stream } interface SendResult { id: string; status: "queued"; } ``` ## Validation rules (server-side) - `from` must match RFC 5322 and must land on the domain bound to the API key. Mismatch → 422 `from_domain_mismatch`. - Every `to` must be a valid email address. - `subject` length 1..998 chars. - At least one of `text` / `html` must be a non-empty string. Each body is capped at 1,000,000 chars. - Local-part of `from` must be 1..64 chars. ## Error envelope ```http HTTP/1.1 422 Unprocessable Entity Content-Type: application/json { "error": "from_domain_mismatch", "fromDomain": "attacker.example.com", "boundDomain": "yourdomain.com" } ``` ## HTTP → code matrix | HTTP | Codes | SDK class | Retryable | |----------|--------------------------------------------------------------------|---------------------|-----------| | 400 | invalid_json, validation_failed, missing_or_invalid_bearer | ValidationError | no | | 401 | api_key_invalid, api_key_revoked | AuthenticationError | no | | 404 | domain_not_found | ValidationError | no | | 422 | from_domain_mismatch, domain_not_bound, worker_not_deployed | ValidationError | no | | 429 | rate_limited | RateLimitError | yes | | 502 | send_failed, decode_failed, internal_error | UpstreamError | yes | | network | network_error | UpstreamError | yes | ## The FlowmailsError hierarchy Every error extends `FlowmailsError`. Use `instanceof` to discriminate. - `AuthenticationError` (401): `api_key_invalid`, `api_key_revoked`. - `ValidationError` (400 / 422): carries `detail` with the human-readable reason. - `RateLimitError` (429): retryable, no per-key `Retry-After` header yet. - `UpstreamError` (502 / 504 / 408): carries `upstreamMessage` from the receive-worker. - `FlowmailsError` (other): catch-all for unexpected statuses. ## Retry policy - **Retried** (default 2 attempts, exponential backoff with jitter, capped at 4 s): 5xx, 408, 429, and network-level failures. - **Never retried**: 400, 401, 404, 422 — fix the request. - **Timeout**: 15-second `AbortSignal.timeout`. - **Idempotency**: `send` is NOT idempotent. Build a request id into the subject line if your caller can retry on network failure. ## Discriminating with instanceof ```ts try { const { id } = await fm.send({ from, to, subject, text }); console.log("queued", id); } catch (err) { if (err instanceof RateLimitError || err instanceof UpstreamError) { await enqueueRetry(err); // SDK has already retried } else if (err instanceof AuthenticationError) { await notifyOps("sdk-key-revoked", err); // key rotated or revoked } else if (err instanceof ValidationError) { logger.warn({ code: err.code, detail: err.detail }, "validation"); } else if (err instanceof FlowmailsError) { logger.error({ code: err.code, status: err.status }, "sdk"); } else { throw err; // not from us } } ``` ## API keys Format: `fm_<32+hex>`. Minted in the dashboard at [/dashboard/settings/api-keys](/dashboard/settings/api-keys). Every key is pinned to exactly one of your registered domains. The dashboard shows the raw key exactly once. ## What the SDK does NOT do (v0.1) - Reads: no `messages.list`, `messages.get`, `threads.get`. Use the dashboard inbox. - Webhooks: no outbound delivery on queued → sent → bounced. Poll the dashboard. - Per-key rate-limit headers: no `X-Flowmails-RateLimit-Remaining`. Client-side backoff is the only mitigation. - Custom attachment hosting: attachments always go through the platform's R2 bucket. - Idempotency keys: `send` is not idempotent on the wire. ## AI-agent integration Coding agents integrating `@flowmails/flowmails-sdk` should install the `flowmails-sdk` skill, which auto-injects the SDK contract (constructor signature, five error classes, retry policy, payload shapes) into every session. The recommended install + use prompt is documented on [/docs/ai-agents](/docs/ai-agents); a shorter form: ```bash npx skills add wms-why/flowmails-sdk-plugin@flowmails-sdk ``` > Make sure the `flowmails-sdk` skill is installed via > `npx skills add wms-why/flowmails-sdk-plugin@flowmails-sdk`, then add > a Flowmails client to this project using `FLOWMAILS_API_KEY`, and > wire it up so I can call `fm.send()` from any server-side route / > handler / API endpoint with a typed `SendOptions` payload. Do NOT > bypass the SDK with raw fetch / axios / curl. Branch errors with > `instanceof` (`AuthenticationError`, `ValidationError`, > `RateLimitError`, `UpstreamError`, `FlowmailsError`). The skill auto-injects the SDK contract into every coding-agent session. After it is installed, the agent does not need to re-fetch any external doc on every run. ## v0.2 roadmap (drafts) - `messages.list` / `messages.get` — read endpoints that mirror what the dashboard inbox already shows. - `threads.get` — conversation-level read resolving a root message-id to the full chain. - Outbound webhook delivery — signed HTTP POST on every queued → sent → bounced event. HMAC-SHA256 in `X-Flowmails-Signature`. At-least-once delivery with exponential backoff up to 24 h. - Per-key rate-limit headers — `X-Flowmails-RateLimit-Remaining` and `X-Flowmails-RateLimit-Reset` on every authenticated response. Wire shapes are drafts and may change before v0.2 ships. --- # Flowmails — blog (operator notes) Long-form writing about self-hosted email in D1, Workers-native routing, the REST API, and the parts of the platform that show up in the security review. ## Posts - **What is Flowmails?** — April 2026. A Cloudflare-native email routing platform that keeps your inbox and outbox in your own D1, with a REST API on top. [/blog/what-is-flowmails](/blog/what-is-flowmails) - **Cloudflare API token permissions, explained** — May 2026. The exact scopes Flowmails needs, the principle of least privilege, and the audit trail you can show your security reviewer. [/blog/cloudflare-api-token-permissions](/blog/cloudflare-api-token-permissions) - **How to send transactional email from your Cloudflare custom domain** — June 2026. Why most transactional-email providers are overkill for a Cloudflare-native team, and how Cloudflare Email Services + a Worker gets you there in a day. [/blog/send-transactional-email-from-cloudflare-domain](/blog/send-transactional-email-from-cloudflare-domain) - **Self-hosting your email data in Cloudflare D1 (no vendor lock-in)** — June 2026. The architectural case for putting inbox and outbox in your own D1 database, and what that means in practice for compliance, exports, and exit plans. [/blog/self-host-email-data-in-cloudflare-d1](/blog/self-host-email-data-in-cloudflare-d1) - **How Workers-native email routing actually processes your inbound mail** — June 2026. A tour of the runtime: Email Routing, the Worker, the R2 bucket for attachments, and the D1 tables behind a single inbound message. [/blog/workers-native-email-routing-explained](/blog/workers-native-email-routing-explained) - **Custom Email Routing on Cloudflare: Build Your Own Address Book** — June 2026. Why a catch-all isn't always enough, how Flowmails route tables replace it with explicit literal-matcher rules, and how to switch safely. [/blog/route-tables-explained](/blog/route-tables-explained) - **Contact the Flowmails team: advice, orders, and bug reports** — June 2026. Three role-based inboxes (`advice@`, `order@`, `bug@`) and a Twitter handle so feature requests, billing questions, and bug reports reach the person who can actually act on them. [/blog/contact](/blog/contact) --- # Flowmails — legal These pages are part of the public site but the full text is long and unchanged by feature work. For the authoritative version, fetch the URLs directly: - **Terms of Service** — [/terms](/terms) - **Privacy Policy** — [/legal/privacy](/legal/privacy) - **Acceptable Use** — [/acceptable-use](/acceptable-use) --- # Machine-readable - [/llms.txt](/llms.txt) — this site's index file, with one-line descriptions per page. - [/llms-full.txt](/llms-full.txt) — this file. Use it when an LLM needs the full platform context. - `flowmails-sdk` skill — install via `npx skills add wms-why/flowmails-sdk-plugin@flowmails-sdk`. Use it when an AI coding agent is integrating `@flowmails/flowmails-sdk`. - [/sitemap.xml](/sitemap.xml) — every indexable URL with `` timestamps. - [/robots.txt](/robots.txt) — crawler directives.