Skip to content

app-showcase's email template declares locale: 'en', which no en-US send can resolve — and it bypasses defineEmailTemplateDefinition #10267

Description

@os-elon

Found while writing content/docs/automation/email-templates.mdx (#10211), by checking the example corpus for a real authored template to model the guide's samples on.

The defect

examples/app-showcase/src/system/emails/index.ts declares:

exportconstTaskDoneEmail={name: 'showcase_task_done_email',// …locale: 'en',// …};

sendTemplate's locale ladder is exact match, then en-US, then (no-locale calls only) the bundle's lowest tag — deliberately with no language-prefix matching, so en does not satisfy en-US and vice versa. The ladder is documented on SendTemplateInput.locale in packages/spec/src/contracts/email-service.ts and pinned by packages/plugins/plugin-email/src/template-locale-resolution.test.ts.

Consequences for this row:

calloutcome
sendTemplate({ template: 'showcase_task_done_email' }) (no locale)resolves — rung 3, because the bundle has no en-US row
sendTemplate({ template: 'showcase_task_done_email', locale: 'en-US' })TEMPLATE_NOT_FOUND
notify-node delivery for a recipient whose locale is en-USTEMPLATE_NOT_FOUND

The third one is the one that matters: the notify node's template path resolves (name, recipient locale)per recipient at delivery time, so this template is unreachable for exactly the recipients the showcase is most likely to have. It is latent today only because nothing in the showcase currently references the template by name — the file's own comment calls it "Email template fired by the Task Completed flow", but grep finds no consumer, so the example is both mis-localed and unwired.

The second half — why the schema never caught it

The literal is not wrapped in defineEmailTemplateDefinition(...), so EmailTemplateDefinitionSchema.parse() never runs at authoring time. The schema would not have rejected locale: 'en' either (it is z.string(), not a BCP-47 validator) — but the factory is what applies the en-US default, and an author who omitted locale entirely would have landed on the resolvable value for free.

Worth noting the example corpus is what customers and AI authors copy, and the docs page added in #10211 explicitly warns that zh does not resolve zh-CN — the showcase currently demonstrates the anti-pattern the guide warns about.

Suggested fix

Set locale: 'en-US' (or drop the key and take the default), and wrap the literal in defineEmailTemplateDefinition(...) the way examples/app-showcase/src/automation/jobs/index.ts already wraps its job in defineJob(...). Whether the template should also be wired to the Task Completed flow's notify node is a separate call for whoever owns the showcase.

No label applied — leaving severity to triage. Filed unassigned from the #10211 docs card, whose surface is content/docs/automation/** only.

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions