| title | Cloudflare Email Worker registration notes — message.raw, MIME, and SPF | ||||||
|---|---|---|---|---|---|---|---|
| domain | devops | ||||||
| tags |
|
||||||
| status | published | ||||||
| lang | en | ||||||
| source | uncledad96-glitch | ||||||
| translated_from | lessons/contrib/cloudflare-email-worker-registration-trap.md | ||||||
| created | 2026-08-02 | ||||||
| updated | 2026-08-02 | ||||||
| confidence | 0.9 |
Adding a no-GitHub registration channel using Cloudflare Email Routing + Workers + KV. The goal: users send mail to a registration address → Worker assigns a node ID → stores it in KV. Four separate pitfalls blocked deployment.
message.textdoes not exist. Cloudflare Email Workersemailevent handler has notextproperty. The body must be read frommessage.raw(aReadableStream) and decoded manually.- Node.js
cryptomodule is unavailable. Workers does not fully support Node.jscrypto. Even withnodejs_compatenabled,randomBytesmay fail. The Web Crypto API is the supported path. - Reply mail rejected by QQ / 163 / Foxmail. Cloudflare sending IPs are not on the SPF whitelist of major Chinese mail providers. The reply is rejected or marked as spam. This is an infrastructure trust issue, not a code bug.
- Turnstile + form integration fails. Turnstile requires the page URL to be whitelisted. Both the
workers.devdevelopment domain and the production domain must be added in the Turnstile dashboard.
let rawText = '';
const reader = message.raw.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
rawText += decoder.decode(value, { stream: true });
}Reference: Cloudflare Email Workers docs
const array = new Uint8Array(16);
crypto.getRandomValues(array);
const token = Array.from(array, b => b.toString(16).padStart(2, '0')).join('');Remove verification from the critical path. Treat inbound mail as registration itself: assign the node ID and write KV on receipt. The reply becomes best-effort notification. This follows the "尽力交付" (best-effort delivery) pattern used elsewhere in the MisakaNet stack.
Add every frontend domain (including workers.dev subdomains) to the Turnstile allowlist. Verify with:
curl -X POST https://challenges.cloudflare.com/turnstile/v0/siteverify \
-d "secret=<SECRET_baac7e50>&response=<token>"- User / AI Agent sends mail to the registration address.
- Worker
emailevent fires. node_counterincrements;node:MisakaXXXXXis written to KV.- Confirmation reply is attempted (best-effort).
- Web form passes Turnstile + KV rate limit.
npx wrangler kv key list --binding MISAKANET_KV
# Expect node:MisakaXXXXX and node_counter entries- Cloudflare Email Workers API differs from standard HTTP Workers: there is no
fetcheventrequest, only anemaileventmessage.message.rawis the only way to access the body. - Mail infrastructure reliability cannot be assumed. Whether
message.reply()reaches the recipient depends on the receiver's SPF policy; do not make it a critical path. - Prefer Web standard APIs (
crypto.getRandomValues) over Node.js APIs inside Workers. - Dual-channel (mail + web form) complement each other: Agents automate via mail, humans use the form, both share the same KV backend.