The Nuxt Email Layer includes powerful development tools that make it easy to test, debug, and preview emails during development. The devtools provide a complete email testing environment without needing external email services.
The email devtools provide:
📧 Email Inbox - View all emails sent during development🧪 Test Email Sending - Send test emails with sample data🔍 Email Preview - Preview email content in a browser-compatible format🗑️ Email Management - Clear email history and manage individual emails⚡ Real-time Updates - See new emails as they're sentThe devtools are automatically available when running your Nuxt application in development mode.
Visit the devtools interface at:
http://localhost:3000/__email-devtools
The email devtools are also integrated with Nuxt DevTools. Look for the "Email" tab in your Nuxt DevTools panel.
The left sidebar shows all caught emails with:
Recipient email address Sender email address Email subject Timestamp Quick delete button The main panel displays:
Email metadata (to, from, date)Subject line Rendered email content in an iframeEmail actions (delete, etc.)Send Test - Send a sample email for testingRefresh - Reload the email listClear All - Delete all stored emailsStart your development server
npm run dev
# or
pnpm dev
Open the devtools
Navigate to http://localhost:3000/__email-devtoolsSend test emails
Use your application's email functionality or click "Send Test"Review emails
Click on emails in the sidebar to preview their contentUse the "Send Test" button to quickly send sample emails for testing:
server/api/__devtools/emails/send.get.ts
import TestEmail from '#layers/email/server/emails/two-factor-auth.vue'
export default defineEventHandler ( async ( event ) => {
const email = useEmail ()
return await email. send ({
to: 'test@example.com' ,
subject: 'Test Email from Devtools' ,
template: TestEmail,
data: {
userName: 'Test User' ,
verificationCode: '123456' ,
expiresIn: '10 minutes' ,
supportUrl: 'https://help.example.com'
}
})
})
Create dedicated test endpoints for your email templates:
server/api/test/welcome-email.ts
import WelcomeEmail from '~/server/emails/welcome.vue'
export default defineEventHandler ( async ( event ) => {
const query = getQuery (event)
const email = useEmail ()
return await email. send ({
to: query.email as string || 'test@example.com' ,
subject: 'Welcome Email Test' ,
template: WelcomeEmail,
data: {
userName: query.name as string || 'Test User' ,
userEmail: query.email as string || 'test@example.com' ,
dashboardUrl: 'https://app.example.com/dashboard' ,
supportUrl: 'https://help.example.com'
}
})
})
Then test with different parameters:
http://localhost:3000/api/test/welcome-email?name=John&email=john@example.com
Test order confirmations, password resets, and other transactional emails:
server/api/test/order-confirmation.ts
import OrderConfirmationEmail from '~/server/emails/order-confirmation.vue'
export default defineEventHandler ( async ( event ) => {
const email = useEmail ()
return await email. send ({
to: 'customer@example.com' ,
subject: 'Order Confirmation #12345' ,
template: OrderConfirmationEmail,
data: {
customerName: 'John Doe' ,
orderNumber: '12345' ,
orderItems: [
{ name: 'Product A' , quantity: 2 , price: 29.99 },
{ name: 'Product B' , quantity: 1 , price: 49.99 }
],
totalAmount: 109.97 ,
trackingUrl: 'https://shipping.example.com/track/12345'
}
})
})
Test marketing and newsletter content:
server/api/test/newsletter.ts
import NewsletterEmail from '~/server/emails/newsletter.vue'
export default defineEventHandler ( async ( event ) => {
const email = useEmail ()
return await email. send ({
to: 'subscriber@example.com' ,
subject: 'Weekly Newsletter - Tech Updates' ,
template: NewsletterEmail,
data: {
subscriberName: 'Jane Smith' ,
articles: [
{
title: 'New Vue 3.4 Features' ,
excerpt: 'Discover the latest features in Vue 3.4 including improved performance and developer experience.' ,
url: 'https://blog.example.com/vue-3-4-features' ,
image: 'https://example.com/images/vue-article.jpg'
},
{
title: 'Building Scalable APIs' ,
excerpt: 'Best practices for designing APIs that can handle millions of requests.' ,
url: 'https://blog.example.com/scalable-apis'
}
],
unsubscribeUrl: 'https://example.com/unsubscribe?token=abc123'
}
})
})
If templates aren't rendering correctly:
Check the email preview in the devtoolsLook for console errors in the browser developer toolsVerify template data by logging it in your API endpointserver/api/debug-template.ts
import MyTemplate from '~/server/emails/my-template.vue'
export default defineEventHandler ( async ( event ) => {
const email = useEmail ()
const templateData = {
userName: 'Debug User' ,
actionUrl: 'https://example.com/action'
}
// Log template data for debugging
console. log ( 'Template data:' , templateData)
try {
const result = await email. send ({
to: 'debug@example.com' ,
subject: 'Debug Template' ,
template: MyTemplate,
data: templateData
})
console. log ( 'Email sent successfully:' , result.id)
return result
} catch (error) {
console. error ( 'Template rendering failed:' , error)
throw error
}
})
Test provider configuration:
server/api/test-provider.ts
export default defineEventHandler ( async ( event ) => {
try {
const email = useEmail ()
console. log ( 'Provider name:' , email.name)
const result = await email. send ({
to: 'test@example.com' ,
subject: 'Provider Test' ,
body: 'Testing provider configuration'
})
return {
success: true ,
provider: email.name,
emailId: result.id,
message: result.message
}
} catch (error) {
console. error ( 'Provider test failed:' , error)
return {
success: false ,
error: error.message,
provider: 'unknown'
}
}
})
Create comprehensive test suites for your templates:
server/api/test/template-variations.ts
import WelcomeEmail from '~/server/emails/welcome.vue'
const testCases = [
{
name: 'basic-user' ,
data: {
userName: 'John Doe' ,
userEmail: 'john@example.com' ,
dashboardUrl: 'https://app.example.com/dashboard'
}
},
{
name: 'long-name-user' ,
data: {
userName: 'Dr. Jonathan Alexander Smith-Wilson III' ,
userEmail: 'jonathan.smith-wilson@very-long-domain-name.co.uk' ,
dashboardUrl: 'https://app.example.com/dashboard'
}
},
{
name: 'special-chars-user' ,
data: {
userName: 'José María Azuña-Óñate' ,
userEmail: 'jose.maria@empresa-española.es' ,
dashboardUrl: 'https://app.example.com/dashboard'
}
}
]
export default defineEventHandler ( async ( event ) => {
const query = getQuery (event)
const testCase = query.case as string || 'basic-user'
const selectedTest = testCases. find ( tc => tc.name === testCase)
if ( ! selectedTest) {
throw createError ({
statusCode: 400 ,
statusMessage: `Test case '${ testCase }' not found`
})
}
const email = useEmail ()
return await email. send ({
to: selectedTest.data.userEmail,
subject: `Welcome Test - ${ selectedTest . name }` ,
template: WelcomeEmail,
data: selectedTest.data
})
})
Test different cases:
/api/test/template-variations?case=long-name-user
/api/test/template-variations?case=special-chars-user
Verify that your email hooks are working correctly:
server/api/test-hooks.ts
export default defineEventHandler ( async ( event ) => {
const email = useEmail ()
// This email should trigger any registered hooks
const result = await email. send ({
to: 'hooks-test@example.com' ,
subject: 'Testing Email Hooks' ,
body: 'This email tests the hook system.'
})
return {
emailId: result.id,
message: 'Check server logs for hook execution' ,
sentData: result.sentData
}
})
Emails not appearing in devtools:
Ensure you're using the mailcatcher provider Check that the storage directory has write permissions Verify the storage key configuration Template rendering errors:
Check Vue Email component imports Verify template data types match component props Look for missing required props Devtools interface not loading:
Ensure you're in development mode Check that the route /__email-devtools is accessible Verify the email devtools module is enabled Create a diagnostic endpoint to check your configuration:
server/api/email-config.ts
export default defineEventHandler ( async ( event ) => {
const config = useRuntimeConfig ()
return {
provider: config.email?.provider || 'not set' ,
defaultFrom: config.email?.defaultFrom || 'not set' ,
mailcatcher: {
storageKey: config.email?.mailcatcher?.storageKey || 'not set'
},
devMode: process.env. NODE_ENV === 'development' ,
devtoolsEnabled: config.emailDevtools?.devtools !== false
}
})
The devtools are automatically disabled in production, but you can explicitly control this:
nuxt.config.ts
export default defineNuxtConfig ({
emailDevtools: {
devtools: process.env. NODE_ENV === 'development'
}
})
Clear development email data when switching to production:
# Remove mailcatcher storage
rm -rf ./.data/mailcatcher