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:

  1. Verify the domain in Resend.
  2. Add the DNS records Resend shows, including the apex MX.
  3. Enable sending and receiving for the domain.
  4. Set the full-access key:
bunx wrangler secret put RESEND_API_KEY
  1. Deploy:
bun run deploy
  1. Add a Resend webhook pointing to:
https://<your-worker-url>/api/webhooks/resend
  1. Include events such as email.received, email.sent, email.delivered, email.bounced, email.complained, email.delivery_delayed, and email.failed.
  2. 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:

  1. Enable Cloudflare Email Sending.
  2. Enable Cloudflare Email Routing.
  3. Configure catch-all routing to send inbound mail to the QuickInbox Worker.
  4. Set:
"vars": {
  "EMAIL_PROVIDER": "cloudflare",
  "CLOUDFLARE_MAIL_DOMAINS": "yourdomain.com"
}
  1. 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:changed messages 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

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.