QuickInbox is another useful stop in this Cloudflare email run.
It sits between the projects we just covered:
Agentic Inbox -> Cloudflare AI email demo
Mailflare -> broader webmail/workspace with Docker option
SaaSMail -> SaaS customer timelines and sequences
QuickInbox -> practical custom-domain inbox on Workers
The interesting part is the provider choice.
QuickInbox can receive and send mail through Resend, or it can use Cloudflare Email Service directly if your domain is on Cloudflare DNS and you have the right Workers plan.
That makes it more flexible than a Cloudflare-only email demo, but still not a Docker homelab mail server.
What Is QuickInbox?
QuickInbox describes itself as:
Self-hosted email for your own domain, running on Cloudflare Workers. Get
[email protected]with a full web client - no third-party mailbox, no servers to maintain.
I inspected:
repo: https://github.com/DivinPrince/quickinbox
commit: 2d2c7d62f250f122ad73296c840d60e775a9a599
version: 1.0.0
license: MIT
One small naming note: the config still uses quickmail in places.
The README explains why. Existing installs were renamed in the UI/docs, but the Worker, D1 database, R2 bucket, and old API key prefix may remain quickmail / quickmail-attachments / qm_live_.
That is normal for this repo.
What You Get
From the README and source inspection, QuickInbox includes:
- custom-domain email inbox;
- inbound and outbound mail;
- threaded conversations;
- attachments stored in R2;
- sandboxed HTML rendering for received mail;
- multiple domains and users;
- per-user addresses;
- admin catch-all and unrouted-mail view;
- combined inbox with address filtering;
- delivery status tracking when using Resend events;
- REST API keys;
- CLI access;
- hosted MCP with OAuth;
- local stdio MCP through the CLI;
- inbox tabs: Primary, Social, Promotions, Updates, Forums;
- spam mailbox;
- custom labels;
- light and dark themes;
- PWA manifest and service worker;
- desktop push notifications;
- optional Telegram notifications;
- English, French, Simplified Chinese, and Spanish UI strings.
This is not a campaign tool like SaaSMail.
It is a custom-domain inbox with automation hooks.
Stack
The current stack is:
| Layer | QuickInbox uses |
|---|---|
| Frontend / app | SvelteKit, Svelte 5, Tailwind CSS 4 |
| Runtime | Cloudflare Workers |
| Build | Vite 8, Bun scripts, SvelteKit Cloudflare adapter |
| Database | Cloudflare D1 |
| Attachments | Cloudflare R2 |
| Outbound email | Resend API or Cloudflare Email Service |
| Inbound email | Resend webhook or Cloudflare Email Routing Worker handler |
| MIME parsing | postal-mime |
| API / MCP schemas | Zod |
| CLI | quickinbox / quickmail command |
| MCP | Hosted Streamable HTTP MCP plus local stdio MCP |
| Optional classification | TypeSafe API |
| Optional notifications | Web Push and Telegram Bot API |
The key deployment config is in wrangler.jsonc:
{
"name": "quickmail",
"main": ".svelte-kit/cloudflare/_worker.js",
"vars": {
"EMAIL_PROVIDER": "resend",
"CLOUDFLARE_MAIL_DOMAINS": "example.com"
},
"send_email": [{ "name": "EMAIL", "remote": true }],
"d1_databases": [
{
"binding": "DB",
"database_name": "quickmail",
"database_id": "REPLACE_WITH_YOUR_D1_DATABASE_ID"
}
],
"r2_buckets": [
{
"binding": "ATTACHMENTS",
"bucket_name": "quickmail-attachments"
}
]
}
The implementation detail I like: SvelteKit’s generated Worker is fetch-only, so QuickInbox wraps it after build to add Cloudflare’s email() handler.
That keeps the web app in SvelteKit while still receiving native Cloudflare inbound mail.
Provider Tracks
QuickInbox has two supported provider tracks.
| Track | Inbound | Outbound | DNS | Notes |
|---|---|---|---|---|
| Resend | Webhook to /api/webhooks/resend |
Resend REST API | Any DNS host | Better if your DNS is not on Cloudflare or you already use Resend. |
| Cloudflare Email | Worker email() handler |
env.EMAIL.send() |
Cloudflare DNS required | Better if the whole domain already lives in Cloudflare. |
Only one provider is active per deploy:
EMAIL_PROVIDER=resend
EMAIL_PROVIDER=cloudflare
The README is explicit: do not point the same domain’s apex MX at both providers.
That matters.
Email delivery is DNS-driven. If two systems think they own inbound mail for the same domain, debugging becomes miserable.
Cloudflare Dependency Map
Even with the Resend track, QuickInbox is still a Cloudflare Worker app.
| Cloudflare service | Required? | What QuickInbox uses it for |
|---|---|---|
| Workers | Yes | Runs the SvelteKit app, API routes, webhook routes, MCP endpoint, and Cloudflare email() handler. |
| D1 | Yes | Stores users, sessions, mail metadata, domains, addresses, labels, OAuth grants, API tokens, and settings. |
| R2 | Yes | Stores inbound and outbound attachments. |
| Workers Assets | Yes | Serves SvelteKit build output. |
| Email Routing | Only for Cloudflare Email track | Delivers inbound mail to the Worker email() handler. |
| Email Sending | Only for Cloudflare Email track | Sends outbound mail through the EMAIL binding. |
| Custom domain / DNS | Practical requirement | Gives you real addresses like [email protected]. |
There is no Docker Compose path in the repo.
That is not an omission in this post. It is the architecture.
Self-Hosting QuickInbox
You can deploy it with the Cloudflare button, or run the setup wizard:
bun run setup
If Bun is not installed, the repo ships:
bash scripts/setup.sh
The wizard creates the D1 database and R2 bucket, writes config, and helps onboard the domain.
Manual setup looks like:
bun install
bunx wrangler login
bunx wrangler d1 create quickmail
bunx wrangler r2 bucket create quickmail-attachments
bun run db:migrate:remote
Then choose one provider.
Resend Track
Use this when DNS is elsewhere, or you prefer Resend’s API and event model.
High-level steps:
- Verify the domain in Resend.
- Add the DNS records Resend shows, including the apex MX.
- Enable sending and receiving for the domain.
- Set the full-access key:
bunx wrangler secret put RESEND_API_KEY
- Deploy:
bun run deploy
- Add a Resend webhook pointing to:
https://<your-worker-url>/api/webhooks/resend
- Include events such as
email.received,email.sent,email.delivered,email.bounced,email.complained,email.delivery_delayed, andemail.failed. - Set the webhook signing secret:
bunx wrangler secret put RESEND_WEBHOOK_SECRET
bun run deploy
Cloudflare Email Track
Use this when the domain is already on Cloudflare DNS and you want the mail stack inside Cloudflare.
High-level steps:
- Enable Cloudflare Email Sending.
- Enable Cloudflare Email Routing.
- Configure catch-all routing to send inbound mail to the QuickInbox Worker.
- Set:
"vars": {
"EMAIL_PROVIDER": "cloudflare",
"CLOUDFLARE_MAIL_DOMAINS": "yourdomain.com"
}
- Deploy:
bun run deploy
Inbound Cloudflare Email does not work through plain vite dev. You need a deployed Worker or bun run preview because the email() handler is a Worker runtime feature.
API, CLI, and MCP
QuickInbox has a practical automation surface.
Any user can create API keys in Settings. Keys are stored as hashes and start with:
qi_live_
Older keys may start with:
qm_live_
Both are expected after the rename.
Example send:
curl https://your-worker/api/mail \
-H "Authorization: Bearer qi_live_..." \
-H "Content-Type: application/json" \
-d '{"to": "[email protected]", "subject": "hello", "text": "hi"}'
The CLI installs as:
curl -fsSL https://raw.githubusercontent.com/DivinPrince/quickinbox/main/scripts/install.sh | sh
Then:
quickinbox login --url https://mail.example.com --token qi_live_...
quickinbox inbox
quickinbox send --to [email protected] --subject "Hi" --body "Hello"
Hosted MCP lives at:
https://mail.example.com/mcp
It uses OAuth 2.1, dynamic client registration, PKCE, refresh-token rotation, and revocation. Clients such as Claude, Cursor, or ChatGPT can connect through the browser consent flow.
The local CLI can also run a stdio MCP server:
{
"mcpServers": {
"quickinbox": {
"command": "quickinbox",
"args": ["mcp"],
"env": {
"QUICKINBOX_URL": "https://mail.example.com",
"QUICKINBOX_TOKEN": "qi_live_..."
}
}
}
}
PWA Details
QuickInbox ships a real PWA manifest:
static/manifest.webmanifest
The manifest sets:
name: Quickinbox
start_url: /inbox
display: standalone
orientation: portrait-primary
categories: productivity
shortcuts: Inbox and Compose
It also has:
src/service-worker.ts
The service worker handles:
- install and activation;
- push events;
- notification clicks;
- forwarding
mail:changedmessages to open tabs; - opening the right inbox URL when a notification is clicked;
- checking that the current account owns the push subscription before showing mail content.
That last point is important for a multi-account inbox. A push notification should not leak one account’s mail into another logged-in browser session.
This does not make QuickInbox statically deployable.
The frontend is a SvelteKit app, but the useful product depends on Worker routes, D1, R2, provider secrets, webhooks, and email handlers.
Optional Add-Ons
QuickInbox has three notable optional integrations.
Desktop Push
Generate VAPID keys:
bunx web-push generate-vapid-keys
Set:
bunx wrangler secret put VAPID_PUBLIC_KEY
bunx wrangler secret put VAPID_PRIVATE_KEY
bunx wrangler secret put VAPID_SUBJECT
Users opt in from Settings.
Telegram Notifications
Set:
bunx wrangler secret put TELEGRAM_BOT_TOKEN
bunx wrangler secret put TELEGRAM_CHAT_ID
Optional:
bunx wrangler secret put TELEGRAM_THREAD_ID
APP_URL is useful so notification messages can link back to the inbox.
Inbox Tabs
Set:
bunx wrangler secret put TYPESAFE_API_KEY
Without it, everything lands in Primary.
With it, inbound mail can be classified into Primary, Social, Promotions, Updates, Forums, and spam. Promotions and Social do not send push/Telegram notifications, and high-confidence spam is filed silently.
Field Note: Local Build Trial
I tried a bounded local build in a temporary clone.
Environment:
bun: 1.2.16
node: v18.19.1
npm: 9.2.0
Commands:
bun install
bun run build
bun run test
bun install installed dependencies, but the prepare hook hit:
File is not defined
from the SvelteKit/Undici path.
The build then failed with:
You are using Node.js 18.19.1.
Vite requires Node.js version 20.19+ or 22.12+.
ReferenceError: CustomEvent is not defined
The test run started, but failed because svelte-kit sync had not completed and $lib/... aliases were missing.
My practical note: use Node 20.19+ or Node 22+ for local development, even though Bun is the command runner. Do not judge the app from a Node 18 build failure.
I did not create a Home-Lab Docker Compose file because the repository does not provide a container-native deployment path.
How It Compares
| Project | Best fit | Deployment shape |
|---|---|---|
| Agentic Inbox | Studying Cloudflare AI email, Workers AI, Access, and MCP | Cloudflare-native |
| Mailflare | Broader custom-domain webmail/workspace, especially if Docker matters | Cloudflare or Docker |
| SaaSMail | SaaS customer timelines, templates, suppressions, and email sequences | Cloudflare-native |
| QuickInbox | Custom-domain inbox with Resend/Cloudflare provider choice, CLI, PWA, API, and MCP | Cloudflare-native |
QuickInbox is less campaign-oriented than SaaSMail.
It is less Docker-friendly than Mailflare.
It is more practical as a normal inbox than Agentic Inbox.
FAQ
Is QuickInbox self-hosted?
Yes, but in the Cloudflare-native sense.
You deploy it into your own Cloudflare account, with your own D1 database, R2 bucket, secrets, Worker, domain, and email provider setup.
It is not a local Docker mail server.
Is there a Docker Compose setup?
No official Docker Compose path exists in the inspected repository.
The app depends on Cloudflare Workers, D1, R2, and either Resend webhooks or Cloudflare Email Service. A normal Compose file would need a different runtime layer, a different database layer, a different object storage layer, and a different inbound mail path.
For Docker/homelab email, compare it with Mailflare instead.
Do I need Cloudflare Email Service?
Not necessarily.
You have two tracks:
- Resend track: DNS can be hosted anywhere, inbound comes through Resend webhooks, outbound uses the Resend API.
- Cloudflare Email track: the domain must be on Cloudflare DNS, inbound uses Email Routing to the Worker, outbound uses Cloudflare Email Sending.
If your domain is already on Cloudflare and you pay for Workers, the Cloudflare track is tidy. If DNS is elsewhere or you already use Resend, the Resend track may be easier.
Can QuickInbox be deployed as a static SvelteKit site?
No, not with full functionality.
The browser UI is SvelteKit, but the app needs Worker runtime APIs, D1, R2, provider secrets, webhook routes, API routes, MCP routes, and Cloudflare’s email() handler for the Cloudflare provider track.
A static site would not receive mail, send mail, store mailbox state, or run MCP/API functionality.
Is QuickInbox a PWA?
Yes.
It includes a web manifest, install icons, shortcuts for Inbox and Compose, and a service worker for push notifications and notification-click handling.
The PWA layer improves the browser/mobile experience, but the backend still requires Workers, D1, R2, and provider configuration.
Does QuickInbox support MCP?
Yes.
It has hosted MCP at /mcp with OAuth 2.1 and browser consent, plus a local stdio MCP server through the quickinbox mcp CLI.
Hosted tools include reading threads, searching mail, listing attachments, sending messages, replying, and updating thread state. Read-only clients only receive read tools.
How does QuickInbox compare with the other Cloudflare email posts?
The short chooser is:
| Project | Pick it when… | Main tradeoff |
|---|---|---|
| Agentic Inbox | ||
| You want to study Cloudflare’s AI email primitives: Workers, Durable Objects, R2, Workers AI, Access, and MCP. | It is more of a Cloudflare reference/demo than a normal personal inbox product. | |
| Mailflare | ||
| You want the broadest custom-domain webmail/workspace and may want Docker/SQLite/local files instead of only Cloudflare. | The Docker path brings more traditional ops work; the Cloudflare path is broader but heavier. | |
| SaaSMail | ||
| You want SaaS customer communication: timelines, templates, sequences, suppressions, and one-click unsubscribe. | It is not a general mailbox replacement and is not Docker-native. | |
| QuickInbox | You want a practical custom-domain inbox on Cloudflare with Resend-or-Cloudflare provider choice, REST API, CLI, PWA, and MCP. | It is Cloudflare-native only and has no local Docker Compose deployment. |
So:
- Use QuickInbox for a personal/small-team custom-domain inbox with automation hooks.
- Use Mailflare if Docker/homelab portability matters most.
- Use SaaSMail if sequences and customer lifecycle messaging matter most.
- Use Agentic Inbox if you are studying Cloudflare AI/MCP architecture rather than choosing a production mailbox.
Is QuickInbox good for transactional, marketing, or cold outbound?
QuickInbox is best understood as a mailbox and automation surface, not a campaign platform.
It can send programmatic mail through the REST API, CLI, or MCP, so light transactional use is possible if your provider and domain reputation are configured correctly.
It is not a newsletter platform like Listmonk, not a SaaS lifecycle sequencing tool like SaaSMail, and not a cold-outbound platform like Smartlead or Instantly.
Do not use your primary inbox domain for cold outreach.
What should I back up?
Back up both D1 and R2.
D1 holds users, sessions, mailbox metadata, message metadata, domains, addresses, labels, API token hashes, OAuth records, and settings.
R2 holds attachments.
Also keep private notes for wrangler.jsonc, Cloudflare resource IDs, DNS records, provider webhooks, and which secrets you set. Do not commit real .dev.vars values.
Conclusion
QuickInbox is a clean example of custom-domain email built for the Cloudflare edge.
It is not the broadest inbox suite, and it is not a Docker homelab app.
But it has a strong practical surface: Resend or Cloudflare provider choice, D1/R2 storage, PWA behavior, API keys, CLI access, hosted OAuth MCP, local MCP, and optional push/Telegram/classification integrations.
If you want a Cloudflare-native personal or small-team custom-domain inbox, this is worth watching.
If you need Docker portability, Mailflare is the better comparison point.
If you need sequences and SaaS lifecycle messaging, SaaSMail is the closer fit.
Comments