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: sendEmailResendProvider → localized Vue Email template.

What it provides

  • A MailProvider interface 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

FileRole
server/email/types.tsTemplate names, provider interface, and send result types
server/email/index.tsProvider lifecycle, sendEmail, template/message maps, getTemplate
server/email/provider/resend.tsResend implementation and default sender
server/email/templates/*.vueVue Email transactional templates
app/components/email/*Shared email layout and button
server/utils/auth.tsBetter Auth verification/reset calls
server/api/contact.post.tsValidated contact message delivery
app/config/website-config.tsProvider, sender, and support address

Setup

Configure Resend

Create a Resend API key and set it server-side:

NUXT_RESEND_API_KEY=re_your_key

Do 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 keyComponentContext supplied by wired flow
verifyEmailverify-email.vueurl, name
forgotPasswordforgot-password.vueurl, name
contactMessagecontact-message.vuename, email, subject, message
subscribeNewslettersubscribe-newsletter.vuename

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 en and zh; 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.

On this page