Skip to main content
Send transactional emails from Cloudflare Workers using Lettr’s HTTP API. Workers run on Cloudflare’s global edge network with instant cold starts and zero-millisecond latency — perfect for email APIs that need to be fast anywhere in the world. Using Cursor? Jump straight in using this prompt

Prerequisites

Before you begin, make sure you have: You’ll also need:
  • Cloudflare account (free tier works)
  • Wrangler CLI installed (npm install -g wrangler)
  • Node.js 18.x or 20.x for local development

Quick Setup

1

Create a new Worker project

npm create cloudflare@latest my-email-worker
cd my-email-worker
When prompted, choose:
  • Type: “Hello World” Worker
  • TypeScript: Yes (recommended)
  • Git: Yes (optional)
  • Deploy: No (we’ll deploy later)
2

Install the Lettr SDK

npm install lettr
The SDK works seamlessly with Workers and provides a clean, type-safe interface.
3

Add your API key as a secret

npx wrangler secret put LETTR_API_KEY
When prompted, paste your Lettr API key (starts with lttr_).
Secrets are encrypted environment variables that are not visible in your code or Wrangler config. They’re perfect for API keys.
4

Deploy your Worker

npm run deploy
Your Worker will be deployed to Cloudflare’s edge network and available at https://my-email-worker.your-subdomain.workers.dev.

Worker Implementation

Create or update src/index.ts:
import { Lettr } from 'lettr';

export interface Env {
  LETTR_API_KEY: string;
  FROM_EMAIL?: string;
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    // Only allow POST requests
    if (request.method !== 'POST') {
      return new Response('Method not allowed', { status: 405 });
    }

    // Initialize Lettr client
    const lettr = new Lettr(env.LETTR_API_KEY);

    try {
      const body = await request.json() as {
        to: string | string[];
        subject: string;
        html?: string;
        text?: string;
      };

      const { to, subject, html, text } = body;

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

      // Send email
      const result = await lettr.emails.send({
        from: 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 Response.json({
        success: true,
        requestId: result.request_id,
        accepted: result.accepted,
      });
    } catch (error: any) {
      console.error('Failed to send email:', error);

      return Response.json(
        { error: error.message || 'Failed to send email' },
        { status: error.status || 500 }
      );
    }
  },
};
Cloudflare Workers use the Env interface to define environment variables and secrets. The Lettr SDK automatically handles retries and provides detailed error messages.

Configuration

Configure your Worker in wrangler.toml:
name = "my-email-worker"
main = "src/index.ts"
compatibility_date = "2024-01-01"

# Non-sensitive environment variables
[vars]
FROM_EMAIL = "noreply@yourdomain.com"

# Secrets (set via wrangler secret put)
# LETTR_API_KEY = "set via CLI"
Never commit API keys to wrangler.toml. Always use wrangler secret put for sensitive values.

What’s Next