Skip to content

Add MessageBuilder support for Email Sending API in local mode#11942

Merged
penalosa merged 11 commits intomainfrom
penalosa/email
Jan 19, 2026
Merged

Add MessageBuilder support for Email Sending API in local mode#11942
penalosa merged 11 commits intomainfrom
penalosa/email

Conversation

@penalosa
Copy link
Copy Markdown
Contributor

@penalosa penalosa commented Jan 15, 2026

Implements support for the simplified MessageBuilder interface in Miniflare's Email Sending API binding. This provides a developer-friendly alternative to manually constructing MIME messages with the EmailMessage API.

Key changes:

  • Add TypeScript types for MessageBuilder API (types.ts)
  • Implement send() overload accepting MessageBuilder alongside EmailMessage
  • Store email content (text, HTML, attachments) to viewable temp files
  • Extract common storeTempFile() helper to reduce duplication
  • Add comprehensive test coverage (12 new tests)

In local mode, content is saved to files that developers can open in their editor/browser for inspection, with file paths logged to the console.


  • Tests
    • Tests included/updated
    • Automated tests not possible - manual testing has been completed as follows:
    • Additional testing not necessary because:
  • Public documentation
    • Cloudflare docs PR(s):
    • Documentation not necessary because: pre-release

A picture of a cute animal (not mandatory, but encouraged)

… mode

Implements support for the simplified MessageBuilder interface in Miniflare's
Email Sending API binding. This provides a developer-friendly alternative to
manually constructing MIME messages with the EmailMessage API.

Key changes:
- Add TypeScript types for MessageBuilder API (types.ts)
- Implement send() overload accepting MessageBuilder alongside EmailMessage
- Store email content (text, HTML, attachments) to viewable temp files
- Extract common storeTempFile() helper to reduce duplication
- Add comprehensive test coverage (12 new tests)

In local mode, content is saved to files that developers can open in their
editor/browser for inspection, with file paths logged to the console.
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Jan 15, 2026

🦋 Changeset detected

Latest commit: 5dac37e

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@penalosa penalosa changed the title [miniflare] Add MessageBuilder support for Email Sending API in local… Add MessageBuilder support for Email Sending API in local mode Jan 15, 2026
@github-project-automation github-project-automation bot moved this to Untriaged in workers-sdk Jan 15, 2026
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Jan 15, 2026

create-cloudflare

npm i https://pkg.pr.new/create-cloudflare@11942

@cloudflare/kv-asset-handler

npm i https://pkg.pr.new/@cloudflare/kv-asset-handler@11942

miniflare

npm i https://pkg.pr.new/miniflare@11942

@cloudflare/pages-shared

npm i https://pkg.pr.new/@cloudflare/pages-shared@11942

@cloudflare/unenv-preset

npm i https://pkg.pr.new/@cloudflare/unenv-preset@11942

@cloudflare/vite-plugin

npm i https://pkg.pr.new/@cloudflare/vite-plugin@11942

@cloudflare/vitest-pool-workers

npm i https://pkg.pr.new/@cloudflare/vitest-pool-workers@11942

@cloudflare/workers-editor-shared

npm i https://pkg.pr.new/@cloudflare/workers-editor-shared@11942

@cloudflare/workers-utils

npm i https://pkg.pr.new/@cloudflare/workers-utils@11942

wrangler

npm i https://pkg.pr.new/wrangler@11942

commit: 5dac37e


Add support for Email Sending API's MessageBuilder interface in local mode

Miniflare now supports the simplified MessageBuilder interface for sending emails, alongside the existing EmailMessage (raw MIME) support. This matches the API available in production Workers.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Miniflare now supports the simplified MessageBuilder interface for sending emails, alongside the existing EmailMessage (raw MIME) support. This matches the API available in production Workers.
Miniflare now supports the simplified MessageBuilder interface for sending emails, alongside the existing `EmailMessage` support.

await env.EMAIL.send({
from: { name: "Alice", email: "alice@example.com" },
to: ["bob@example.com"],
subject: "Hello from Miniflare",
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
subject: "Hello from Miniflare",
subject: "Hello",

});
```

In local mode, email content (text, HTML, attachments) is stored to temporary files that you can open in your editor or browser for inspection. File paths are logged to the console when emails are sent.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In local mode, email content (text, HTML, attachments) is stored to temporary files that you can open in your editor or browser for inspection. File paths are logged to the console when emails are sent.

} else if (content instanceof ArrayBuffer) {
body = new Uint8Array(content);
} else {
// ArrayBufferView
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// ArrayBufferView

- Simplify changeset description
- Shorten example subject to 'Hello'
- Remove trailing newline in changeset
- Remove extra blank line in send_email.worker.ts
Adds comprehensive manual testing examples for the MessageBuilder API:
- /send-simple: Basic text-only email
- /send-html: Email with text and HTML content
- /send-attachment: Single text attachment
- /send-multi-attachment: Multiple attachment types (text, JSON, binary)
- /send-complex: Multiple recipients (to/cc/bcc)
- /test-bindings: Test all three binding types

Also includes:
- README with complete usage instructions
- Documentation of expected console output
- Notes about type assertions (types not yet in @cloudflare/workers-types)

Tested locally - all routes work correctly.
The validateMessageBuilder function was passing EmailAddress objects
(with { name, email } structure) directly to validateRecipients, which
expected strings. This caused the error 'email to [object Object] not allowed'.

Fix: Extract email addresses from EmailAddress objects before validation
using the existing extractEmailAddress helper.

Tested with fixture routes that use EmailAddress objects:
- /send-simple (named sender)
- /send-complex (multiple recipients with names)

All tests pass.
The MessageBuilder snapshot test was failing on Windows because the regex
only matched Unix-style paths (/...). Updated the regex to also match
Windows paths (C:\...) while still normalizing both to the same format.

Regex now matches:
- Unix: /var/folders/.../email-text/uuid.txt
- Windows: C:\Users\...\email-text\uuid.txt

Both normalize to: /email-text/[FILE].txt
The proxy server previously only handled EmailMessage objects by
reconstructing them from the serialized 'EmailMessage::raw' property.
This fix adds detection for MessageBuilder objects and passes them
through directly since they're already plain serializable objects.

Changes:
- Check if the argument has 'EmailMessage::raw' property to distinguish
  EmailMessage from MessageBuilder
- EmailMessage: Reconstruct with EmailMessage constructor (existing behavior)
- MessageBuilder: Pass through directly as plain object (new behavior)

Both APIs now work correctly in remote mode via wrangler dev --remote.
@penalosa penalosa marked this pull request as ready for review January 19, 2026 11:33
@penalosa penalosa requested a review from a team as a code owner January 19, 2026 11:33
dependabot bot and others added 3 commits January 19, 2026 11:34
Bumps the workerd-and-workers-types group with 2 updates: [workerd](https://github.com/cloudflare/workerd) and [@cloudflare/workers-types](https://github.com/cloudflare/workerd).


Updates `workerd` from 1.20260115.0 to 1.20260116.0
- [Release notes](https://github.com/cloudflare/workerd/releases)
- [Changelog](https://github.com/cloudflare/workerd/blob/main/RELEASE.md)
- [Commits](cloudflare/workerd@v1.20260115.0...v1.20260116.0)

Updates `@cloudflare/workers-types` from 4.20260115.0 to 4.20260116.0
- [Release notes](https://github.com/cloudflare/workerd/releases)
- [Changelog](https://github.com/cloudflare/workerd/blob/main/RELEASE.md)
- [Commits](https://github.com/cloudflare/workerd/commits)

---
updated-dependencies:
- dependency-name: workerd
  dependency-version: 1.20260116.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: workerd-and-workers-types
- dependency-name: "@cloudflare/workers-types"
  dependency-version: 4.20260116.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: workerd-and-workers-types
...

Signed-off-by: dependabot[bot] <support@github.com>
The following dependency versions have been updated:

| Dependency | From         | To           |
| ---------- | ------------ | ------------ |
| workerd    | 1.20260115.0 | 1.20260116.0 |
Copy link
Copy Markdown
Contributor

@LuisDuarte1 LuisDuarte1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you for the help 🫶, lgtm!

Copy link
Copy Markdown
Contributor

@emily-shen emily-shen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

testing this manually and i don't seem to be getting a console log with a temp path when i test /send in the fixture (the one that uses the old API) - is that expected?

nvm it does work - everything looks good on manual test...

@github-project-automation github-project-automation bot moved this from Untriaged to Approved in workers-sdk Jan 19, 2026
Co-authored-by: emily-shen <69125074+emily-shen@users.noreply.github.com>
@penalosa penalosa merged commit 133bf95 into main Jan 19, 2026
36 checks passed
@penalosa penalosa deleted the penalosa/email branch January 19, 2026 17:10
@github-project-automation github-project-automation bot moved this from Approved to Done in workers-sdk Jan 19, 2026
Skye-31 added a commit to Skye-31/workerd that referenced this pull request Jan 19, 2026
Now that this is supported locally cloudflare/workers-sdk#11942
and ungated in production, these types are ready to update.
Skye-31 added a commit to Skye-31/workerd that referenced this pull request Jan 19, 2026
Now that this is supported locally (ref: cloudflare/workers-sdk#11942)
and ungated in production, these types are ready to be updated.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants