Commit 7ad7139
feat(worker): add send_email binding support (cloudflare#975)
* feat(worker): add send_email binding support
Adds a `SendEmail` binding and `EmailMessage` type so workers can dispatch
email via the Cloudflare Email Sending service configured under
`[[send_email]]` in wrangler.toml. Includes worker-sys bindings for
`cloudflare:email`, a runnable example under `examples/send-email`, and
integration tests.
* feat(worker): add structured Email builder for send_email binding
Extend the SendEmail binding to cover the public-beta builder overload in
addition to the raw MIME path. Adds `Email`/`EmailBuilder`, `EmailAddress`,
`EmailAttachment` (with `AttachmentContent::{Base64, Binary}`), and
`EmailSendResult { message_id }`. `SendEmail::send` now takes `&Email`;
the raw MIME path moves to `SendEmail::send_mime(&EmailMessage)`.
* address pr comments
* remove miniflare workaround
cloudflare/workers-sdk#13577 landed
* cleanup comments & example readme
* use ts-gen for email
* Auto-gen email bindings via ts-gen anonymous interface synthesis
Drops the hand-written Email/EmailBuilder/EmailAddress/EmailAttachment
types in worker/src/send_email.rs in favour of the auto-generated
SendEmailBuilder, EmailAddress, EmailAttachment, etc. that ts-gen now
synthesises from the d.ts. send_email.rs is reduced to the EnvBinding
trait impl on the auto-gen SendEmail extern type and re-exports.
types/email.d.ts renames the global EmailMessage interface to
StructuredEmailMessage to keep it unambiguously distinct from the
cloudflare:email-imported EmailMessage constructor class. The chompfile
prepends a `use email::EmailMessage` to the generated file so the
top-level send(message) signature resolves cross-module — removable
once ts-gen handles same-file module imports natively.
All 133 npm tests pass; both legacy raw-MIME and modern structured
send paths work end-to-end.
* add new_with_readable_stream test
* Pull cross-module qualification + new builder ergonomics from ts-gen
ts-gen learned three things since the last sync that simplify the
email surface here:
* Cross-module type references emit qualified Rust paths
(`&email::EmailMessage` from a `Global` extern block referencing the
`cloudflare:email` class). Drops the `chompfile.toml` postprocess
that was prepending `use email::EmailMessage;` to the generated
file.
* Built-in `web_sys` defaults — `Headers`, `Event`, `ReadableStream`,
etc. resolve to `::web_sys::*` automatically, so those `--external`
flags are redundant. Only the project-specific `Env` and
`ExecutionContext` mappings remain in the chompfile.
* New dictionary builder shape: required fields go through the
constructor, `build()` is infallible, literal discriminators
collapse into the function name. Call sites update from
`SendEmailBuilder::builder().from(x).build()?` to
`SendEmailBuilder::builder(from, to, subject).build()` (or
`::new(from, to, subject)` when no optionals are needed).
`types/email.d.ts` collapses to a single `class EmailMessage` inside
`declare module "cloudflare:email"`. The previous global-interface +
module-class split (mirroring upstream `@cloudflare/workers-types`)
was producing two distinct Rust types that both lowered to the same JS
object, which forced an `unchecked_ref` at the `reply()` call site.
Collapsed to one type they're indistinguishable in Rust.
`worker/src/send_email.rs` keeps the [`EnvBinding`] impl on top of
the auto-gen `SendEmail` extern type, plus a `#[cfg(test)]` compile
check that `SendEmail: Send` (which it is already, via the upstream
`JsValue: Send + Sync` change — no `unsafe impl Send` needed).
* Use FixedLengthStream Deref instead of unchecked_into in mime-stream test
`FixedLengthStream` already has `extends = web_sys::TransformStream` in
`worker-sys`, so wasm-bindgen auto-generates `Deref<Target = TransformStream>`
and `fixed.readable()` resolves through it. The previous
`fixed.unchecked_into::<web_sys::TransformStream>().readable()` was
unnecessarily defensive — drop the cast plus the now-unused `JsCast`
and `web_sys` imports.
* Fmt + advance ts-gen submodule to PR branch HEAD
CI's rustfmt --check flagged the dispatch_structured signature.
Apply fmt and bump the ts-gen submodule pointer to the latest
PR cloudflare#8 commit (CONVENTIONS.md rationale + emit cleanup).
* Pull doc-comment generation from ts-gen PR cloudflare#9
Each `new*` and `builder*` variant now ships with a doc block listing
its inlined literal discriminants under `# Inlined fields` and the
caller-supplied parameters under `# Parameters`, sourced from the
original getter JSDoc.
* Advance ts-gen submodule to merged main
ts-gen PR cloudflare#9 (doc comments on dictionary builder variants) merged.
Bump the submodule pointer to the merge commit on main; the
generated `worker/src/email.rs` is unchanged from the PR-branch
output.
* Advance ts-gen submodule to merged main
ts-gen PR cloudflare#10 (h2 headings + dash-separated bullets in builder docs)
merged. Bump the submodule pointer and regenerate
`worker/src/email.rs` with the updated doc format.
---------
Co-authored-by: Guy Bedford <gbedford@cloudflare.com>1 parent fd18681 commit 7ad7139
24 files changed
Lines changed: 1362 additions & 31 deletions
File tree
- examples/send-email
- src
- test
- src
- tests
- types
- worker-build/src
- worker/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
3 | 19 | | |
4 | 20 | | |
5 | 21 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
18 | | - | |
| 18 | + | |
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
| |||
0 commit comments