The useEmail() composable is the primary interface for sending emails in your Nuxt application. It automatically selects the configured email provider and provides a consistent API.
Returns an EmailProvider instance with the following interface:
interface EmailProvider {
name : string
send : ( email : EmailParams ) => Promise < EmailResponse >
}
Sends an email using the configured provider.
type EmailParams = {
from ?: string // Sender email (optional, uses defaultFrom if not provided)
to : string // Recipient email address (required)
subject : string // Email subject line (required)
} & (
| { body : string } // Plain text or HTML content
| { template : Component ; data ?: Record < string , unknown > } // Vue template with data
)
interface EmailResponse {
id : string // Unique email identifier
message : string // Success message
metadata : Record < string , any > // Provider-specific response data
sentData : SentEmailData // Final processed email data
}
interface SentEmailData extends EmailParams {
body : string // Rendered email body (templates are converted to HTML)
}
server/api/simple-email.ts
export default defineEventHandler ( async ( event ) => {
const email = useEmail ()
const result = await email. send ({
to: 'user@example.com' ,
subject: 'Welcome!' ,
body: 'Thank you for joining our platform.'
})
return {
emailId: result.id,
message: result.message
}
})
server/api/html-email.ts
export default defineEventHandler ( async ( event ) => {
const email = useEmail ()
const result = await email. send ({
to: 'user@example.com' ,
subject: 'HTML Newsletter' ,
body: `
<h1>Welcome to our Newsletter!</h1>
<p>Here's what's new this week:</p>
<ul>
<li>Feature updates</li>
<li>Bug fixes</li>
<li>Community highlights</li>
</ul>
`
})
return result
})
server/api/template-email.ts
import WelcomeEmail from '#layers/email/server/emails/welcome.vue'
export default defineEventHandler ( async ( event ) => {
const email = useEmail ()
const result = await email. send ({
to: 'user@example.com' ,
subject: 'Welcome to Our Platform!' ,
template: WelcomeEmail,
data: {
userName: 'John Doe' ,
userEmail: 'user@example.com' ,
dashboardUrl: 'https://app.example.com/dashboard'
}
})
return result
})
server/api/custom-sender.ts
export default defineEventHandler ( async ( event ) => {
const email = useEmail ()
const result = await email. send ({
from: 'support@example.com' ,
to: 'user@example.com' ,
subject: 'Support Response' ,
body: 'Your support ticket has been updated.'
})
return result
})
The send() method throws errors for various failure conditions. Always wrap calls in try-catch blocks:
server/api/safe-email.ts
export default defineEventHandler ( async ( event ) => {
try {
const email = useEmail ()
const result = await email. send ({
to: 'user@example.com' ,
subject: 'Test Email' ,
body: 'This is a test.'
})
return {
success: true ,
emailId: result.id
}
} catch (error) {
console. error ( 'Email failed:' , error)
throw createError ({
statusCode: 500 ,
statusMessage: 'Failed to send email' ,
data: { error: error.message }
})
}
})
// Thrown when email provider is not configured
Error : Email provider is not set
// Thrown when required provider settings are missing
Error : Mailgun API key and domain are required
// Thrown when email body is missing for providers that require it
Error : Email body isn 't set. Either provide one directly or use a templat e
// Thrown when template rendering fails
Error : Failed to render email template
// Provider-specific errors (e.g., Mailgun API errors)
Error : Error sending email via Mailgun
// Network or service errors
Error : Email service temporarily unavailable
Access information about the current provider:
server/api/provider-info.ts
export default defineEventHandler ( async ( event ) => {
const email = useEmail ()
return {
providerName: email.name,
isMailCatcher: email.name === 'mailcatcher' ,
isMailgun: email.name === 'mailgun'
}
})
The useEmail() composable is fully typed. Import types for better development experience:
import type {
EmailParams,
EmailResponse,
EmailProvider,
SentEmailData
} from '#layers/email/server/libs/useEmail/types'
export default defineEventHandler ( async ( event ) => {
const email : EmailProvider = useEmail ()
const emailData : EmailParams = {
to: 'user@example.com' ,
subject: 'Typed Email' ,
body: 'This email is fully typed!'
}
const result : EmailResponse = await email. send (emailData)
return result
})
The useEmail() composable automatically integrates with the hooks system. All emails sent through useEmail() will trigger registered hooks:
server/plugins/email-hooks.ts
import { emailLayerHooks } from '#layers/email/server/utils/email'
export default defineNitroPlugin ( async ( nitroApp ) => {
// This hook will be called for all useEmail().send() calls
emailLayerHooks. hook ( 'send:before' , ( email , context ) => {
console. log ( `Sending email via ${ context . provider }` )
return email
})
})
Template Rendering : Templates are rendered server-side, which adds processing timeProvider Selection : Provider is selected once per useEmail() call based on runtime configError Handling : Always implement proper error handling to prevent blocking operationsAsync Operations : The send() method is async and should be awaitedAlways handle errors : Wrap send() calls in try-catch blocksValidate input data : Check email addresses and required fields before sendingUse templates for complex emails : Templates are more maintainable than inline HTMLLog email activity : Use hooks or direct logging for audit trailsTest with MailCatcher : Use MailCatcher in development to avoid sending real emails