Email Workers
Receive inbound mail via Email Routing and send outbound mail from a Go worker.
Email Workers let a Worker handle inbound mail routed by Email Routing, and send outbound mail through a SendEmail binding. The exp/cloudflare/email package covers both sides.
Handle inbound email
email.Handle registers a func(*email.ForwardableEmailMessage) error as the worker’s email(message, env, ctx) handler and blocks. There is no wrangler.toml key for the inbound trigger — create an Email Routing route with a “Send to a Worker” action pointing at this worker (Email > Email Routing in the dashboard).
func main() {
email.Handle(func(msg *email.ForwardableEmailMessage) error {
log.Printf("from=%s to=%s size=%d", msg.From(), msg.To(), msg.RawSize())
// the destination must be a verified address on this zone
if _, err := msg.Forward("you@example.com", nil); err != nil {
return msg.SetReject("forwarding failed")
}
return nil
})
}
msg.From(),msg.To(),msg.RawSize()expose the envelope;msg.Raw()streams the raw MIME content as anio.ReadCloserandmsg.Headers()returns anhttp.Header.msg.Forward(rcptTo, headers)forwards to a verified destination address.msg.SetReject(reason)returns a permanent SMTP error to the connecting client.- Returning an error is treated as a temporary failure — the message is not accepted and delivery may be retried.
Handleblocks; a worker that also serves HTTP should register other handlers and call a single blocking entry point such asworkers.Serveinstead.
Reply or send outbound mail
Declare a send_email binding:
[[send_email]]
name = "SEND_EMAIL"
# destination_address = "you@example.com" # optional: restrict to one verified address
Build an *email.EmailMessage with email.NewEmailMessage(from, to, raw) (raw MIME streamed from an io.Reader) or email.NewEmailMessageString(from, to, raw), then pass its JSValue() to Reply or Send:
sender, err := email.NewSendEmail("SEND_EMAIL")
if err != nil {
return err
}
msg, err := email.NewEmailMessageString("bot@example.com", "user@example.com",
"Subject: hi\r\n\r\nHello from a Worker\r\n")
if err != nil {
return err
}
res, err := sender.Send(msg.JSValue()) // res.MessageID
Inside an email handler, msg.Reply(reply.JSValue()) replies to the original sender. SendBuilder/ReplyBuilder take the EmailMessageBuilder/EmailReplyMessageBuilder structs instead, for composing a message without writing raw MIME.
Example project
_examples/email-forward forwards inbound mail to a verified destination address.