EmailFlare
Run transactional email APIs and a team inbox on Cloudflare Workers.
EmailFlare is a self-hosted Postmark/Resend alternative built on Cloudflare (D1, Durable Objects, Email Workers, KV, Queues). Paid services required. Inspect the source and license in the linked repository.
Source & license
Upstream license: MIT
License TL;DR
You can use it, change it, self-host it and sell it. Keep the original copyright and license notice with copies of the code. You don’t have to publish your changes. The authors don’t promise it will work.
Explain MIT in plain English →Summary of the main license. Separate packages and assets can have different terms.
Inspect repository ↗Read this project’s actual license ↗Repository owner
See the upstream repository for the original creator and contributors.
Maintain this project? Maintainer verification →Cloudflare hosting
Paid services required
EmailFlare has a documented low-volume paid Cloudflare path beginning with Workers Paid ($5 USD/account/month), with separately metered usage. Arbitrary-recipient email requires Paid; database, storage and email usage above included allowances add charges.
Hosting requirements
- Use Workers Paid for arbitrary-recipient email, starting at $5 USD/account/month; 3,000 outbound emails/month are included, then $0.35 per 1,000.
- Workers Paid starts at $5 USD/account/month and includes 10 million requests/month plus 30 million CPU milliseconds/month; higher CPU limits do not make execution unmetered.
- Workers Paid D1 includes 25 billion rows read/month, 50 million written/month and 5 GB storage; database usage above those amounts is metered.
- Workers Paid KV includes 10 million reads/month, 1 million writes, deletes and lists/month each, plus 1 GB; additional usage is metered.
- Use R2 Standard storage, at most 10 GB-month, 1 million Class A operations and 10 million Class B operations/month; provision an eligible billing-enabled R2 account.
- Paid SQLite Durable Objects include 1 million requests/month, 400,000 GB-s duration/month and 5 GB-month SQL storage; active duration and excess database operations are metered.
- Workers Paid Queues includes 1 million operations/month; count writes, reads, deletes, retries and each 64 KB chunk, with usage above the allowance metered.
- Workers Paid Email Service includes 3,000 outbound emails/account/month, then $0.35 per 1,000; inbound Email Routing remains unmetered apart from Worker processing.
- Use a small personal or team workload; domain registration and optional third-party providers are separate costs. Provision your own IDs, secrets and migrations.
Sources checked 01/10/2026
Repository snapshot: d448ea2. Hosting eligibility reflects the deployment documentation and listed assumptions.
- resend ↗
Both services are built on Cloudflare — Email Sending, Email Routing, D1, KV, R2, Queues, and Durable Objects — and deploy as **Cloudflare Workers** (primary, zero-ops) or as a single **Docker** container with embedded SQLite (secondary, for self-hosting).
- postmark ↗
Both services are built on Cloudflare — Email Sending, Email Routing, D1, KV, R2, Queues, and Durable Objects — and deploy as **Cloudflare Workers** (primary, zero-ops) or as a single **Docker** container with embedded SQLite (secondary, for self-hosting).
- workers ↗
{ // ── Cloudflare Workers config template for emailflare ──────────────────────── // // ⚠ This is a TEMPLATE. It is tracked in git and contains REPLACE_WITH_* // placeholders. Do NOT put real resource IDs here. // // The setup script (scripts/setup.mjs / `just emailflare-api-worker-setup`) // generates the gitignored `wrangler.jsonc` from this template with your real IDs. // // ★ FIRST-TIME SETUP — one command does everything: // just emailflare-api-worker-setup // (creates D1 + KV, generates wrangler.jsonc, applies migrations, sets secrets, deploys) // // ★ DEPLOY UPDATES — migrates schema then redeploys atomically: // just emailf
- d1 ↗
everything: // just emailflare-api-worker-setup // (creates D1 + KV, generates wrangler.jsonc, applies migrations, sets secrets, deploys) // // ★ DEPLOY UPDATES — migrates schema then redeploys atomically: // just emailflare-api-worker-update // // ★ GRADUAL ROLLOUT — upload a version and control traffic split: // pnpm rollout:upload # apply migrations + upload new version // wrangler versions deploy \ // --version-percentage <VERSION_ID>=10 # 10 % traffic // wrangler versions deploy \ // --version-percentage <VERSION_ID>=100 # full cutover // // Manual setup (if needed): // 1. `wrangler d1 create emailflare` → fill in database_id bel
- kv ↗
thing: // just emailflare-api-worker-setup // (creates D1 + KV, generates wrangler.jsonc, applies migrations, sets secrets, deploys) // // ★ DEPLOY UPDATES — migrates schema then redeploys atomically: // just emailflare-api-worker-update // // ★ GRADUAL ROLLOUT — upload a version and control traffic split: // pnpm rollout:upload # apply migrations + upload new version // wrangler versions deploy \ // --version-percentage <VERSION_ID>=10 # 10 % traffic // wrangler versions deploy \ // --version-percentage <VERSION_ID>=100 # full cutover // // Manual setup (if needed): // 1. `wrangler d1 create emailflare` → fill in database_id below /
- r2 ↗
SETUP: // just emailflare-inbox-deploy // (creates D1, KV, R2, Queue, generates wrangler.jsonc, applies migrations, // sets secrets, builds inbox-ui, deploys) // // Manual setup (if needed): // 1. Create D1: wrangler d1 create emailflare-inbox → fill in database_id // 2. Create KV: wrangler kv namespace create emailflare-inbox-rate-limit → fill in id // 3. Create R2: wrangler r2 bucket create emailflare-inbox-attachments // 4. Apply migrations: pnpm migrations:apply:local // 5. Set secrets: // wrangler secret put SESSION_SECRET (min 32 chars, random) // wrangler secret put CF_API_TOKEN (CF token: Email Send + Zone + DNS) // wrangler se
- durable-objects ↗
d — Cloudflare error 10099). "migrations": [ { "tag": "v1", "new_sqlite_classes": ["NotificationsHub"], }, ], // Queue for sequence email delivery "queues": { "producers": [ { "binding": "EMAIL_QUEUE", "queue": "emailflare-inbox-sequences", }, ], "consumers": [ { "queue": "emailflare-inbox-sequences", "max_batch_size": 10, "max_batch_timeout": 30, }, ], }, // No hardcoded env vars here — all account/deployment-specific values are set // via `wrangler secret put` (see scripts/deploy-inbox.mjs + scripts/config.toml). // For local `wrangler dev`, copy .dev.vars.example → .dev.vars and fill in. // Workers Rate Limiting for API key calls (100 req / 60s pe
- queues ↗
"NotificationsHub"], }, ], // Queue for sequence email delivery "queues": { "producers": [ { "binding": "EMAIL_QUEUE", "queue": "emailflare-inbox-sequences", }, ], "consumers": [ { "queue": "emailflare-inbox-sequences", "max_batch_size": 10, "max_batch_timeout": 30, }, ], }, // No hardcoded env vars here — all account/deployment-specific values are set // via `wrangler secret put` (see scripts/deploy-inbox.mjs + scripts/config.toml). // For local `wrangler dev`, copy .dev.vars.example → .dev.vars and fill in. // Workers Rate Limiting for API key calls (100 req / 60s per key) "unsafe": { "bindings": [ { "name": "RATE_LIMITER", "type": "ratelimit"
- email-workers ↗
{ // ── Cloudflare Workers config template for emailflare ──────────────────────── // // ⚠ This is a TEMPLATE. It is tracked in git and contains REPLACE_WITH_* // placeholders. Do NOT put real resource IDs here. // // The setup script (scripts/setup.mjs / `just emailflare-api-worker-setup`) // generates the gitignored `wrangler.jsonc` from this template with your real IDs. // // ★ FIRST-TIME SETUP — one command does everything: // just emailflare-api-worker-setup // (creates D1 + KV, generates wrangler.jsonc, applies migrations, sets secrets, deploys) // // ★ DEPLOY UPDATES — migrates schema then redeploys atomically: // just emailflare-api-worker-update //
- paid ↗
{ // ── Cloudflare Workers config template for emailflare ──────────────────────── // // ⚠ This is a TEMPLATE. It is tracked in git and contains REPLACE_WITH_* // placeholders. Do NOT put real resource IDs here. // // The setup script (scripts/setup.mjs / `just emailflare-api-worker-setup`) // generates the gitignored `wrangler.jsonc` from this template with your real IDs. // // ★ FIRST-TIME SETUP — one command does everything: // just emailflare-api-worker-setup // (creates D1 + KV, generates wrangler.jsonc, applies migrations, sets secrets, deploys) // // ★ DEPLOY UPDATES — migrates schema then redeploys atomically: // just emailf
- paid ↗
everything: // just emailflare-api-worker-setup // (creates D1 + KV, generates wrangler.jsonc, applies migrations, sets secrets, deploys) // // ★ DEPLOY UPDATES — migrates schema then redeploys atomically: // just emailflare-api-worker-update // // ★ GRADUAL ROLLOUT — upload a version and control traffic split: // pnpm rollout:upload # apply migrations + upload new version // wrangler versions deploy \ // --version-percentage <VERSION_ID>=10 # 10 % traffic // wrangler versions deploy \ // --version-percentage <VERSION_ID>=100 # full cutover // // Manual setup (if needed): // 1. `wrangler d1 create emailflare` → fill in database_id bel
- paid ↗
thing: // just emailflare-api-worker-setup // (creates D1 + KV, generates wrangler.jsonc, applies migrations, sets secrets, deploys) // // ★ DEPLOY UPDATES — migrates schema then redeploys atomically: // just emailflare-api-worker-update // // ★ GRADUAL ROLLOUT — upload a version and control traffic split: // pnpm rollout:upload # apply migrations + upload new version // wrangler versions deploy \ // --version-percentage <VERSION_ID>=10 # 10 % traffic // wrangler versions deploy \ // --version-percentage <VERSION_ID>=100 # full cutover // // Manual setup (if needed): // 1. `wrangler d1 create emailflare` → fill in database_id below /
- paid ↗
up>1, 2, 3, 4</sup> | Duration | CPU time | | --- | --- | --- | --- | | **Free** | 100,000 per day | No charge for duration | 10 milliseconds of CPU time per invocation | | **Standard** | 10 million included per month <br> +$0.30 per additional million | No charge or limit for duration | 30 million CPU milliseconds included per month<br> +$0.02 per additional million CPU milliseconds<br><br> Max of [5 minutes of CPU time](https://developers.cloudflare.com/workers/platform/limits/#account-plan-limits) per invocation (default: 30 seconds)<br> Max of 15 minutes of CPU time per [Cron Trigger](https://developers.cloudflare.com/workers/configuration/cron-triggers/) or [Queue Consumer](https://developers.cloudflare.co
- paid ↗
oudflare.com/workers/platform/pricing/#workers) | | --- | --- | --- | | Rows read | 5 million / day | First 25 billion / month included + $0.001 / million rows | | Rows written | 100,000 / day | First 50 million / month included + $1.00 / million rows | | Storage (per GB stored) | 5 GB (total) | First 5 GB included + $0.75 / GB-mo | Track your D1 usage To accurately track your usage, use the [meta object](https://developers.cloudflare.com/d1/worker-api/return-object/), [GraphQL Analytics API](https://developers.cloudflare.com/d1/observability/metrics-analytics/#query-via-the-graphql-api), or the [Cloudflare dashboard ↗︎](https://dash.cloudflare.com/?to=/:account/workers/d1/). Select your D1 database, then vie
- paid ↗
cing/). | | Free plan<sup>1</sup> | Paid plan | | --- | --- | --- | | Keys read | 100,000 / day | 10 million/month, + $0.50/million | | Keys written | 1,000 / day | 1 million/month, + $5.00/million | | Keys deleted | 1,000 / day | 1 million/month, + $5.00/million | | List requests | 1,000 / day | 1 million/month, + $5.00/million | | Stored data | 1 GB | 1 GB, + $0.50/ GB-month | <sup>1</sup> The Workers Free plan includes limited Workers KV usage. All limits reset daily at 00:00 UTC. If you exceed any one of these limits, further operations of that type will fail with an error. Note Workers KV pricing for read, write and delete operations is on a per-key basis. Bulk read operations are billed by the amount
- paid ↗
infrequent access storage) for 1.1 GB, you will be billed for 2 GB. ### Free tier You can use the following amount of storage and operations each month for free. | | Free | | --- | --- | | Storage | 10 GB-month / month | | Class A Operations | 1 million requests / month | | Class B Operations | 10 million requests / month | | Egress (data transfer to Internet) | Free <sup>[1](#user-content-fn-1)</sup> | Caution The free tier only applies to Standard storage, and does not apply to Infrequent Access storage. ### Storage usage Storage is billed using gigabyte-month (GB-month) as the billing metric. A GB-month is calculated by averaging the *peak* storage per day over a billing period (30 days). For examp
- paid ↗
jects are available both on Workers Free and Workers Paid plans. - **Workers Free plan**: Only Durable Objects with [SQLite storage backend](https://developers.cloudflare.com/durable-objects/best-practices/access-durable-objects-storage/#create-sqlite-backed-durable-object-class) are available. - **Workers Paid plan**: Durable Objects with the SQLite storage backend are available. The [key-value storage backend](https://developers.cloudflare.com/durable-objects/reference/durable-objects-migrations/#storage-backends) is only available to accounts that already have a key-value-backed namespace. If you wish to downgrade from a Workers Paid plan to a Workers Free plan, you must first ensure that you have deleted all Durable Object namespaces with the key-value storage backend. On Workers Free plan: - If you exceed any one of the free tier limits, further operations of that type will fail with an error. - Daily free limits reset at 00:00 UTC. ## Compute billing Durable Objects are billed for compute duration (wall-clock time) while the Durable Object is actively running or is idle in memory but unable to [hibernate](https://developers.cloudflare.com/durable-objects/concepts/durable-object-lifecycle/). Durable Objects that are idle and eligible for hibernation are not billed for duration, even before the runtime has hibernated them. Requests to a D
- paid ↗
dth) charges. | | Workers Free | Workers Paid | | --- | --- | --- | | Standard operations | 10,000 operations/day included | 1,000,000 operations/month included + $0.40/million operations | | Message retention | 24 hours (non-configurable) | 4 days default, configurable up to 14 days | In most cases, it takes 3 operations to deliver a message: 1 write, 1 read, and 1 delete. Therefore, you can use the following formula to estimate your monthly bill: ```txt ((Number of Messages * 3) - 1,000,000) / 1,000,000 * $0.40 ``` Additionally: - Each retry incurs a read operation. A batch of 10 messages that is retried would incur 10 operations for each retry. - Messages that reach the maximum retries and that are wr
- paid ↗
g is based on your Cloudflare plan and email usage. ## Plan pricing Email Routing is available on both the Workers Free and Workers Paid plans. Sending to arbitrary recipients requires the Workers Paid plan. Sending to [verified destination addresses](https://developers.cloudflare.com/email-service/configuration/email-routing-addresses/#destination-addresses) in your account is free on all plans, including when only Email Routing is configured. | | Workers Free | Workers Paid | | --- | --- | --- | | **Outbound emails (Email Sending)** | Not available | 3,000 included per month, then $0.35 per 1,000 emails | | **Inbound emails (Email Routing)** | Unlimited | Unlimited | The 3,000 included emails apply per a
- paid ↗
billed accordingly. | | Free plan | Paid plan | | --- | --- | --- | | Requests | 100,000 / day | 1 million / month, + $0.15/million<br> Includes HTTP requests, RPC sessions<sup>1</sup>, WebSocket messages<sup>2</sup>, and alarm invocations | | Duration<sup>3</sup> | 13,000 GB-s / day | 400,000 GB-s / month, + $12.50/million GB-s<sup>4,5</sup> | <details> <summary> Footnotes </summary> <sup>1</sup> Each <a href="https://developers.cloudflare.com/workers/runtime-apis/rpc/lifecycle/">RPC session</a> is billed as one request to your Durable Object. Every <a href="https://developers.cloudflare.com/durable-objects/best-practices/create-durable-object-stubs-and-send-requests/">RPC method call</a> on a <a href="https://developers.cloudflare.com/durable-objects/">Durable Objects stub</a> is its own RPC session and therefore a single billed request. RPC method calls can return objects (stubs) extending <a href="https://developers.cloudflare.com/workers/runtime-apis/rpc/lifecycle/#lifetimes-memory-and-resource-management"><code>RpcTarget</code></a> and invo
- paid ↗
/). | | Workers Free plan | Workers Paid plan | | --- | --- | --- | | Rows reads <sup>1,2</sup> | 5 million / day | First 25 billion / month included + $0.001 / million rows | | Rows written <sup>1,2,3,4</sup> | 100,000 / day | First 50 million / month included + $1.00 / million rows | | SQL Stored data <sup>5</sup> | 5 GB (total) | 5 GB-month, + $0.20/ GB-month | <details> <summary> Footnotes </summary> <sup>1</sup> Rows read and rows written included limits and rates match <a href="https://developers.cloudflare.com/d1/platform/pricing/">D1 pricing</a>, Cloudflare's serverless SQL database. <sup>2</sup> Key-value methods like <code>get()</code>, <code>put()</code>, <code>delete()</code>, or <code>list(
- paid ↗
es Functions, Workers KV, Hyperdrive, and Durable Objects usage for a minimum charge of $5 USD per month for an account. The plan includes increased initial usage allotments, with clear charges for usage that exceeds the base plan. There are no additional charges for data transfer (egress) or throughput (bandwidth). All included usage is on a monthly basis. Pages Functions billing All [Pages Functions](https://developers.cloudflare.com/pages/functions/) are billed as Workers. All pricing and inclusions in this document apply to Pages Functions. Refer to [Functions Pricing](https://developers.cloudflare.com/pages/functions/pricing/) for more information on Pages Functions pricing. ## Workers Users on the Wo
- paid ↗
Routing is available on both the Workers Free and Workers Paid plans. Sending to arbitrary recipients requires the Workers Paid plan. Sending to [verified destination addresses](https://developers.cloudflare.com/email-service/configuration/email-routing-addresses/#destination-addresses) in your account is free on all plans, including when only Email Routing is configured. | | Workers Free | Workers Paid | | --- | --- | --- | | **Outbound emails (Email Sending)** | Not available | 3,000 included per month, then $0.35 per 1,000 emails | | **Inbound emails (Email Routing)** | Unlimited | Unlimited | The 3,000 included emails apply per account, per month, aligned with your Cloudflare subscription billing cycle. Emails that hard-bounce or are otherwise accepted by Email Service count toward the quota. Emails rejected at the API boundary, including sends blocke
- MIT ↗
MIT License Copyright (c) 2026 0xdps Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMEN
- architecture ↗
{ // ── Cloudflare Workers config template for emailflare ──────────────────────── // // ⚠ This is a TEMPLATE. It is tracked in git and contains REPLACE_WITH_* // placeholders. Do NOT put real resource IDs here. // // The setup script (scripts/setup.mjs / `just emailflare-api-worker-setup`) // generates the gitignored `wrangler.jsonc` from this template with your real IDs. // // ★ FIRST-TIME SETUP — one command does everything: // just emailflare-api-worker-setup // (creates D1 + KV, generates wrangler.jsonc, applies migrations, sets secrets, deploys) // // ★ DEPLOY UPDATES — migrates schema then redeploys atomically: // just emailf
- architecture ↗
everything: // just emailflare-api-worker-setup // (creates D1 + KV, generates wrangler.jsonc, applies migrations, sets secrets, deploys) // // ★ DEPLOY UPDATES — migrates schema then redeploys atomically: // just emailflare-api-worker-update // // ★ GRADUAL ROLLOUT — upload a version and control traffic split: // pnpm rollout:upload # apply migrations + upload new version // wrangler versions deploy \ // --version-percentage <VERSION_ID>=10 # 10 % traffic // wrangler versions deploy \ // --version-percentage <VERSION_ID>=100 # full cutover // // Manual setup (if needed): // 1. `wrangler d1 create emailflare` → fill in database_id bel
- architecture ↗
thing: // just emailflare-api-worker-setup // (creates D1 + KV, generates wrangler.jsonc, applies migrations, sets secrets, deploys) // // ★ DEPLOY UPDATES — migrates schema then redeploys atomically: // just emailflare-api-worker-update // // ★ GRADUAL ROLLOUT — upload a version and control traffic split: // pnpm rollout:upload # apply migrations + upload new version // wrangler versions deploy \ // --version-percentage <VERSION_ID>=10 # 10 % traffic // wrangler versions deploy \ // --version-percentage <VERSION_ID>=100 # full cutover // // Manual setup (if needed): // 1. `wrangler d1 create emailflare` → fill in database_id below /
- architecture ↗
SETUP: // just emailflare-inbox-deploy // (creates D1, KV, R2, Queue, generates wrangler.jsonc, applies migrations, // sets secrets, builds inbox-ui, deploys) // // Manual setup (if needed): // 1. Create D1: wrangler d1 create emailflare-inbox → fill in database_id // 2. Create KV: wrangler kv namespace create emailflare-inbox-rate-limit → fill in id // 3. Create R2: wrangler r2 bucket create emailflare-inbox-attachments // 4. Apply migrations: pnpm migrations:apply:local // 5. Set secrets: // wrangler secret put SESSION_SECRET (min 32 chars, random) // wrangler secret put CF_API_TOKEN (CF token: Email Send + Zone + DNS) // wrangler se
- architecture ↗
d — Cloudflare error 10099). "migrations": [ { "tag": "v1", "new_sqlite_classes": ["NotificationsHub"], }, ], // Queue for sequence email delivery "queues": { "producers": [ { "binding": "EMAIL_QUEUE", "queue": "emailflare-inbox-sequences", }, ], "consumers": [ { "queue": "emailflare-inbox-sequences", "max_batch_size": 10, "max_batch_timeout": 30, }, ], }, // No hardcoded env vars here — all account/deployment-specific values are set // via `wrangler secret put` (see scripts/deploy-inbox.mjs + scripts/config.toml). // For local `wrangler dev`, copy .dev.vars.example → .dev.vars and fill in. // Workers Rate Limiting for API key calls (100 req / 60s pe
- architecture ↗
"NotificationsHub"], }, ], // Queue for sequence email delivery "queues": { "producers": [ { "binding": "EMAIL_QUEUE", "queue": "emailflare-inbox-sequences", }, ], "consumers": [ { "queue": "emailflare-inbox-sequences", "max_batch_size": 10, "max_batch_timeout": 30, }, ], }, // No hardcoded env vars here — all account/deployment-specific values are set // via `wrangler secret put` (see scripts/deploy-inbox.mjs + scripts/config.toml). // For local `wrangler dev`, copy .dev.vars.example → .dev.vars and fill in. // Workers Rate Limiting for API key calls (100 req / 60s per key) "unsafe": { "bindings": [ { "name": "RATE_LIMITER", "type": "ratelimit"
What it can replace
Compare the workflow you need. These mappings describe overlap; full feature parity requires a separate comparison.
Transactional email API sending, templates, delivery records and suppression management; full commercial deliverability operations, SLAs and every provider integration are excluded.
See supporting source ↗Transactional email API sending, templates, delivery records and suppression management; full commercial deliverability operations, SLAs and every provider integration are excluded.
See supporting source ↗How it works
The shape of EmailFlare on Cloudflare, and how it stacks up against the rented tools it replaces.
Architecture
Diagram of deployment declarations at the reviewed commit. Each app has its own entrypoint; declared resources do not prove runtime calls. Follow file and line sources below.
View upstream source ↗Configuration and workflow sources
Reviewed commit d448ea205937. Files were read as data; upstream applications and CI jobs were not executed.
Partial source coverage: 46 files outside collection bounds; 0 collection or parsing issues. Dynamic imports and generated entrypoints may need manual review.
Deployment configuration · 5 files
Cloudflare Workers · compatibility 2025-05-01
emailflare-api-bridge · default
Entrypoint: src/index.ts
No resource bindings declared in this scope.
Cloudflare Workers · compatibility 2025-01-01
emailflare-inbox-bridge · default
Entrypoint: src/index.ts
No resource bindings declared in this scope.
Cloudflare Workers · example/template, excluded from overview · compatibility 2025-05-01
emailflare-api-worker · default
Entrypoint: src/index.ts
Static assets: ../email-ui/dist · single-page-application
DB→ D1RATE_LIMIT_KV→ KVASSETS→ Static assets
Cloudflare Workers · example/template, excluded from overview · compatibility 2025-05-01
emailflare-inbox-worker · default
Entrypoint: src/index.ts
Static assets: ../inbox-ui/dist · single-page-application
Cron triggers (UTC): */5 * * * *
DB→ D1RATE_LIMIT_KV→ KVATTACHMENTS→ R2NOTIFICATIONS→ Durable Objects · class NotificationsHubEMAIL_QUEUE→ Queues (producer) · queue emailflare-inbox-sequencesemailflare-inbox-sequences→ Queues (consumer) · queue emailflare-inbox-sequencesASSETS→ Static assets
Cloudflare Workers · compatibility 2026-04-28
emailflare · default
Static assets: ./dist · 404-page
Static assets→ Static assets
Named environments are separate deployments. Bindings are shown only where declared. Configured routes are URL patterns, not verified application endpoints.
Runtime source · handlers, binding usage and workflow steps
Observed TypeScript/JavaScript declarations from Worker entrypoints and resolved relative imports. Calls and workflow steps may run conditionally; their listed order is not a proven end-to-end request flow. Router declarations may be mounted under a prefix or may not be registered. This shows code wiring, not a successful deployment or runtime test. Dynamic wiring, aliases and generated code may not resolve.
- L37 · loadConfig calls (conditional paths may differ): existsSync, parseToml, readFileSync, die
- L69 · run calls (conditional paths may differ): execSync
- L77 · capture calls (conditional paths may differ): spawnSync
- L87 · log calls (conditional paths may differ): process.stdout.write
- L91 · ok calls (conditional paths may differ): process.stdout.write
- L95 · warn calls (conditional paths may differ): process.stdout.write
- L99 · die calls (conditional paths may differ): process.stderr.write, process.exit
- L104 · promptSecret calls (conditional paths may differ): process.stdout.write, createInterface, process.stdin.setRawMode, chunk.toString, process.stdin.removeListener, rl.close, resolve, process.exit, value.slice, process.stdin.on, process.stdin.resume
- L115 · onData calls (conditional paths may differ): chunk.toString, process.stdin.setRawMode, process.stdin.removeListener, rl.close, process.stdout.write, resolve, process.exit, value.slice
Environment references: process.env.EMAILFLARE_DB_NAME · process.env.CLOUDFLARE_API_TOKEN · process.env.CLOUDFLARE_ACCOUNT_ID
- L17 · email handler exported · references EMAIL_SERVER_URL, WEBHOOK_SECRET · calls arrayBuffer, env.EMAIL_SERVER_URL.replace, fetch
Environment references: env.EMAIL_SERVER_URL · env.WEBHOOK_SECRET
- L31 · email handler exported · references INBOX_WEBHOOK_SECRET, INBOX_SERVER_URL · calls arrayBuffer, btoa, String.fromCharCode, JSON.stringify, message.headers.get, hmacSha256Hex, env.INBOX_SERVER_URL.replace, fetch
- L16 · hmacSha256Hex calls (conditional paths may differ): crypto.subtle.importKey, encode, crypto.subtle.sign, join, map, Array.from, padStart, b.toString
Environment references: env.INBOX_WEBHOOK_SECRET · env.INBOX_SERVER_URL
- L144 · fetch handler exported
- L150 · email handler exported · calls handleInboundEmail
- L57 · app.use("*")
- L60 · app.use("/v1/*")
- L69 · app.use("/api/*")
- L84 · app.get("/health")
- L87 · app.route("/v1/unsubscribe")
- L90 · app.use("/v1/send")
- L91 · app.use("/v1/send")
- L92 · app.route("/v1/send")
- L95 · app.route("/api/auth")
- L99 · admin.use("*")
- L102 · admin.get("/layouts")
- L107 · admin.post("/layouts/:id/preview")
- L115 · admin.route("/domains")
- L116 · admin.route("/templates")
- L117 · admin.route("/keys")
- L118 · admin.route("/logs")
- L119 · admin.route("/stats")
- L120 · admin.route("/cloudflare")
- L121 · admin.route("/suppressions")
- L122 · admin.route("/lists")
- L124 · app.route("/api")
- L137 · app.post("/api/_seed")
- L42 · parseAdminOrigins calls (conditional paths may differ): map, filter, raw.split, d.trim, d.startsWith
Environment references: c.env.ADMIN_ORIGIN · c.env.DB
- L161 · fetch handler exported · calls app.fetch
- L166 · email handler exported · calls handleIncomingEmail
- L171 · scheduled handler exported · calls processDueSequenceSteps
- L176 · queue handler exported · calls handleSequenceQueueMessage, msg.ack, msg.retry
- L68 · app.use("/v1/*")
- L78 · app.get("/health")
- L79 · app.route("/api/setup")
- L80 · app.route("/api/auth")
- L81 · app.route("/api")
- L84 · app.route("/v1/unsubscribe")
- L87 · app.use("/v1/*")
- L88 · app.route("/v1/send")
- L92 · adminApp.use("/*")
- L94 · adminApp.route("/domains")
- L95 · adminApp.route("/keys")
- L96 · adminApp.route("/logs")
- L97 · adminApp.route("/templates")
- L98 · adminApp.route("/stats")
- L99 · adminApp.route("/cloudflare")
- L100 · adminApp.route("/lists")
- L101 · adminApp.route("/suppressions")
- L105 · testMailboxApp.use("/*")
- L106 · testMailboxApp.route("/")
- L107 · adminApp.route("/test-emails")
- L110 · adminApp.route("/inbox/people")
- L111 · adminApp.route("/inbox/compose")
- L112 · adminApp.route("/inbox/inboxes")
- L113 · adminApp.route("/inbox/sequences")
- L114 · adminApp.route("/inbox/templates")
- L118 · adminOnlyApp.use("/*")
- L119 · adminOnlyApp.route("/users")
- L120 · adminApp.route("/admin")
- L123 · adminApp.get("/notifications/ws")
- L131 · adminApp.post("/seed")
- L136 · app.route("/api")
- L148 · app.all("*")
Environment references: c.env.NOTIFICATIONS · c.env.DB · c.env.ASSETS
- L19 · secretKey calls (conditional paths may differ): encode
- L23 · getSession calls (conditional paths may differ): getCookie, jwtVerify, secretKey, Boolean
- L34 · saveSession calls (conditional paths may differ): sign, setExpirationTime, setIssuedAt, setProtectedHeader, secretKey, setCookie
- L52 · clearSession calls (conditional paths may differ): deleteCookie
Environment references: c.env.SESSION_SECRET
- L9 · sha256Hex calls (conditional paths may differ): encode, crypto.subtle.digest, join, map, Array.from, padStart, b.toString
Environment references: c.env.DB
- L62 · seedSystemTemplates calls (conditional paths may differ): makeDb, toISOString, Object.entries, templates.findOne, templates.insert, generateId
- L27 · app.post("/login")
- L44 · app.post("/logout")
- L50 · app.get("/me")
- L11 · timingSafeEqual calls (conditional paths may differ): crypto.subtle.generateKey, Promise.all, crypto.subtle.sign, encoder.encode
Environment references: c.env.RATE_LIMIT_KV · c.env.ADMIN_TOKEN
- L18 · app.get("/")
- L25 · app.get("/:id")
- L33 · app.post("/")
- L91 · app.get("/:id/dns")
- L102 · app.post("/:id/verify")
- L123 · app.delete("/:id")
Environment references: c.env.DB · c.env.CF_API_TOKEN
- L13 · app.get("/")
- L27 · app.get("/themes")
- L37 · app.get("/:idOrSlug")
- L47 · app.post("/")
- L73 · app.put("/:id")
- L110 · app.delete("/:id")
- L121 · app.post("/:id/preview")
Environment references: c.env.DB
- L18 · app.get("/")
- L25 · app.post("/")
- L59 · app.delete("/:id")
- L8 · randomHex calls (conditional paths may differ): crypto.getRandomValues, join, map, Array.from, padStart, b.toString
Environment references: c.env.DB
Environment references: c.env.DB
- L27 · app.get("/")
- L9 · rangeStart calls (conditional paths may differ): now.setDate, now.getDate, now.setHours, now.toISOString
Environment references: c.env.DB
Environment references: c.env.CF_API_TOKEN · c.env.CF_ACCOUNT_ID · c.env.DB
- L20 · app.post("/")
Environment references: c.env.DB · c.env.PUBLIC_URL · c.env.CF_API_TOKEN · c.env.CF_ACCOUNT_ID
Environment references: c.env.DB
Environment references: c.env.DB
- L42 · app.get("/")
- L55 · app.post("/")
- L17 · resolveToken calls (conditional paths may differ): db.query
- L25 · performUnsubscribe calls (conditional paths may differ): makeDb, resolveToken, db.run, generateId, rec.email.toLowerCase, toISOString
Environment references: env.DB
- L31 · isBounce calls (conditional paths may differ): toLowerCase, BOUNCE_SUBJECTS.some, sub.includes, BOUNCE_FROM_PATTERNS.some, from.includes
- L37 · isComplaint calls (conditional paths may differ): toLowerCase, email.headers.find, h.key.toLowerCase, includes, ct.toLowerCase, COMPLAINT_SUBJECTS.some, sub.includes, COMPLAINT_FROM_PATTERNS.some, from.includes
- L51 · extractRecipient calls (conditional paths may differ): content.match, toLowerCase, trim
- L72 · classifyBounce calls (conditional paths may differ): content.match, code.startsWith, test, spamPhrases.some, includes, content.toLowerCase, hardPhrases.some
- L120 · extractReason calls (conditional paths may differ): content.match, slice, split, trim
- L139 · handleInboundEmail calls (conditional paths may differ): arrayBuffer, log.warn, parse, join, toISOString, isBounce, processBounce, isComplaint, processComplaint
- L174 · processBounce calls (conditional paths may differ): extractRecipient, log.warn, classifyBounce, extractReason, toISOString, Date.now, db.query, db.run, generateId, log.info, Number
- L247 · processComplaint calls (conditional paths may differ): extractRecipient, log.warn, toISOString, Date.now, db.query, db.run, generateId, log.info
Environment references: env.DB
Environment references: c.env.DB
Build and deployment pipeline · 3 GitHub Actions workflows
Repository CI declarations, separate from runtime request processing. Job dependencies and conditions are shown as written; long commands are shortened with an ellipsis; a workflow file does not prove a recent successful run.
Triggers: workflow_dispatch
Deploy emailflare-api-worker · no job dependencies declared
Condition: ${{ github.event.inputs.target == 'cf-api' || github.event.inputs.target == 'all' }}
- actions/checkout@v4
actions/checkout@v4 - Enable Corepack
corepack enable - actions/setup-node@v4
actions/setup-node@v4 - Install workspace dependencies
pnpm install --frozen-lockfile - Build shared packages
pnpm run build:shared - Build admin UI (email-ui)
pnpm install --frozen-lockfile pnpm build - Install worker deps
pnpm install --frozen-lockfile - Audit dependencies
pnpm audit --audit-level=high - Generate wrangler.jsonc
sed -e "s/REPLACE_WITH_D1_DATABASE_ID/${{ vars.EMAIL_WORKER_D1_ID }}/g" \ -e "s/REPLACE_WITH_KV_NAMESPACE_ID/${{ vars.EMAIL_WORKER_KV_ID }}/g" \ wrangler.example.jsonc > wrangler.jsonc - Apply D1 migrations
pnpm run migrations:apply - Deploy worker
npx wrangler deploy
Deploy emailflare-inbox-worker · no job dependencies declared
Condition: ${{ github.event.inputs.target == 'cf-inbox' || github.event.inputs.target == 'all' }}
- actions/checkout@v4
actions/checkout@v4 - Enable Corepack
corepack enable - actions/setup-node@v4
actions/setup-node@v4 - Install workspace dependencies
pnpm install --frozen-lockfile - Build shared packages
pnpm run build:shared - Build inbox UI (inbox-ui)
pnpm install --frozen-lockfile pnpm build - Install worker deps
pnpm install --frozen-lockfile - Audit dependencies
pnpm audit --audit-level=high - Generate wrangler.jsonc
sed -e "s/REPLACE_WITH_D1_DATABASE_ID/${{ vars.EMAIL_WORKER_D1_ID }}/g" \ -e "s/REPLACE_WITH_KV_NAMESPACE_ID/${{ vars.INBOX_WORKER_KV_ID }}/g" \ wrangler.example.jsonc > wrangler.jsonc - Apply D1 migrations
pnpm run migrations:apply - Deploy worker
npx wrangler deploy
Deploy bridges · no job dependencies declared
Condition: ${{ github.event.inputs.target == 'cf-worker' || github.event.inputs.target == 'all' }}
- actions/checkout@v4
actions/checkout@v4 - Enable Corepack
corepack enable - actions/setup-node@v4
actions/setup-node@v4 - Install workspace dependencies
pnpm install --frozen-lockfile - Deploy bridge
npx wrangler deploy
Triggers: push
Check emailflare-api Dockerfile · no job dependencies declared
- actions/checkout@v4
actions/checkout@v4 - docker/setup-buildx-action@v3
docker/setup-buildx-action@v3 - Build (no push)
docker/build-push-action@v6
Check emailflare-inbox Dockerfile · no job dependencies declared
- actions/checkout@v4
actions/checkout@v4 - docker/setup-buildx-action@v3
docker/setup-buildx-action@v3 - Build (no push)
docker/build-push-action@v6
Verify ${{ matrix.name }} · no job dependencies declared
- actions/checkout@v4
actions/checkout@v4 - Enable Corepack
corepack enable - actions/setup-node@v4
actions/setup-node@v4 - Install workspace dependencies
pnpm install --frozen-lockfile - Build shared packages
pnpm run build:shared - Check (${{ matrix.check }})
${{ matrix.check }} - Audit dependencies
pnpm audit --audit-level=high
Triggers: push, workflow_dispatch
Verify API · ${{ matrix.name }} · no job dependencies declared
- actions/checkout@v4
actions/checkout@v4 - Enable Corepack
corepack enable - actions/setup-node@v4
actions/setup-node@v4 - Install workspace dependencies
pnpm install --frozen-lockfile - Build shared packages
pnpm run build:shared - Build
pnpm run build - Audit dependencies
pnpm audit --audit-level=high
Verify Inbox · ${{ matrix.name }} · no job dependencies declared
- actions/checkout@v4
actions/checkout@v4 - Enable Corepack
corepack enable - actions/setup-node@v4
actions/setup-node@v4 - Install workspace dependencies
pnpm install --frozen-lockfile - Build shared packages
pnpm run build:shared - Build
pnpm run build - Audit dependencies
pnpm audit --audit-level=high
Build emailflare-api image · after verify-api
- actions/checkout@v4
actions/checkout@v4 - Resolve image name
if [[ "${{ github.ref_name }}" =~ ^s[0-9] ]]; then echo "image=${{ env.REGISTRY }}/${{ github.repository_owner }}/emailflare-api-staging" >> $GITHUB_OUTPUT echo "is_staging=true" >> $GITHUB_OUTPUT else echo "image=${{ env.REGISTRY }}/${{ github.repository_owner }}/emailflare-api" >> $GITHUB_OUTPUT echo "is_staging=false" >> $GITHUB_OUTPUT fi - docker/setup-qemu-action@v3
docker/setup-qemu-action@v3 - docker/setup-buildx-action@v3
docker/setup-buildx-action@v3 - Log in to GitHub Container Registry
docker/login-action@v3Condition: github.event_name != 'pull_request' - Extract Docker metadata
docker/metadata-action@v5 - Build and push
docker/build-push-action@v6
Build emailflare-inbox image · after verify-inbox
- actions/checkout@v4
actions/checkout@v4 - Resolve image name
if [[ "${{ github.ref_name }}" =~ ^s[0-9] ]]; then echo "image=${{ env.REGISTRY }}/${{ github.repository_owner }}/emailflare-inbox-staging" >> $GITHUB_OUTPUT echo "is_staging=true" >> $GITHUB_OUTPUT else echo "image=${{ env.REGISTRY }}/${{ github.repository_owner }}/emailflare-inbox" >> $GITHUB_OUTPUT echo "is_staging=false" >> $GITHUB_OUTPUT fi - docker/setup-qemu-action@v3
docker/setup-qemu-action@v3 - docker/setup-buildx-action@v3
docker/setup-buildx-action@v3 - Log in to GitHub Container Registry
docker/login-action@v3Condition: github.event_name != 'pull_request' - Extract Docker metadata
docker/metadata-action@v5 - Build and push
docker/build-push-action@v6
build:email-core: pnpm --filter @emailflare/email-core buildbuild:inbox-core: pnpm --filter @emailflare/inbox-core buildbuild:emails: pnpm --filter @emailflare/emails buildbuild:shared: pnpm run build:email-core && pnpm run build:inbox-core && pnpm run build:emailsbuild:email-server: pnpm --filter @emailflare/email-server buildbuild:inbox-server: pnpm --filter @emailflare/inbox-server buildbuild:email-ui: pnpm --filter @emailflare/email-ui buildbuild:inbox-ui: pnpm --filter @emailflare/inbox-ui build
build: tsc
build: tsc
deploy: wrangler deploy
build: tsc
build: vite build && tsc --noEmit
deploy: wrangler deploymigrations:apply:local: wrangler d1 migrations apply emailflare --localmigrations:apply: wrangler d1 migrations apply emailflare --remote
build: tsc
deploy: wrangler deploy
build: tscmigrate: node dist/migrate.js
build: vite build && tsc --noEmit
deploy: wrangler deploymigrations:apply:local: wrangler d1 migrations apply emailflare --localmigrations:apply: wrangler d1 migrations apply emailflare --remotebuild:packages: pnpm --filter @emailflare/email-core build && pnpm --filter @emailflare/inbox-core buildbuild:ui: pnpm --filter @emailflare/inbox-ui builddeploy:full: pnpm run build:packages && pnpm run build:ui && wrangler d1 migrations apply emailflare --remote && wrangler deploy
build: astro builddeploy: pnpm build && wrangler deploy
Repository README
View original on GitHub ↗Full upstream document by @0xdps · README.md · snapshot d448ea2
EmailFlare
EmailFlare is a Cloudflare-native email platform with two independent services that work together:
- emailflare-api — transactional email sending API with an admin dashboard (domains, templates, API keys, logs, suppressions, lists + one-click unsubscribe)
- emailflare-inbox — team inbox and lightweight CRM (receive, thread, reply, sequences, multi-user, lists + one-click unsubscribe)
Both services are built on Cloudflare — Email Sending, Email Routing, D1, KV, R2, Queues, and Durable Objects — and deploy as Cloudflare Workers (primary, zero-ops) or as a single Docker container with embedded SQLite (secondary, for self-hosting).
emailflare-api · Email Sending API
A Hono API for sending transactional email via the Cloudflare Email Sending API, with a React admin panel for managing domains, templates, API keys, and logs.
Cloudflare Worker deployment (primary — no Docker, edge-native)
just install
cp scripts/config.example.toml scripts/config.toml
# fill in your values
just emailflare-api-worker-setup
Read the full guide: docs/CLOUDFLARE.md
Docker self-host (secondary)
gcr.io/0xdps/emailflare-api:latest
cp .env.api.example .env.local
# fill in SESSION_SECRET, ADMIN_TOKEN, CF_API_TOKEN, CF_ACCOUNT_ID
docker compose --env-file .env.local -f deploy/docker/compose.email-api.yaml up -d
Open http://localhost:8090. Read the full guide: docs/SELF_HOSTING.md
Railway
emailflare-inbox · Team Inbox & CRM
A Node.js inbox server with a React dashboard for receiving inbound email via Cloudflare Email Routing, threading conversations, replying, running sequences, and managing contacts across a team.
Cloudflare Worker deployment (primary — inbox-worker, D1 + R2 + KV + DO + Queues)
just install
cp scripts/config.example.toml scripts/config.toml
# fill in your values
just emailflare-inbox-deploy
Read the full guide: docs/CLOUDFLARE.md
Docker self-host (secondary)
ghcr.io/0xdps/emailflare-inbox:latest
cp .env.inbox.example .env.inbox.local
# fill in SESSION_SECRET, WEBHOOK_SECRET, CF_API_TOKEN, CF_ACCOUNT_ID, REDIS_URL
docker compose --env-file .env.inbox.local -f deploy/docker/compose.email-inbox.yaml up -d
Open http://localhost:8091. Read the full guide: docs/SELF_HOSTING.md
What ships in this repo
Email API
services/email-worker— Cloudflare Worker bundling API + admin UI (D1 + KV) — primary deployservices/email-server— Hono API (Node.js): domains, templates, keys, stats, send — for Dockerservices/email-ui— React admin panel (Vite + TanStack Router)services/email-bridge— CF Worker: receives bounce/complaint email and forwards to email-server webhookdeploy/docker/Dockerfile.email-api— production image for emailflare-apideploy/docker/compose.email-api.yaml— single-container production composedeploy/docker/compose.email-api.dev.yaml— local dev stack with hot reload
Inbox
services/inbox-worker— Cloudflare Worker variant of the inbox (D1 + R2 + KV + DO + Queues) — primary deployservices/inbox-server— Hono inbox API (Node.js): inboxes, people, threads, sequences, templates — for Dockerservices/inbox-ui— React inbox dashboard (Vite + TanStack Router)services/inbox-bridge— CF Worker: receives inbound email via CF Email Routing, forwards to inbox-serverdeploy/docker/Dockerfile.email-inbox— production image for emailflare-inboxdeploy/docker/compose.email-inbox.yaml— single-container production composedeploy/docker/compose.email-inbox.dev.yaml— local dev stack with hot reload
Shared
services/emails— shared email layouts and rendering used by both serversscripts/— setup tooling for CF Worker deployments (setup.mjs,config.example.toml)justfile— task runner for dev, prod, and Cloudflare Worker operations (docs/RECIPES.md)docs/CLOUDFLARE.md— Cloudflare Workers deployment guide (primary)docs/SELF_HOSTING.md— Docker self-hosting guide (secondary)
Deployment modes
EmailFlare supports two deployment modes for each product:
| Mode | Products | Stack | When to use |
|---|---|---|---|
| Cloudflare Workers (primary) | emailflare-api, emailflare-inbox | D1 + KV (+ R2, Queues, DO for inbox) | Default — zero-ops, edge-native |
| Docker (secondary) | emailflare-api, emailflare-inbox | single container + embedded SQLite | Self-hosting on your own VPS/VM |
The Docker path uses SQLite via embedded mesahub-core (one image, one volume at /data).
Read the full guides: docs/CLOUDFLARE.md · docs/SELF_HOSTING.md
Minimum required environment
emailflare-api (.env.local):
| Variable | Description |
|---|---|
ADMIN_TOKEN |
Admin API token (32+ chars) |
SESSION_SECRET |
Session signing secret (32+ chars) |
MESAHUB_URL |
mh://local/emailflare for embedded SQLite |
CF_API_TOKEN |
Cloudflare token with Email Sending + Zone permissions |
CF_ACCOUNT_ID |
Cloudflare account ID |
PUBLIC_URL |
Public base URL, used for one-click unsubscribe links (optional) |
emailflare-inbox (.env.inbox.local):
| Variable | Description |
|---|---|
SESSION_SECRET |
Session signing secret (32+ chars) |
WEBHOOK_SECRET |
Shared secret for inbox-bridge webhook auth |
MESAHUB_URL |
mh://local/inbox-db for embedded SQLite |
REDIS_URL |
Redis connection string (rate limiting + BullMQ) |
CF_API_TOKEN |
Cloudflare token for sending replies |
CF_ACCOUNT_ID |
Cloudflare account ID |
PUBLIC_URL |
Public base URL, used for one-click unsubscribe links in sequences (optional) |
Open source
- License: MIT
- Contributing guide: CONTRIBUTING.md
- Security policy: SECURITY.md
Frequently asked about EmailFlare
What is EmailFlare?+
EmailFlare is a self-hosted Postmark/Resend alternative built on the Cloudflare developer platform. Run transactional email APIs and a team inbox on Cloudflare Workers.
What does EmailFlare replace?+
EmailFlare is listed as an alternative to Postmark, Resend. Compare the features and tradeoffs before migrating.
What Cloudflare primitives does EmailFlare use?+
EmailFlare is built on D1, Durable Objects, Email Workers, KV, Queues, R2, Workers.
How much does EmailFlare cost to run?+
EmailFlare has a documented low-volume paid Cloudflare path beginning with Workers Paid ($5 USD/account/month), with separately metered usage. Arbitrary-recipient email requires Paid; database, storage and email usage above included allowances add charges. Use Workers Paid for arbitrary-recipient email, starting at $5 USD/account/month; 3,000 outbound emails/month are included, then $0.35 per 1,000. Workers Paid starts at $5 USD/account/month and includes 10 million requests/month plus 30 million CPU milliseconds/month; higher CPU limits do not make execution unmetered. Workers Paid D1 includes 25 billion rows read/month, 50 million written/month and 5 GB storage; database usage above those amounts is metered. Workers Paid KV includes 10 million reads/month, 1 million writes, deletes and lists/month each, plus 1 GB; additional usage is metered. Use R2 Standard storage, at most 10 GB-month, 1 million Class A operations and 10 million Class B operations/month; provision an eligible billing-enabled R2 account. Paid SQLite Durable Objects include 1 million requests/month, 400,000 GB-s duration/month and 5 GB-month SQL storage; active duration and excess database operations are metered. Workers Paid Queues includes 1 million operations/month; count writes, reads, deletes, retries and each 64 KB chunk, with usage above the allowance metered. Workers Paid Email Service includes 3,000 outbound emails/account/month, then $0.35 per 1,000; inbound Email Routing remains unmetered apart from Worker processing. Use a small personal or team workload; domain registration and optional third-party providers are separate costs. Provision your own IDs, secrets and migrations. Check current Cloudflare pricing before deploying.
Is EmailFlare open source?+
The upstream repository declares the MIT license. Read its terms at https://raw.githubusercontent.com/0xdps/emailflare/d448ea205937a5e82683f89013d4c23159da5b7d/LICENSE. Source code and contributor credit are available at https://github.com/0xdps/emailflare.


Discussion · 0
sign in to comment →