Features

Email

Email infrastructure with Vue Email templates and Resend delivery

Email

Status: Stable ✅

The Email feature provides server-side email utilities and client-side flow components for verification, magic links, password resets, and team invitations. Works standalone or integrates with @fyit/crouton-auth.

Enable

The email feature is included in the core @fyit/crouton package. Ensure it is in your extends:

// nuxt.config.ts
export default defineNuxtConfig({
  extends: ['@fyit/crouton']
})

Environment Variables

# Required
RESEND_API_KEY=re_xxx

# Optional (can be set in nuxt.config.ts)
EMAIL_FROM=noreply@example.com
EMAIL_FROM_NAME=My App
EMAIL_REPLY_TO=support@example.com

Configuration

// nuxt.config.ts
export default defineNuxtConfig({
  extends: ['@fyit/crouton'],

  runtimeConfig: {
    email: {
      resendApiKey: process.env.RESEND_API_KEY,
      from: 'noreply@example.com',
      fromName: 'My App',
      replyTo: 'support@example.com'
    },
    public: {
      crouton: {
        email: {
          brand: {
            name: 'My App',
            logoUrl: 'https://example.com/logo.png',
            primaryColor: '#0F766E',
            url: 'https://example.com'
          },
          verification: {
            codeLength: 6,
            codeExpiry: 10, // minutes
            resendCooldown: 60 // seconds
          },
          magicLink: {
            expiry: 10, // minutes
            resendCooldown: 60 // seconds
          }
        }
      }
    }
  }
})

Server Utilities

Email Service

import { useEmailService } from '#crouton-email/server/utils/email'

const emailService = useEmailService()

// Send raw email
const result = await emailService.send({
  to: 'user@example.com',
  subject: 'Hello',
  html: '<p>Hello World</p>'
})

Convenience Senders

import {
  sendVerificationEmail,
  sendMagicLink,
  sendPasswordReset,
  sendTeamInvite,
  sendWelcome
} from '#crouton-email/server/utils/senders'

// Send verification code email
await sendVerificationEmail({
  to: 'user@example.com',
  code: '123456',
  name: 'John'
})

// Send magic link
await sendMagicLink({
  to: 'user@example.com',
  link: 'https://app.com/auth/magic?token=xxx',
  name: 'John'
})

// Send password reset
await sendPasswordReset({
  to: 'user@example.com',
  link: 'https://app.com/auth/reset?token=xxx',
  name: 'John'
})

// Send team invitation
await sendTeamInvite({
  to: 'user@example.com',
  link: 'https://app.com/invite/accept?token=xxx',
  inviterName: 'Jane',
  teamName: 'Acme Inc',
  role: 'member'
})

// Send welcome email
await sendWelcome({
  to: 'user@example.com',
  name: 'John',
  getStartedLink: 'https://app.com/getting-started'
})

Client Components

EmailVerificationFlow

Complete verification code input flow with resend functionality.

<template>
  <EmailVerificationFlow
    :email="userEmail"
    @verified="handleVerified"
    @resend="handleResend"
    @error="handleError"
  />
</template>
PropTypeDefaultDescription
emailstringrequiredEmail being verified
codeLengthnumber6Code length
resendCooldownnumber60Cooldown in seconds
loadingbooleanfalseLoading state while verifying
errorstring''External error message
EventPayloadDescription
verifiedcode: stringCode entered
resend-Resend requested
errorerror: stringError occurred

EmailMagicLinkSent

"Check your email" message with resend option.

<template>
  <EmailMagicLinkSent
    :email="userEmail"
    @resend="handleResend"
    @change-email="handleChangeEmail"
  />
</template>
PropTypeDefaultDescription
emailstringrequiredEmail where link was sent
resendCooldownnumber60Cooldown in seconds
loadingbooleanfalseLoading state while resending
errorstring''External error message

EmailResendButton

Timer-based resend button with cooldown.

<template>
  <EmailResendButton
    :cooldown="60"
    :loading="isResending"
    @resend="handleResend"
  />
</template>

EmailInput

Email input with validation.

<template>
  <EmailInput
    v-model="email"
    :error="emailError"
    placeholder="Enter your email"
  />
</template>

Email Templates

Built-in Vue Email templates:

TemplatePurposeProps
BaseLayout.vueShared layoutbrandName, logoUrl, primaryColor
Verification.vueVerification codecode, name, expiryMinutes
MagicLink.vueMagic link loginlink, name, expiryMinutes
PasswordReset.vuePassword resetlink, name, expiryMinutes
TeamInvite.vueTeam invitationlink, inviterName, teamName, role
Welcome.vueWelcome emailname, getStartedLink

Integration with Auth

When using with @fyit/crouton-auth, the auth package automatically uses email utilities for:

  • Email verification on signup
  • Magic link authentication
  • Password reset emails
  • Team invitation emails
export default defineNuxtConfig({
  extends: ['@fyit/crouton']
  // Email config will be used automatically by auth
})

Standalone Usage

Works without auth. Implement your own endpoints:

// server/api/auth/verify.post.ts
export default defineEventHandler(async (event) => {
  const { email } = await readBody(event)

  // Generate your verification code
  const code = generateCode()

  // Save code to your database
  await saveVerificationCode(email, code)

  // Send email using crouton-email
  const { sendVerificationEmail } = await import('#crouton-email/server/utils/senders')
  await sendVerificationEmail({ to: email, code })

  return { success: true }
})

Custom Templates

Create your own templates:

  1. Create template in server/emails/MyEmail.vue
  2. Use the BaseLayout component for consistent styling
  3. Import and use your template in sender functions
<!-- server/emails/OrderConfirmation.vue -->
<script setup lang="ts">
// Note: This path works via filesystem resolution but is not an explicit
// package.json export of @fyit/crouton-email. It relies on the layer's
// file structure being accessible at build time.
import BaseLayout from '@fyit/crouton-email/server/emails/BaseLayout.vue'

defineProps<{
  orderNumber: string
  items: Array<{ name: string; price: number }>
  total: number
}>()
</script>

<template>
  <BaseLayout brand-name="My Store">
    <h1>Order Confirmed!</h1>
    <p>Order #{{ orderNumber }}</p>
    <!-- ... -->
  </BaseLayout>
</template>

Testing Emails

Use Resend's test mode:

# Use Resend's test API key for development
RESEND_API_KEY=re_test_xxx

Use Cases

  • Authentication flows: Verification codes, magic links, password resets
  • Team management: Invitations, role changes, notifications
  • Transactional emails: Order confirmations, receipts, updates
  • User engagement: Welcome emails, onboarding sequences