mirror of
https://github.com/ananthb/cutout.git
synced 2026-09-20 16:26:51 +00:00
Transparent email alias proxy built on Cloudflare Workers
- Rust 98.8%
- Nix 0.9%
- JavaScript 0.3%
worker crate is on 0.7 in Cargo.toml; latest worker-build (0.8.x) demands worker >= 0.8.1. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .github/workflows | ||
| doc | ||
| migrations | ||
| src | ||
| .envrc | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| DEPLOY.md | ||
| flake.lock | ||
| flake.nix | ||
| garnix.yaml | ||
| LICENSE | ||
| package.json | ||
| README.md | ||
| rust-toolchain.toml | ||
| worker-shim.mjs | ||
| wrangler.local.toml | ||
| wrangler.toml | ||
Cutout
Transparent email alias proxy: similar to SimpleLogin or addy.io, built entirely on Cloudflare Workers. No servers, no containers, no monthly VM bills.
How it works
- You own one or more domains with Cloudflare Email Routing (inbound) and Email Service (outbound)
- Someone emails
anything@yourdomain.com - Cutout worker is triggered, matches the recipient against your rules, and forwards the email to your real address
- For email destinations:
- Native mode uses CF's native
EmailMessage.forward(); original bytes (PGP, attachments) pass through untouched. - Proxy mode reconstructs the email via
send_emailto ensureReply-Toworks reliably when replying via the same domain (strips signatures/attachments). Both modes inject anX-Original-Fromheader for permanent archival in your inbox.
- Native mode uses CF's native
- For Telegram/Discord destinations: the bot posts the content to the chat and stores a reply context in KV. Replies in the chat (Telegram's native reply, Discord's "Reply" button → modal) route back to the original sender via email
- Destinations depend on your secrets: Telegram and Discord only appear in the UI when their bot tokens are configured
Getting Started
See the Deploy guide for step-by-step instructions on forking and deploying your own instance of Cutout to Cloudflare.
CI/CD is handled by Cloudflare Builds (Workers CI), which builds and deploys directly from this repo without needing GitHub Actions or Nix.
To wire up your fork:
- In the Cloudflare dashboard, create a Worker named (e.g.)
cutoutand connect this repo under Settings → Builds.- Build command: leave default (CF Builds runs
npm installfrompackage.json) - Deploy command:
npm run deploy(defined inpackage.json— installsworker-build, applies pending D1 migrations, then runswrangler deploy)
- Build command: leave default (CF Builds runs
- Bind a D1 database (
DB), KV namespace (KV), R2 bucket (EMAILS), Queues (RETRIESproducer +cutout-retries/cutout-retries-dlqconsumers), Email send-binding (EMAIL), and Analytics Engine dataset (EVENTS) under Settings → Bindings. Names must match thebindingvalues inwrangler.toml. - Set runtime variables and secrets under Settings → Variables and Secrets — see the list at the bottom of
wrangler.toml. - Push to
main. Cloudflare Builds runs the build command (which applies any pending D1 migrations), thenwrangler deploy— which picks up[build] command = "worker-build --release"fromwrangler.tomlto compile the Rust crate to WASM.
Features
- Rule-based routing: ordered glob patterns on local and domain parts, evaluated top-to-bottom, first match wins; a
*@*Drop catch-all is always pinned at the end - Dual-mode email forwarding: choose between high-fidelity Native mode (preserves PGP/attachments) and reliable Proxy mode (ensures
Reply-Torouting works via your custom domain) - Permanent Archival: an
X-Original-Fromheader is injected into all forwarded mail so you never lose the sender's identity even if KV mappings expire - Multi-destination forwards: one rule can forward to any mix of email / Telegram / Discord targets
- Bot-relay replies: reply directly from Telegram or Discord chat; Cutout routes it back to the original sender via email
- HTMX Management UI: clean, responsive web interface for managing rules, gated by Cloudflare Access
- Safety first: automatic loop detection; kinds whose secrets aren't set are hidden from the UI and rejected by the validator
- Live tester: each rule's inspector includes an interactive tester that evaluates a recipient address against this rule plus the full ruleset, highlighting which rule actually fires
- Multi-domain: one worker serves any number of zones; rules use the domain glob to differentiate
Architecture
- Cloudflare Workers: Rust compiled to WebAssembly
- Cloudflare Email Routing: inbound MX + catch-all -> worker, plus
EmailMessage.forward()for the Native Forward path - Cloudflare Email Service: used for reverse-alias replies, Proxy mode forwarding, and fanning out beyond the first destination
- Cloudflare KV: rule list, reverse-alias mappings, and per-message bot reply contexts
- Cloudflare Access: protects
/manage - botrelay-rs: shared crate providing the Telegram + Discord bot clients and reply-context primitives
Development
nix develop # enter dev shell with all tools (Nix-only; CI does not use Nix)
cargo test # run tests
cargo clippy # lint
wrangler dev # local dev server
nix flake check # run all CI checks (tests, clippy, fmt, pre-commit)
Nix is for local convenience only — Cloudflare Builds installs the same toolchain via rustup, which reads the channel from rust-toolchain.toml.