Summary
The "Upload to Resend" / "Bulk Upload" buttons in the preview server's Resend toolbar always call resend.templates.create(), so every click creates a brand new template in the Resend dashboard rather than updating the existing one. This makes the integration effectively unusable as a sync mechanism — you end up with welcome, welcome (1), welcome (2), etc., and the template ID referenced by your application code keeps pointing at the original (outdated) version.
Reproduction
- Create an email template (e.g.
emails/welcome.tsx)
- Run
pnpm email
- Open the template, go to the Resend tab in the toolbar, click Upload. A new template is created in Resend — copy its ID into your app code.
- Edit
emails/welcome.tsx (e.g. change a heading)
- Click Upload again
- Expected: the same template (by ID) is updated with the new HTML
- Actual: a second template named
welcome is created with a new ID; the original template still has the old HTML, and the app code still points at it
Source
In packages/preview-server/src/actions/export-single-template.ts:
const response = await resend.templates.create({
name: parsedInput.name,
html: parsedInput.html,
});
It only calls create, never update. The UI also has no way to associate a template file with an existing Resend template ID — neither through the toolbar nor a config file.
Suggested fix
Two parts:
- Per-template ID mapping: support an optional config (e.g.
react-email.config.ts or .react-email.json) that maps email file paths/slugs to existing Resend template IDs:
export default {
resend: {
templates: {
"welcome": "tmpl_abc123",
"password-reset": "tmpl_def456",
},
},
};
- Use update when an ID is known: in
exportSingleTemplate, if the slug is in the mapping, call resend.templates.update(id, { html }); otherwise fall through to create() and (ideally) write the new ID back to the config so the next upload updates in place.
A simpler MVP would just look up the template by name via resend.templates.list() and call update() if a match exists — no config file needed — but a stable ID mapping is more reliable since template names aren't unique in Resend.
Workaround
I wrote a small standalone script that uses @react-email/render + resend.templates.update(id, { html }) directly with hardcoded IDs. Happy to share if useful, and happy to put up a PR for the upstream fix if there's interest in either of the approaches above.
Environment
react-email: 5.2.10
@react-email/preview-server: 5.2.10
resend: 6.x
Summary
The "Upload to Resend" / "Bulk Upload" buttons in the preview server's Resend toolbar always call
resend.templates.create(), so every click creates a brand new template in the Resend dashboard rather than updating the existing one. This makes the integration effectively unusable as a sync mechanism — you end up withwelcome,welcome (1),welcome (2), etc., and the template ID referenced by your application code keeps pointing at the original (outdated) version.Reproduction
emails/welcome.tsx)pnpm emailemails/welcome.tsx(e.g. change a heading)welcomeis created with a new ID; the original template still has the old HTML, and the app code still points at itSource
In
packages/preview-server/src/actions/export-single-template.ts:It only calls
create, neverupdate. The UI also has no way to associate a template file with an existing Resend template ID — neither through the toolbar nor a config file.Suggested fix
Two parts:
react-email.config.tsor.react-email.json) that maps email file paths/slugs to existing Resend template IDs:exportSingleTemplate, if the slug is in the mapping, callresend.templates.update(id, { html }); otherwise fall through tocreate()and (ideally) write the new ID back to the config so the next upload updates in place.A simpler MVP would just look up the template by name via
resend.templates.list()and callupdate()if a match exists — no config file needed — but a stable ID mapping is more reliable since template names aren't unique in Resend.Workaround
I wrote a small standalone script that uses
@react-email/render+resend.templates.update(id, { html })directly with hardcoded IDs. Happy to share if useful, and happy to put up a PR for the upstream fix if there's interest in either of the approaches above.Environment
react-email: 5.2.10@react-email/preview-server: 5.2.10resend: 6.x