Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.lettr.com/llms.txt

Use this file to discover all available pages before exploring further.

Send transactional emails from Vercel serverless functions using Lettr’s HTTP API. Vercel’s global edge network and fast cold starts make it perfect for email-triggered API routes and server actions. Using Cursor? Jump straight in using this prompt

Prerequisites

Before you begin, make sure you have:

API Key

Create an API key in the Lettr dashboard

Verified Domain

Add and verify your sending domain
You’ll also need:
  • Vercel account with a project deployed or ready to deploy
  • Next.js project (recommended) or a Node.js serverless function
  • Node.js 18.x or 20.x runtime

Quick Setup

1

Install the Lettr SDK

npm install lettr
The SDK provides a clean interface for sending emails with full TypeScript support.
2

Add environment variables

Add your API key via the Vercel dashboard or CLI:
vercel env add LETTR_API_KEY
When prompted, paste your API key (starts with lttr_). Then add your from email:
vercel env add FROM_EMAIL
For local development, create a .env.local file with the same variables. Vercel automatically loads .env.local in development mode.
3

Create an API route

Create a file at app/api/send/route.ts (App Router) or pages/api/send.ts (Pages Router) with the code examples below.
4

Deploy

vercel deploy
Your email API route will be available at https://your-domain.vercel.app/api/send.
For Next.js 13+ projects using the App Router, create a file at app/api/send/route.ts:
import { NextResponse } from 'next/server';
import { Lettr } from 'lettr';

const lettr = new Lettr(process.env.LETTR_API_KEY!);

export async function POST(request: Request) {
  try {
    const body = await request.json();
    const { to, subject, html, text } = body;

    // Validate required fields
    if (!to || !subject || (!html && !text)) {
      return NextResponse.json(
        { error: 'Missing required fields: to, subject, and html or text' },
        { status: 400 }
      );
    }

    // Send email via Lettr
    const result = await lettr.emails.send({
      from: process.env.FROM_EMAIL || 'noreply@yourdomain.com',
      to: Array.isArray(to) ? to : [to],
      subject,
      html,
      text,
    });

    console.log(`Email sent successfully. Request ID: ${result.request_id}`);

    return NextResponse.json({
      success: true,
      requestId: result.request_id,
      accepted: result.accepted,
    });
  } catch (error: any) {
    console.error('Failed to send email:', error);

    return NextResponse.json(
      { error: error.message || 'Failed to send email' },
      { status: error.status || 500 }
    );
  }
}

// Configure function execution
export const maxDuration = 30; // Max duration in seconds (Pro plan and higher)
The maxDuration export configures the maximum execution time for the function. Email sending typically completes in under 1 second, but setting a higher limit accounts for retries and network latency.

Next.js Pages Router

For Next.js projects using the Pages Router, create a file at pages/api/send.ts:
import type { NextApiRequest, NextApiResponse } from 'next';
import { Lettr } from 'lettr';

const lettr = new Lettr(process.env.LETTR_API_KEY!);

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  // Only allow POST requests
  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method not allowed' });
  }

  try {
    const { to, subject, html, text } = req.body;

    // Validate required fields
    if (!to || !subject || (!html && !text)) {
      return res.status(400).json({
        error: 'Missing required fields: to, subject, and html or text',
      });
    }

    // Send email
    const result = await lettr.emails.send({
      from: process.env.FROM_EMAIL || 'noreply@yourdomain.com',
      to: Array.isArray(to) ? to : [to],
      subject,
      html,
      text,
    });

    console.log(`Email sent. Request ID: ${result.request_id}`);

    res.status(200).json({
      success: true,
      requestId: result.request_id,
      accepted: result.accepted,
    });
  } catch (error: any) {
    console.error('Email send failed:', error);

    res.status(error.status || 500).json({
      error: error.message || 'Internal server error',
    });
  }
}

// Configure function execution
export const config = {
  maxDuration: 30,
};

What’s Next

Advanced Guide

Learn about Server Actions, Edge Runtime, and advanced patterns

AWS Lambda

Deploy on AWS Lambda

Cloudflare Workers

Deploy on Cloudflare

API Reference

Complete API documentation