Notify
Modules send email, such as a sign-in link or a receipt, without choosing an email service. Notify is where your app picks how email, SMS and simple notifications are delivered, per environment. For emails designed with Vue components, add Email Templates on top.
The package is @frigear-nu/notify. In-app toasts are not part of it: use
useToast() from Nuxt UI.
What you get
- Composables and helpers.
- Server functions that send an email, an SMS or a simple notification, auto-imported in Nitro.
- A
logdriver that prints each notification instead of sending it. On by default. - Email drivers for Resend, Amazon SES and Cloudflare Email Service, or a driver file of your own. Opt-in.
- Emails. None of its own. It sends what other modules build.
modules. Auth (server
mode), Users, Forms,
Subscriptions and Email Templates install Notify.
Optional:Email Templates, to render emails from Vue templates.Quick setup
Install the module
pnpm add @frigear-nu/notify
Configure it in nuxt.config.ts
List Notify in modules only to configure it. This setup sends email through Resend and SMS through your own driver:
export default defineNuxtConfig({
modules: ['@frigear-nu/notify'],
notify: {
email: { driver: 'resend' },
sms: { driver: '~/server/utils/twilio-sms-driver' },
simple: { driver: 'log' },
},
})
nuxt.config.ts. Anyone who has them can send email as you.Set the environment variables
Set NUXT_NOTIFY_EMAIL_FROM and the credentials of your email driver, listed under
Environment variables.
log driver, the server console prints [notify] Dispatching notification: and
the notification. With a real driver, the email arrives.Options
Options go under the notify key. Each notification type has its own driver, and only the configured driver is
loaded.
| Option | Type | Default | Purpose |
|---|---|---|---|
email.driver | 'log' | 'resend' | 'ses' | 'cloudflare' | string | 'log' | A built-in name, or a path to a file whose default export is an EmailDriver. |
sms.driver | 'log' | string | 'log' | 'log', or a path to a file whose default export is an SMSDriver. |
simple.driver | 'log' | string | 'log' | 'log', or a path to a file whose default export is a SimpleDriver. |
push.driver | string | none | Reserved. Typed, but not implemented. |
email.driver set to a built-in name only sets the default. NUXT_NOTIFY_EMAIL_DRIVER overrides it at runtime. A
path to a file is fixed at build time.
Environment variables
The built-in email drivers are read from runtimeConfig.notify.email at runtime, so each environment can use another
service without a rebuild. They use plain fetch, with no dependencies. SES requests are signed with AWS Signature
Version 4 through Web Crypto.
| Variable | Used by | Purpose |
|---|---|---|
NUXT_NOTIFY_EMAIL_DRIVER | all | log (default), resend, ses or cloudflare. Any other value throws when sending. |
NUXT_NOTIFY_EMAIL_FROM | resend, ses, cloudflare | The sender, such as Frigear <no-reply@frigear.nu>. |
NUXT_NOTIFY_EMAIL_RESEND_API_TOKEN | resend | API token. |
NUXT_NOTIFY_EMAIL_SES_REGION | ses | AWS region, such as eu-west-1. Uses the SES v2 API. |
NUXT_NOTIFY_EMAIL_SES_ACCESS_KEY_ID | ses | Access key id. |
NUXT_NOTIFY_EMAIL_SES_SECRET_ACCESS_KEY | ses | Secret access key. |
NUXT_NOTIFY_EMAIL_SES_SESSION_TOKEN | ses | Optional, for temporary credentials. |
NUXT_NOTIFY_EMAIL_CLOUDFLARE_ACCOUNT_ID | cloudflare | Cloudflare account id (Email Service). |
NUXT_NOTIFY_EMAIL_CLOUDFLARE_API_TOKEN | cloudflare | API token. |
A missing credential fails the send, with an error that names the variable to set.
Server
The dispatch functions and the definers are auto-imported in server code wherever the module is installed.
| Function | Signature |
|---|---|
dispatchEmailNotification | (notification: EmailNotification) => Promise<void> |
dispatchSMSNotification | (notification: SMSNotification) => Promise<void> |
dispatchSimpleNotification | (notification: SimpleNotification) => Promise<void> |
defineEmailNotification, defineSMSNotification, defineSimpleNotification | Typed helpers that return the notification unchanged. |
defineEmailDriver, defineSMSDriver, defineSimpleDriver | Typed helpers that return the driver unchanged. |
await dispatchEmailNotification({
to: user.email,
subject: 'Welcome!',
body: '<p>Thanks for signing up.</p>',
text: 'Thanks for signing up.',
})
await dispatchSMSNotification({
to: user.phone,
body: 'Your verification code is 123456.',
})
await dispatchSimpleNotification({
title: 'New signup',
text: `${user.email} just signed up.`,
})
Templates
Notify renders no templates itself. dispatchEmailNotification calls the notify:email hook before the driver runs,
where Email Templates renders notification.template. Without a renderer, subject and body are sent as built.
Types
The types are exported from @frigear-nu/notify/types. The package root re-exports the notification, driver and
ModuleOptions types.
interface EmailNotification<M = NotificationMeta> {
to: string | string[]
subject: string
/** HTML body. */
body: string
/** Optional plain-text body. */
text?: string
/** Address replies go to (the `Reply-To` header). */
replyTo?: string
/** Template to render instead of subject/body/text, when a renderer is installed. */
template?: { name: string, props?: Record<string, unknown>, locale?: string }
meta?: M
}
interface SMSNotification<M = NotificationMeta> {
to: string | string[]
body: string
meta?: M
}
interface SimpleNotification<M = Record<string, unknown>> {
title: string
text: string
/** Optional URL to open when the notification is clicked. */
url?: string
meta?: M
}
type NotificationMeta<AdditionalMeta = Record<string, unknown>> = { driver?: string } & AdditionalMeta
type EmailDriver = (notification: EmailNotification) => Promise<void> | void
type SMSDriver = (notification: SMSNotification) => Promise<void> | void
type SimpleDriver = (notification: SimpleNotification) => Promise<void> | void
Custom driver
A driver is a function that delivers one notification. Point the driver option at a file whose default export is that function:
import type { EmailDriver } from '@frigear-nu/notify/types'
const sendWithResend: EmailDriver = async (notification) => {
// call your provider with notification.to / subject / body / text / replyTo
}
export default sendWithResend
Store types
@frigear-nu/notify/types also exports StoredNotification and NotificationStore, a contract with put, get,
list and delete for keeping notifications. Nothing in the module uses a store yet, and dispatch records nothing.
Hooks
A renderer such as Email Templates listens to these hooks.
| Hook | When | Payload |
|---|---|---|
notify:email (Nitro) | An email is about to go to the driver. | { notification }, replaceable |
notify:email:templates (Nuxt) | A renderer collects the template folders that modules ship. | EmailTemplateSource[]: push { dir } |
Next steps
- Email Templates – render your emails from Vue components with your branding.
- Send an email – send your first email from a server route.
- Deployment – set the driver's secrets on your hosting platform.