Email with Resend
Transactional email with Resend in the Nuxt template.
Transactional email is Integrated through a small provider abstraction.
Verification, password reset, and contact messages all follow the same path:
sendEmail → ResendProvider → localized Vue Email template.
What it provides
- A
MailProviderinterface with templated and raw send methods. - Lazy provider initialization based on
websiteConfig.mail.provider. - Resend delivery using
NUXT_RESEND_API_KEY. - Vue Email rendering with English and Chinese message dictionaries.
- Wired Better Auth verification/reset and contact-form delivery.
- An included newsletter template asset, but no subscription workflow.
Important files
| File | Role |
|---|---|
server/email/types.ts | Template names, provider interface, and send result types |
server/email/index.ts | Provider lifecycle, sendEmail, template/message maps, getTemplate |
server/email/provider/resend.ts | Resend implementation and default sender |
server/email/templates/*.vue | Vue Email transactional templates |
app/components/email/* | Shared email layout and button |
server/utils/auth.ts | Better Auth verification/reset calls |
server/api/contact.post.ts | Validated contact message delivery |
app/config/website-config.ts | Provider, sender, and support address |
Setup
Configure Resend
Create a Resend API key and set it server-side:
NUXT_RESEND_API_KEY=re_your_keyDo not expose it with a NUXT_PUBLIC_ prefix.
Set mail identities
Update websiteConfig.mail.fromEmail to a sender on your verified domain and
supportEmail to the inbox that should receive contact submissions. Keep
provider: "resend" unless you implement another MailProvider.
Verify the domain
Add the DNS records required by Resend and wait for verification. Production
sends must use an allowed From address; an API key alone is not sufficient.
Templates and context
getTemplate() selects a Vue component, injects locale and the matching
en-us.json/zh-cn.json messages, renders HTML with @vue-email/render, and
derives a plain-text fallback. Subjects come from the locale's mail messages.
| Template key | Component | Context supplied by wired flow |
|---|---|---|
verifyEmail | verify-email.vue | url, name |
forgotPassword | forgot-password.vue | url, name |
contactMessage | contact-message.vue | name, email, subject, message |
subscribeNewsletter | subscribe-newsletter.vue | name |
Better Auth calls the first two from server/utils/auth.ts. It currently omits
the optional locale, so verification and reset mail fall back to English.
Pass the user's locale explicitly if those flows must be bilingual. The contact
API Zod-validates its request and sends contactMessage to supportEmail,
passing the form locale when present.
subscribe-newsletter.vue is only a reusable template asset. The starter does
not include a newsletter subscription endpoint, subscriber persistence,
confirmation flow, or unsubscribe handling.
Customize or add a provider
Edit the Vue templates and the mail.* keys in both locale JSON files together.
When adding a new locale, also extend messagesMap in server/email/index.ts.
To replace Resend, implement MailProvider, initialize it in
initializeMailProvider(), and keep the sendEmail() call sites unchanged.
Return structured failures and ensure the provider supports both HTML and text.
Verify
- Register a user and receive the verification email (English by default).
- Request a password reset and confirm the link reaches the reset page.
- Submit
/contact; the configured support inbox receives the message. - Render templates explicitly with both
enandzh; after wiring auth locale, verify both subjects, copy, links, and responsive layout. - Confirm failed sends are visible in application logs and the Resend dashboard.
Production notes
Monitor delivery, bounces, and complaints; add retry or queue semantics if email is business-critical. Avoid logging message bodies or recipients. Configure SPF/DKIM/DMARC, keep verification links on the production base URL, and test sender restrictions before enabling required email verification.
