Skip to main content
The Nuxt Lettermint module provides server-side utilities for sending emails directly from your API routes, server middleware, and Nitro handlers.

Basic usage

Use the sendEmail() function in any server context:
server/api/send.post.ts
import { sendEmail } from '#imports'

export default defineEventHandler(async () => {
  return await sendEmail({
    from: '[email protected]',
    to: '[email protected]',
    subject: 'Welcome',
    html: '<h1>Welcome!</h1>',
    tags: ['welcome']
  })
})

The sendEmail() function

The sendEmail() function is a convenience wrapper that handles email sending with all available options:
import { sendEmail, type SendEmailOptions } from '#imports'

const result = await sendEmail(options)
Returns:
interface EmailResult {
  message_id: string
  status: string
}

Email options

The sendEmail() function accepts comprehensive email options:
interface SendEmailOptions {
  from: string                    // Sender email address
  to: string | string[]          // Recipient email address(es)
  subject: string                // Email subject
  text?: string                  // Plain text content
  html?: string                  // HTML content
  cc?: string | string[]         // CC recipients
  bcc?: string | string[]        // BCC recipients
  replyTo?: string | string[]    // Reply-to address(es)
  headers?: Record<string, string>  // Custom headers
  metadata?: Record<string, unknown> // Custom metadata
  tags?: string[]                // Tags for categorization
  attachments?: Array<{          // File attachments
    filename: string
    content: string | Buffer
    contentType?: string
  }>
}
All options are validated before sending. Either text or html content is required.

Complete example

Here’s a real example from the module’s playground showing a complete server route:
server/api/server-email-demo.ts
import { defineEventHandler } from 'h3'
import { sendEmail } from '#imports'

export default defineEventHandler(async () => {
  try {
    const result = await sendEmail({
      from: '[email protected]',
      to: '[email protected]',
      subject: 'Server-side Email from Nuxt Lettermint',
      text: 'This email was sent directly from the server using the Lettermint SDK.',
      html: '<h2>Server-side Email</h2><p>This email was sent directly from the server using the <strong>Lettermint SDK</strong>.</p>',
      tags: ['nuxt'],
    })

    return {
      success: true,
      message: 'Email sent from server',
      messageId: result.message_id,
      status: result.status,
    }
  }
  catch (error: unknown) {
    console.error('Server email error:', error)

    const err = error as any
    let errorMessage = 'Failed to send email from server'

    // Extract the actual validation message from Lettermint
    if (err?.responseBody?.message) {
      errorMessage = err.responseBody.message
    }
    else if (err?.message) {
      errorMessage = err.message
    }

    return {
      success: false,
      error: errorMessage,
    }
  }
})

Advanced options

The module supports all Lettermint email features. Here’s an example with all available options:
server/api/full-options.ts
import { sendEmail } from '#imports'

export default defineEventHandler(async () => {
  const result = await sendEmail({
    from: '[email protected]',
    to: '[email protected]',
    cc: '[email protected]',
    bcc: '[email protected]',
    replyTo: '[email protected]',
    subject: 'Test Full Options',
    text: 'Plain text version',
    html: '<h1>HTML version</h1>',
    headers: {
      'X-Custom-Header': 'custom-value',
    },
    metadata: {
      userId: '12345',
      campaign: 'test-campaign',
    },
    tags: ['test', 'full-options'],
    attachments: [
      {
        filename: 'test.txt',
        content: 'Test attachment content',
      },
    ],
  })

  return {
    success: true,
    result,
  }
})

Multiple recipients

Send to multiple recipients by passing arrays:
server/api/newsletter.post.ts
import { sendEmail } from '#imports'

export default defineEventHandler(async () => {
  return await sendEmail({
    from: '[email protected]',
    to: ['[email protected]', '[email protected]'],
    cc: ['[email protected]', '[email protected]'],
    bcc: '[email protected]',
    subject: 'Weekly Newsletter',
    html: '<h1>This Week in Tech</h1>',
    tags: ['newsletter', 'weekly']
  })
})

Error handling

Always wrap sendEmail() calls in try-catch blocks:
import { sendEmail } from '#imports'
import { createError } from 'h3'

export default defineEventHandler(async () => {
  try {
    const result = await sendEmail({
      from: '[email protected]',
      to: '[email protected]',
      subject: 'Hello',
      html: '<h1>Hello</h1>'
    })

    return { success: true, messageId: result.message_id }
  }
  catch (error) {
    throw createError({
      statusCode: 500,
      statusMessage: 'Failed to send email'
    })
  }
})
The Lettermint API returns detailed error messages for validation failures. Always extract and return these messages to help debug issues.

Using with request data

Combine with request body parsing for dynamic email sending:
server/api/contact.post.ts
import { defineEventHandler, readBody, createError } from 'h3'
import { sendEmail } from '#imports'

export default defineEventHandler(async (event) => {
  const { name, email, message } = await readBody(event)

  // Validate input
  if (!name || !email || !message) {
    throw createError({
      statusCode: 400,
      statusMessage: 'Missing required fields'
    })
  }

  // Send email
  const result = await sendEmail({
    from: '[email protected]',
    to: '[email protected]',
    replyTo: email,
    subject: `Contact Form: ${name}`,
    html: `
      <h2>New Contact Form Submission</h2>
      <p><strong>From:</strong> ${name} (${email})</p>
      <p><strong>Message:</strong></p>
      <p>${message}</p>
    `,
    metadata: {
      source: 'contact-form',
      userEmail: email
    },
    tags: ['contact-form']
  })

  return {
    success: true,
    messageId: result.message_id
  }
})

File attachments

Add attachments using base64-encoded content or Buffer:
server/api/send-with-attachment.post.ts
import { sendEmail } from '#imports'
import { readFile } from 'fs/promises'

export default defineEventHandler(async () => {
  // Read file from disk
  const fileBuffer = await readFile('./invoice.pdf')

  return await sendEmail({
    from: '[email protected]',
    to: '[email protected]',
    subject: 'Your Invoice',
    html: '<h1>Invoice Attached</h1><p>Please find your invoice attached.</p>',
    attachments: [
      {
        filename: 'invoice.pdf',
        content: fileBuffer,
        contentType: 'application/pdf'
      }
    ]
  })
})
For base64-encoded strings, you can pass them directly as the content field without converting to Buffer.

Custom headers and metadata

Add custom headers and metadata for tracking and routing:
server/api/campaign.post.ts
import { sendEmail } from '#imports'

export default defineEventHandler(async () => {
  return await sendEmail({
    from: '[email protected]',
    to: '[email protected]',
    subject: 'Special Offer',
    html: '<h1>Limited Time Offer</h1>',
    headers: {
      'X-Campaign-ID': 'spring-2024',
      'X-Email-Type': 'promotional'
    },
    metadata: {
      campaignId: 'spring-2024',
      userId: '67890',
      segmentId: 'premium-users',
      timestamp: new Date().toISOString()
    },
    tags: ['campaign', 'promotional', 'spring-2024']
  })
})

How it works

The sendEmail() function:
  1. Retrieves the Lettermint SDK instance configured with your API key
  2. Converts your options into the Lettermint fluent API format
  3. Handles arrays for recipients, CC, BCC, and reply-to fields
  4. Sends the email via the Lettermint API
  5. Returns the message ID and status
Your API key is securely accessed from runtime config and never exposed to the client.

Next steps

Advanced usage

Use the fluent API for more control

Custom endpoints

Create custom API endpoints with additional logic

Build docs developers (and LLMs) love