Migrating from Vue Email
Learn how to migrate your existing Vue Email project to Nuxt Email Renderer. This guide covers all the steps needed to transition smoothly while maintaining your existing email templates and functionality.
Why Migrate?
In an ideal world, we should have Vue Email working & maintained, so that it can provide a great experience for Vue & Nuxt users. However, the reality is that the project has been abandoned by its maintainers, and there are no signs of it being picked up again.
Unfortunately, I don't have the resources to maintain two separate libraries that serve a similar purpose. Therefore, I have decided to focus all my efforts on Nuxt Email Renderer, which I can actively maintain.
Nuxt Email Renderer offers several advantages over Vue Email:
- Native Nuxt 4+ Integration - Built specifically for Nuxt applications
- Better DevTools Support - Visual email template preview and debugging
- Simplified API - Server-side rendering endpoints built-in
- TypeScript First - Full TypeScript support out of the box
- Hot Module Replacement - Instant template updates during development
ETailwind component available in Vue Email. Currently, it is also not part of the roadmap for future development because it requires significant additional code and maintenance.Migration Steps
Step 1: Remove Vue Email Dependencies
Remove the existing Vue Email packages from your project:
npm uninstall @vue-email/components @vue-email/render
yarn remove @vue-email/components @vue-email/render
pnpm remove @vue-email/components @vue-email/render
bun remove @vue-email/components @vue-email/render
Step 2: Install Nuxt Email Renderer
Install the Nuxt Email Renderer module:
npm install nuxt-email-renderer
yarn add nuxt-email-renderer
pnpm add nuxt-email-renderer
bun add nuxt-email-renderer
Add the module to your nuxt.config.ts:
export default defineNuxtConfig({
modules: ["nuxt-email-renderer"],
});
For detailed installation instructions, see the Installation Guide.
Step 3: Remove Rollup Config (if applicable)
Remove Rollup config from Nitro settings if you have it configured:
export default defineNuxtConfig({
nitro: {
- rollupConfig: {
- plugins: [vue()], // see https://vuemail.net/getting-started/nuxt-nitro
- },
},
})
Step 4: Move Email Templates
Move all your email templates to an emails directory. For Nuxt 4+ projects, use the app/emails directory. For older projects or if you prefer, use the root emails directory:
Before (Vue Email):
your-project/
├── src/
│ └── emails/
│ ├── WelcomeEmail.vue
│ └── ResetPasswordEmail.vue
└── package.json
After (Nuxt Email Renderer with Nuxt 4):
your-project/
├── app/
│ └── emails/ # 📧 Nuxt 4 structure
│ ├── WelcomeEmail.vue
│ └── ResetPasswordEmail.vue
├── nuxt.config.ts
└── package.json
Or (Nuxt Email Renderer with root directory):
your-project/
├── emails/ # 📧 Root directory
│ ├── WelcomeEmail.vue
│ └── ResetPasswordEmail.vue
├── nuxt.config.ts
└── package.json
app/emails (Nuxt 4 structure) first, then falls back to emails (root directory) for backward compatibility.If you prefer to keep your templates in a different location, configure the emails directory:
export default defineNuxtConfig({
modules: ["nuxt-email-renderer"],
nuxtEmailRenderer: {
emailsDir: "/src/emails", // Custom directory
},
});
Step 5: Update Template Imports
Update your email templates to use Nuxt Email Renderer components:
Before (Vue Email):
<template>
<Html>
<Head />
<Body>
<Container>
<Heading>Welcome {{ userName }}!</Heading>
<Text>Thank you for joining us.</Text>
<Button :href="confirmUrl">Confirm Account</Button>
</Container>
</Body>
</Html>
</template>
<script setup>
import { Html, Head, Body, Container, Heading, Text, Button } from '@vue-email/components'
interface Props {
userName: string
confirmUrl: string
}
defineProps<Props>()
</script>
After (Nuxt Email Renderer):
<template>
<EHtml>
<EHead />
<EBody>
<EContainer>
<EHeading>Welcome {{ userName }}!</EHeading>
<EText>Thank you for joining us.</EText>
<EButton :href="confirmUrl">Confirm Account</EButton>
</EContainer>
</EBody>
</EHtml>
</template>
<script setup lang="ts">
// No imports needed - components are auto-imported!
interface Props {
userName: string;
confirmUrl: string;
}
defineProps<Props>();
</script>
Component Mapping
Here's how Vue Email components map to Nuxt Email Renderer components:
| Vue Email | Nuxt Email Renderer | Notes |
|---|---|---|
<Html> | <EHtml> | Same functionality |
<Head> | <EHead> | Same functionality |
<Body> | <EBody> | Same functionality |
<Container> | <EContainer> | Same functionality |
<Text> | <EText> | Same functionality |
<Heading> | <EHeading> | Same functionality |
<Button> | <EButton> | Same functionality |
<Img> | <EImg> | Same functionality |
<Link> | <ELink> | Same functionality |
<Hr> | <EHr> | Same functionality |
<Section> | <ESection> | Same functionality |
<Row> | <ERow> | Same functionality |
<Column> | <EColumn> | Same functionality |
<CodeBlock> | <ECodeBlock> | Same functionality |
<CodeInline> | <ECodeInline> | Same functionality |
<Font> | <EFont> | Same functionality |
<Preview> | <EPreview> | Same functionality |
<Style> | <EStyle> | Same functionality |
<EMarkdown> | <EMarkdown> | Same functionality |
<ETailwind> | ❌ | Not implemented |
Step 6: Update Rendering Logic
Replace your Vue Email rendering code with Nuxt Email Renderer API calls:
Before (Vue Email):
import { render } from "@vue-email/render";
import WelcomeEmail from "./emails/WelcomeEmail.vue";
const html = await render(WelcomeEmail, {
userName: "John Doe",
confirmUrl: "https://example.com/confirm",
});
After (Nuxt Email Renderer):
export default defineEventHandler(async (event) => {
const html = await renderEmailComponent("WelcomeEmail", {
userName: "John Doe",
confirmUrl: "https://example.com/confirm",
});
// Send the email using your email service
// await sendEmail({ to: 'user@example.com', html })
return { success: true };
});
renderEmailComponent function. This approach is more secure than exposing API endpoints publicly, as it keeps your email templates private and prevents abuse.Verification
After migration, verify everything works:
- Start your development server:
npm run dev - Check Nuxt DevTools:
- Open your browser's DevTools
- Navigate to the "Nuxt Email Renderer" tab
- Verify your templates are listed
- Test rendering in your server code:server/api/test-email.get.ts
export default defineEventHandler(async () => { const html = await renderEmailComponent("WelcomeEmail", { userName: "Test User", confirmUrl: "https://example.com/confirm", }); return html; });
Then visithttp://localhost:3000/api/test-emailto see the rendered HTML.
Common Migration Issues
Template Not Found
Problem: Template 'WelcomeEmail' not found
Solution:
- Ensure templates are in the correct directory (
/emailsby default) - Check filename matches exactly (case-sensitive)
- Verify the template file extension is
.vue
Component Import Errors
Problem: Components not recognized in templates
Solution:
- Remove manual component imports from Vue Email
- Components are auto-imported in Nuxt Email Renderer
- Ensure you're using the
Eprefix (e.g.,EHtml,EBody)
Props Type Errors
Problem: TypeScript errors with template props
Solution:
- Ensure
defineProps<Props>()is used correctly - Add
lang="ts"to your script setup block - Verify interface definitions match your API calls
Need Help?
If you encounter issues during migration:
- 📖 Check the Installation Guide
- 🧩 Review Component Documentation
- 🐛 Report issues on GitHub
- 💬 Ask questions in Discussions