- Created project directory:
/Users/netanelgilad/development/offload-email-worker/ - Initialized npm project
- Installed dependencies:
wrangler,typescript,@cloudflare/workers-types - Created
tsconfig.jsonfor TypeScript configuration
- Created D1 database:
email-store - Database ID:
4722c1ac-2668-4650-8398-40f06d00dada - Executed schema migration with tables and indices:
emailstable with fields: id, from_address, to_address, subject, body_text, body_html, headers, received_at, read, starred- Indices on: received_at, from_address, to_address
- Migration executed successfully on both local and remote databases
- Created
src/index.tswith:- Email handler: Receives emails via Cloudflare Email Routing
- HTTP API handler with endpoints:
GET /api/emails- List emails (supports?limit=,?offset=,?unread=true)GET /api/emails/:id- Get single emailPATCH /api/emails/:id- Update email (mark read, starred)DELETE /api/emails/:id- Delete emailGET /api/stats- Get statistics (total, unread, starred)
- Bearer token authentication
- CORS headers enabled
- UUID generation for email IDs
- Created
wrangler.tomlwith:- Worker name:
offload-email - Account ID:
9f115f48742baa27266fe2138fd16ba3 - D1 binding configured
- Route:
email.offloadmy.work/*(zone: offloadmy.work)
- Worker name:
- Generated API secret:
dd010b2f81264ff0b5b5fa84d6527864bba7ef1738c9eaf25b9295bc6f6c3dce - Saved to:
~/.config/offload/email-worker.json - Set in Wrangler:
wrangler secret put API_SECRET
- Successfully deployed worker to Cloudflare
- Version ID:
1d1ee541-df7d-4ae6-b74f-d7de5fd7b50e - Route configured:
email.offloadmy.work/*
The worker is deployed but needs DNS records set up:
Required DNS Record:
- Type:
CNAMEorAAAA - Name:
email - Target:
offload-email.netanelgilad.workers.dev(or appropriate Cloudflare Worker proxy) - Proxy status: Proxied (orange cloud)
Steps:
- Go to Cloudflare Dashboard: https://dash.cloudflare.com/
- Select domain:
offloadmy.work - Navigate to DNS → Records
- Add a new record:
- Type: CNAME (or AAAA pointing to Cloudflare's proxy IPs)
- Name:
email - Target:
<worker-hostname>or use Cloudflare Worker route
- Ensure proxy is enabled (orange cloud)
Configure Cloudflare Email Routing to forward emails to the worker:
Steps:
- Go to Cloudflare Dashboard: https://dash.cloudflare.com/
- Select domain:
offloadmy.work - Navigate to Email → Email Routing
- Ensure Email Routing is enabled for the domain
- Under "Email Workers", click "Create worker route" or "Routes"
- Create a catch-all route:
- Pattern:
*@offloadmy.work(or specific addresses) - Action: Send to Worker
- Worker:
offload-email
- Pattern:
- Save the route
Alternative API Method (if you have an API token):
# Get zone ID
curl -X GET "https://api.cloudflare.com/client/v4/zones?name=offloadmy.work" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json"
# Create email routing rule
curl -X POST "https://api.cloudflare.com/client/v4/zones/{ZONE_ID}/email/routing/rules" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"matchers": [{"type": "all"}],
"actions": [{
"type": "worker",
"value": ["offload-email"]
}],
"enabled": true,
"name": "Catch-all to worker"
}'Once DNS and email routing are configured:
# Set your API token
export API_TOKEN="dd010b2f81264ff0b5b5fa84d6527864bba7ef1738c9eaf25b9295bc6f6c3dce"
# Get stats
curl -H "Authorization: Bearer $API_TOKEN" https://email.offloadmy.work/api/stats
# List emails
curl -H "Authorization: Bearer $API_TOKEN" https://email.offloadmy.work/api/emails
# List only unread emails
curl -H "Authorization: Bearer $API_TOKEN" "https://email.offloadmy.work/api/emails?unread=true&limit=10"Send a test email to any address at offloadmy.work, e.g.:
test@offloadmy.work
hello@offloadmy.work
Then check via API:
curl -H "Authorization: Bearer $API_TOKEN" https://email.offloadmy.work/api/emails# Get the email ID from the list, then:
curl -X PATCH \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"read": true}' \
https://email.offloadmy.work/api/emails/EMAIL_ID/Users/netanelgilad/development/offload-email-worker/
├── package.json
├── package-lock.json
├── tsconfig.json
├── wrangler.toml
├── schema.sql
├── src/
│ └── index.ts
└── DEPLOY_LOG.md (this file)
~/.config/offload/
└── email-worker.json (API secret stored)
- API Secret: Stored in
~/.config/offload/email-worker.json - Database ID:
4722c1ac-2668-4650-8398-40f06d00dada - Worker URL:
https://email.offloadmy.work/*(once DNS is configured) - Account ID:
9f115f48742baa27266fe2138fd16ba3
- ⏳ Complete DNS setup (add
email.offloadmy.workrecord) - ⏳ Configure Email Routing catch-all rule
- ⏳ Test email reception by sending to
test@offloadmy.work - ⏳ Test HTTP API endpoints (use
./test-api.shafter DNS is configured) - 💡 Consider building a simple frontend UI to view/manage emails
- 💡 Set up monitoring/alerts for email delivery issues
./test-api.sh- Test all API endpoints./setup-cloudflare.sh- Helper script for DNS/Email routing (requires CF_API_TOKEN)
Issue: DNS not resolving
- Check that the DNS record is created and propagated
- Verify proxy (orange cloud) is enabled in Cloudflare
Issue: Emails not being received
- Check Email Routing is enabled in Cloudflare dashboard
- Verify the worker route is correctly configured
- Check worker logs:
wrangler tail offload-email
Issue: API returns 401/403
- Verify you're using the correct API secret from
~/.config/offload/email-worker.json - Check Authorization header format:
Bearer YOUR_SECRET
Issue: Worker errors
- View logs:
wrangler tail offload-email - Check D1 database binding is correct in wrangler.toml