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:
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
Install the Lettr SDK
The SDK provides a clean interface for sending emails with full TypeScript support. 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.
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.
Deploy
Your email API route will be available at https://your-domain.vercel.app/api/send.
Next.js App Router (Recommended)
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