Miniflare email() handler message has no canBeForwarded property in local dev
Maintainers usually reply within 1 day
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 78/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- javascript, typescript
Research direction
Start in packages/miniflare/src/workers/core/email.ts at the object passed to the Worker’s email() handler, and compare its fields with the ForwardableEmailMessage behavior described in the issue. Run the inline wrangler dev reproduction and confirm canBeForwarded exists as a boolean while rawSize remains 147. The issue leaves the boolean’s value for locally posted mail to maintainers.
Written by the indexing model from the issue text.
Description
What versions & operating system are you using?
- wrangler 4.158.0 (latest on npm at the time of testing), which depends on miniflare 5.20261104.0-beta and workerd 1.20261104.1
- Node.js 26.12.1, npm 12.2.1, macOS 27.2 (arm64)
- Source inspected at workers-sdk
maincommit 33600fc3930902a0e5c9146d0d0c82f0029ddfa9 compatibility_date2026-11-01
Please provide a link to a minimal reproduction
The reproduction is inline under Describe the Bug (two files, wrangler.jsonc and src/index.js, plus a msg.eml fixture); there is no separate repository.
Describe the Bug
In wrangler dev, the ForwardableEmailMessage passed to a Worker's email() handler has no canBeForwarded property: message.canBeForwarded is undefined and "canBeForwarded" in message is false. Production exposes canBeForwarded as a read-only boolean on every inbound message, and the Email Service docs list it, so handler code that tests it for truthiness before calling message.forward() takes a different branch locally than in production.
Steps to reproduce
- Create a project with
wrangler.jsonc:
{
"name": "email-can-be-forwarded-repro",
"main": "src/index.js",
"compatibility_date": "2026-11-01"
}
- Create
src/index.js:
export default {
async email(message) {
console.log("canBeForwarded:", message.canBeForwarded, "| in message:", "canBeForwarded" in message, "| rawSize:", message.rawSize);
},
};
- Create
msg.emlwith CRLF line endings:
From: [email protected]
To: [email protected]
Subject: hello
Message-ID: <[email protected]>
Date: Sun, 08 Nov 2026 12:00:00 +0000
body
- Run
npx [email protected] dev --port 8812with the versions listed above. - Run
curl -X POST 'http://localhost:8812/cdn-cgi/handler/[email protected]&[email protected]' --data-binary @msg.eml.
Expected behavior
The handler should log a boolean for canBeForwarded and true for "canBeForwarded" in message. The production ForwardableEmailMessage declares JSG_READONLY_PROTOTYPE_PROPERTY(canBeForwarded, getCanBeForwarded) returning a bool, and the Email Service email handler reference lists readonly canBeForwarded: boolean; // Whether the message can be forwarded on the message parameter. Which value Miniflare should report for a locally posted message is for the maintainers to decide; the property should exist and be a boolean.
Actual behavior
The curl request returned Worker successfully processed email with HTTP 200, and wrangler dev logged:
canBeForwarded: undefined | in message: false | rawSize: 147
rawSize and the other documented properties are present. A second run with a different handler on the same versions logged canBeForwarded = undefined | 'canBeForwarded' in message = false for each of four inbound messages.
Evidence
- Expected source:
src/workerd/api/email.hlines 256-258 (getCanBeForwarded) and 278 (JSG_READONLY_PROTOTYPE_PROPERTY(canBeForwarded, getCanBeForwarded);) in cloudflare/workerd#8222 at head b3267af57e368a5c22e5a5af86fd42bb66d5fdd4, an open PR whose description says the internal production code is moved "as-is"; andsrc/content/docs/email-service/api/route-emails/email-handler.mdxline 64 in cloudflare/cloudflare-docs (published at https://developers.cloudflare.com/email-service/api/route-emails/email-handler/). - Failure source: the local
wrangler devrun above; source breadcrumb: the object literal passed to the user Worker'semail()inpackages/miniflare/src/workers/core/email.ts(lines 257-382, ending insatisfies ForwardableEmailMessage) setsfrom,to,raw,rawSize,headers,setReject,forwardandreply, and nocanBeForwarded. - Evidence provenance: observed
- Local verification: reproduced
- Reproduction completeness: complete
The local behavior was observed in wrangler dev. The production property is static evidence from the workerd PR source and the docs; it was not observed live, because the investigating account has no zone with Email Routing.
Restoration check
With the reproduction above, the handler currently logs canBeForwarded: undefined | in message: false. After the fix, the same request logs canBeForwarded: true or canBeForwarded: false (a boolean) and in message: true, and still logs rawSize: 147 for the same message.
Additional context
The ForwardableEmailMessage interface in the published @cloudflare/workers-types 5.20261108.1 does not declare canBeForwarded either, so the satisfies ForwardableEmailMessage check in Miniflare cannot flag the missing property. That types gap is tracked in cloudflare/workerd#8290; this report covers only Miniflare's runtime object, which will also stop satisfying the interface once the types add the property.
References
- cloudflare/workers-sdk#16788: a separate Miniflare email local-dev discrepancy (name-less
EmailAddressinsend_email). - cloudflare/workerd#8290:
canBeForwardedmissing fromForwardableEmailMessagein@cloudflare/workers-types.
Please provide any relevant error logs
wrangler dev output after the curl request:
[wrangler:info] Ready on http://localhost:8812
canBeForwarded: undefined | in message: false | rawSize: 147
- Dominant language
- TypeScript
- Stars
- 4.7k
- Forks
- 1.6k
- Avg merge
- 1d 23h
- Merged PRs (30d)
- 268
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from cloudflare/workers-sdk
-
bug package:workers-shared
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
cloudflare/workers-sdk#16924 · 1 comment ·
Maintainers usually reply within 1 day
-
Miniflare send_email accepts an EmailAddress without `name`, then drops it from the Local ExplorerMay be free again A pull request for this issue was closed without being merged. Openbug package:miniflare product:email
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
cloudflare/workers-sdk#16788 · 2 comments ·
Maintainers usually reply within 1 day
-
[workers-auth] Reject misleading Cloudflare Access 302 redirectsMay be free again @akhil9tiet claimed this 7 days ago, and no pull request is open. Openbug package:workers-auth
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
cloudflare/workers-sdk#16755 · 2 comments ·
Maintainers usually reply within 1 day
-
wrangler preview: require an explicit previews block only when needed (empty {} should be implied)Openpackage:wrangler product:previews
Difficulty 2/5 1-3 hours Newbie friendliness 67/100
cloudflare/workers-sdk#16754 · 1 comment ·
Maintainers usually reply within 1 day
-
bug feature:workers-assets package:deploy-helpers package:wrangler
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
cloudflare/workers-sdk#16713 · 1 comment ·
Maintainers usually reply within 1 day
All issues in cloudflare/workers-sdk
Similar issues
-
Wallet functions throws TypeError when the wallet has no account IDPossibly taken @Medhansh-741 claimed this today. Openbug
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
hiero-ledger/hiero-sdk-js#4781 · 1 comment ·
Maintainers usually reply within 1 day
-
good first issue
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
dataforgoodfr/mediterranean-rescue#91 ·
Maintainers usually reply within 1 day
-
transformer-directives: `@apply` drops a utility whose CSS is a substring of an earlier one'sPossibly taken A pull request linked to this issue is open or already merged. Open
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Maintainers usually reply within 1 day
-
Add: KRT TVOpenapproved check:passed streams:add
Difficulty 1/5 Under an hour Newbie friendliness 65/100
iptv-org/iptv#58647 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
milind-soni/OpenMausBot#5829 ·
Maintainers usually reply within 1 day