Skip to content

email

Source: src/Cloudflare/Workers/EmailEventSource.ts

Subscribe to Cloudflare Email Worker events with an Effect handler.

Wires both halves of the consumer in one call:

  • Runtime: registers an email event listener on the Worker. The handler receives a ForwardableEmailMessage whose action methods (forward, reply, setReject) return Effects.
  • Deploy-time (when zone is set): yields a Cloudflare.Email.Routing toggle on the zone plus the routing resource whose actions: [{ type: "worker", … }] targets this Worker — Cloudflare.Email.CatchAll for a catch-all subscription, Cloudflare.Email.Rule for anything more specific. No manual wiring needed in alchemy.run.ts.

Requires EmailEventSourceLive provided on the Worker’s Effect.

Failure semantics: a failing handler is logged and the failure is re-raised. Cloudflare turns that into a temporary SMTP failure, so the sending server keeps the message and retries later — mail is never accepted and then silently dropped. Handle the failures you consider final inside the handler (Effect.retry, Effect.catchTag, or message.setReject(...) to bounce permanently); anything you let escape becomes a retryable delivery failure.

Catch-all on a zone — auto-creates routing + catch-all

import * as Cloudflare from "alchemy/Cloudflare";
import * as Effect from "effect/Effect";
export default Cloudflare.Worker(
"Inbox",
{ main: import.meta.url },
Effect.gen(function* () {
yield* Cloudflare.email({ zone: "example.com" }).subscribe(
(message) => message.forward("ops@example.com"),
);
return {};
}).pipe(Effect.provide(Cloudflare.EmailEventSourceLive)),
);

Match a specific address

yield* Cloudflare.email({
zone: "example.com",
matchers: [{ type: "literal", field: "to", value: "hello@example.com" }],
}).subscribe((message) => message.forward("ops@example.com"));

Reject (bounce) a message

yield* Cloudflare.email({ zone: "example.com" }).subscribe((message) =>
message.setReject("Mailbox closed"),
);

Bring-your-own routing — no zone, no auto-create

// Manage `Email.Routing` / `Email.Rule` yourself in alchemy.run.ts.
yield* Cloudflare.email().subscribe((message) =>
Effect.log(`from ${message.from}`),
);