Email delivery
Configure email mailers, templates, and notification events for authentication flows.
The plugin sends transactional emails for signup, sign-in, email verification, and password reset. Configure a mailer, customize templates per event, or disable specific notifications entirely.
Emails only send when emails.mailer is configured. Without it, all email notifications are silently skipped.
Setting up Resend
The plugin ships a first-party Resend integration:
import { createResendMailer } from '@robojs/auth/emails'
import type { AuthPluginOptions } from '@robojs/auth'
export default <AuthPluginOptions>{
secret: process.env.AUTH_SECRET,
emails: {
from: { name: 'My App', address: 'noreply@myapp.com' },
mailer: createResendMailer({
apiKey: process.env.RESEND_API_KEY!
})
}
}import { createResendMailer } from '@robojs/auth/emails'
export default {
secret: process.env.AUTH_SECRET,
emails: {
from: { name: 'My App', address: 'noreply@myapp.com' },
mailer: createResendMailer({
apiKey: process.env.RESEND_API_KEY!
})
}
}Requires the resend npm package installed in your project.
Mailer options
Three ways to provide a mailer.
Direct instance:
import { createResendMailer } from '@robojs/auth/emails'
emails: {
mailer: createResendMailer({ apiKey: '...' })
}import { createResendMailer } from '@robojs/auth/emails'
emails: {
mailer: createResendMailer({ apiKey: '...' })
}Lazy factory:
emails: {
mailer: async () => {
const { createResendMailer } = await import('@robojs/auth/emails')
return createResendMailer({ apiKey: process.env.RESEND_API_KEY! })
}
}emails: {
mailer: async () => {
const { createResendMailer } = await import('@robojs/auth/emails')
return createResendMailer({ apiKey: process.env.RESEND_API_KEY! })
}
}Module spec (auto-imported at runtime):
emails: {
mailer: { module: 'resend', export: 'Resend' }
}emails: {
mailer: { module: 'resend', export: 'Resend' }
}If the mailer implements verify(), it's called during startup to validate the connection.
Custom mailer
Implement the AuthMailer interface:
import type { AuthMailer, MailMessage } from '@robojs/auth'
const customMailer: AuthMailer = {
async send(message: MailMessage) {
await myEmailService.send({
to: typeof message.to === 'string' ? message.to : message.to.address,
from: message.from,
subject: message.subject,
html: message.html,
text: message.text
})
}
}
export default <AuthPluginOptions>{
emails: { mailer: customMailer }
}
const customMailer = {
async send(message) {
await myEmailService.send({
to: typeof message.to === 'string' ? message.to : message.to.address,
from: message.from,
subject: message.subject,
html: message.html,
text: message.text
})
}
}
export default {
emails: { mailer: customMailer }
}Email events
Six events trigger emails automatically:
| Event | When it fires | Default template |
|---|---|---|
user:created | After signup | Welcome email |
session:created | On new sign-in (non-new users only) | Sign-in notification |
email:verification-requested | When verification token is generated | Verification link |
email:verified | After email is confirmed | Confirmation notice |
password:reset-requested | When reset token is generated | Reset link |
password:reset-completed | After password is changed | Completion notice |
Template overrides
Override templates per event:
emails: {
templates: {
'user:created': {
subject: (ctx) => `Welcome to ${ctx.appName}`,
text: (ctx) => `Hi ${ctx.user.name ?? 'there'}, thanks for signing up.`,
html: (ctx) => `<h1>Welcome</h1><p>Hi ${ctx.user.name ?? 'there'}</p>`
},
'session:created': false, // disable login alerts
'email:verified': false // disable verification confirmation
}
}emails: {
templates: {
'user:created': {
subject: (ctx) => `Welcome to ${ctx.appName}`,
text: (ctx) => `Hi ${ctx.user.name ?? 'there'}, thanks for signing up.`,
html: (ctx) => `<h1>Welcome</h1><p>Hi ${ctx.user.name ?? 'there'}</p>`
},
'session:created': false, // disable login alerts
'email:verified': false // disable verification confirmation
}
}Set a template to false to suppress that event.
EmailContext
Every template and trigger receives an EmailContext:
| Field | Type | Description |
|---|---|---|
appName | string | Plugin's appName config value |
user.id | string | User ID |
user.email | string | null | User email |
user.name | string | null | User display name |
session.id | string | null | Session ID |
session.ip | string | null | Client IP address |
session.userAgent | string | null | Client user agent |
tokens.verifyEmail | string | undefined | Raw verification token |
tokens.resetPassword | string | undefined | Raw reset token |
request.origin | string | null | Request origin |
links.verifyEmail | string | undefined | Full verification URL |
links.resetPassword | string | undefined | Full reset URL |
Custom triggers
Triggers are builder functions that run for specific events:
emails: {
triggers: {
'password:reset-requested': async (ctx) => ({
to: ctx.user.email!,
subject: 'Password Reset',
html: `<p>Reset your password: <a href="${ctx.links?.resetPassword}">Click here</a></p>`
}),
'user:created': [
async (ctx) => {
await trackSignup(ctx.user.id)
return null // returning null skips sending from this builder
},
(ctx) => ({
to: ctx.user.email!,
subject: 'Welcome',
html: '<p>Welcome aboard.</p>'
})
]
}
}emails: {
triggers: {
'password:reset-requested': async (ctx) => ({
to: ctx.user.email!,
subject: 'Password Reset',
html: `<p>Reset your password: <a href="${ctx.links?.resetPassword}">Click here</a></p>`
}),
'user:created': [
async (ctx) => {
await trackSignup(ctx.user.id)
return null // returning null skips sending from this builder
},
(ctx) => ({
to: ctx.user.email!,
subject: 'Welcome',
html: '<p>Welcome aboard.</p>'
})
]
}
}Triggers can be arrays. Each builder runs sequentially. Return null to skip sending. If both a trigger and a template exist for an event, triggers run first, then the template.
React Email templates
Use React components for rich templates:
import type { AuthPluginOptions } from '@robojs/auth'
export default <AuthPluginOptions>{
emails: {
mailer: createResendMailer({ apiKey: '...' }),
templates: {
'password:reset-requested': {
subject: (ctx) => `Reset your ${ctx.appName} password`,
react: (ctx) => <ResetEmail link={ctx.links?.resetPassword} user={ctx.user} />
}
}
}
}
export default {
emails: {
mailer: createResendMailer({ apiKey: '...' }),
templates: {
'password:reset-requested': {
subject: (ctx) => `Reset your ${ctx.appName} password`,
react: (ctx) => <ResetEmail link={ctx.links?.resetPassword} user={ctx.user} />
}
}
}
}Requires @react-email/components peer dependency. Templates render via react-dom/server.
Provider templates
Use provider-driven templates (e.g., Resend template IDs):
templates: {
'user:created': {
templateId: 'tmpl_welcome_123',
variables: (ctx) => ({
name: ctx.user.name,
verifyLink: ctx.links?.verifyEmail
})
}
}templates: {
'user:created': {
templateId: 'tmpl_welcome_123',
variables: (ctx) => ({
name: ctx.user.name,
verifyLink: ctx.links?.verifyEmail
})
}
}