Simple Inbox

Deployment

Deploy one Worker, complete first-run setup, and activate Cloudflare mail services safely.

Simple Inbox deploys as simple-inbox-cf. The root wrangler.jsonc declares its D1 database simple-inbox-cf-db, private R2 bucket simple-inbox-cf-raw, Email Sending and rate-limit bindings, and daily retention cron. Wrangler provisions D1/R2 when needed; you do not copy resource IDs into the repository.

Deployment never changes DNS, custom domains, or Email Routing, and never reads or mutates a legacy Inbox installation.

Prerequisites

  • A Cloudflare account with Workers, D1, R2, and Email Routing.
  • Email Routing enabled on the intended new mail zone and at least one owner-controlled destination verified before deployment; Cloudflare requires both before attaching the EMAIL binding.
  • Workers Paid and an onboarded Email Sending domain before testing full compose/reply delivery to arbitrary recipients.
  • Wrangler authenticated to the intended account.
  • The repository's pinned Node, pnpm, and Vite+ versions.
  • Two different secret values of at least 32 random bytes.
  • An owner-controlled mail domain/subdomain and allowlisted test destination.
  • An approved raw/application retention policy.

Verify locally

vp install --frozen-lockfile
vp run check:generated
vp run check
vp run test:boundaries
vp test
vp run build
vp run test:integration
vp exec playwright install chromium
vp run test:e2e
vp exec wrangler whoami

The test harness uses local D1/R2 and simulated Email Sending. It sends no real mail.

The upload runs Wrangler non-interactively to keep provisioned IDs out of source. If whoami lists multiple accounts, set CLOUDFLARE_ACCOUNT_ID for the current shell or CI project only; never add it to the repository.

Deploy manually

For the first manual deployment, after confirming Wrangler's account, run:

vp run deploy:first

This command is immediately remote and state-changing. It builds and deploys the fail-closed Worker so Wrangler can provision D1/R2, then applies the checked-in migrations. Once migration completes, the app is ready for /setup without another upload.

For later upgrades, run:

vp run deploy

The upgrade command:

  1. builds the TanStack Start Worker;
  2. applies checked-in D1 migrations remotely;
  3. deploys the generated apps/web/dist/server/wrangler.json with CI=1, preventing Wrangler from writing an auto-provisioned D1 ID back into tracked source configuration.

Deploy to Cloudflare provisions resources before invoking the regular deploy script, so its one-click flow also follows the migration-before-upload sequence. There is no separate provision, bootstrap, dry-run, or multi-Worker deploy script. Do not deploy a stale generated config or generate migrations during deployment.

Configure secrets

The Deploy to Cloudflare flow prompts for both values. For a manual deployment, add them through the Worker's Cloudflare Dashboard settings or Wrangler's interactive prompts:

vp exec wrangler secret put AUTH_TOKEN_PEPPER --config wrangler.jsonc
vp exec wrangler secret put SETUP_TOKEN --config wrangler.jsonc

AUTH_TOKEN_PEPPER protects magic-link, session, and API-token digests. Rotating it invalidates those outstanding credentials. SETUP_TOKEN authorizes installation setup and must be independently generated. Never pass either plaintext value in command arguments or store it in the repository.

Choose the origin and finish setup

Setup stores the origin from its verified same-origin HTTPS request. Before opening /setup, either keep the generated workers.dev origin or manually attach the intended custom domain. Do not finish setup on one origin and silently move to another later.

At /setup, enter the setup token and installation values. Synthetic examples are:

  • owner: owner@example.test
  • mail domain: mail.example.test
  • inbox: inbox@mail.example.test
  • raw retention: 30 days
  • application-record retention: 90 days
  • batch size: 100

Raw retention must be 1–3,650 days, application retention must be at least as long and no more than 3,650 days, and the batch must be 1–100.

One D1 transaction creates the owner, primary mailbox, sole owner membership, canonical app origin, mail domain, and retention settings. Exact replay is idempotent; conflicting or partial state fails closed. The setup token is never stored, returned, or logged.

Before setup completes, inbound mail is rejected, the scheduled job is idle, and protected API routes return unavailable.

Dashboard-only mail and lifecycle setup

These owner actions are not part of deployment:

  1. Onboard the Email Sending domain and verify SPF/DKIM.
  2. Verify only owner-controlled test destinations; keep arbitrary sending disabled until reviewed.
  3. Confirm the Worker's EMAIL binding can deliver a magic link and synthetic outbound mail.
  4. Keep simple-inbox-cf-raw private with no r2.dev URL/custom domain.
  5. Add an R2 lifecycle rule at approved raw retention plus a short grace, such as two days.
  6. Only after setup and outbound validation, add a test-domain Email Routing rule/catch-all targeting simple-inbox-cf's email() handler.
  7. Do not modify an existing legacy mail rule as part of this process.

Acceptance

Check public pages and metadata, then perform owner-only live validation with uniquely identifiable synthetic content:

  • request, consume, and attempt to reuse a magic link;
  • capture one inbound message in D1 and private R2;
  • verify forwarding and a reply round trip;
  • round-trip a small non-sensitive attachment and authorize its download;
  • confirm repeated outbound idempotency keys do not duplicate delivery;
  • confirm public /internal/* probes return 404;
  • correlate safe request IDs without recording addresses, bodies, tokens, or R2 keys;
  • confirm no legacy resource or route changed.

There is no automated live-smoke command. Real mail and route changes require the owner's explicit approval.

Future Deploy to Cloudflare button

Once the source repository is public:

Deploy Simple Inbox to Cloudflare

Cloudflare can clone the repository, prompt for described secrets, run the custom deploy command, and provision supported resources. Private repositories do not work for other deploy-button users, so this link is future guidance until the repository is public. See Cloudflare's deploy-button documentation.

Upgrades and rollback

For upgrades, back up D1 when the migration warrants it, run the full local suite, and run vp run deploy. Pending migrations are applied before the new code is uploaded; setup and secrets are not recreated.

Preserve the Worker version and change record. A Worker rollback restores code only: it does not undo D1 migrations or restore deleted D1/R2 data. Custom-domain and Email Routing rollback are manual. Keep replacement storage intact for investigation, and never expect captured mail to merge automatically into another store.

On this page