Skip to main content
Letterly

Documentation

Get up and running with Letterly in minutes.

Quick Start
  • 1. Run pnpm install to install all dependencies
  • 2. Copy .env.example to packages/web/.env.local
  • 3. Run pnpm run dev:web to start on localhost:3000
  • 4. The app runs in demo mode with mock data when DATABASE_URL is not set
Database Setup
  • Letterly stores its data in PostgreSQL through Drizzle ORM (the newsletter schema in packages/db).
  • Set DATABASE_URL in packages/web/.env.local to leave demo mode.
  • Migrations live in packages/db/drizzle.
  • Tables: newsletters, subscribers, campaigns, campaign_emails, segments, profiles.
Stripe Billing
  • Create Stripe products for Starter ($9), Pro ($19), and Growth ($49) plans.
  • Set STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, and STRIPE_PRICE_* env vars.
  • Run stripe listen --forward-to localhost:3000/api/stripe/webhook for local testing.
  • Webhooks handle checkout completion, subscription updates, and cancellations.
AI Features
  • Supports two AI providers: Google Gemini (primary) and Anthropic Claude (fallback).
  • Set GEMINI_API_KEY for Gemini or ANTHROPIC_API_KEY for Claude.
  • Configure provider priority with AI_PRIMARY_PROVIDER and AI_SECONDARY_PROVIDER.
  • AI usage is tracked per user with plan-based limits (Free: 100/mo, Starter: 500, Pro: 2000, Growth: unlimited).
  • The AI route includes rate limiting (10 req/min), input sanitization, and automatic provider fallback.
Email Delivery
  • Set EMAIL_PROVIDER=mailstack plus MAILSTACK_HMAC_SECRET (or legacy MAILSTACK_API_KEY), MAILSTACK_API_URL, and MAILSTACK_FROM_EMAIL for email delivery.
  • The @blueforge-studio/service-email factory selects the adapter; the Mailstack adapter handles batching internally.
  • Campaign HTML is sanitized via DOMPurify before sending.
  • The BullMQ worker handles async email jobs — start with pnpm run dev:worker.
Security
  • All API mutation routes have CSRF/origin verification.
  • Rate limiting is Redis-backed with in-memory fallback.
  • API routes verify newsletter ownership before mutations.
  • CSV exports escape formula-triggering characters to prevent injection.
API Reference
  • POST /api/subscribers/import — CSV file import (auth required)
  • GET /api/subscribers/export — CSV download (auth required)
  • POST /api/ai/subject-lines — AI subject line generation
  • POST /api/campaigns/send — Send campaign via service-email (Mailstack) (auth required)
  • POST /api/stripe/checkout — Create Stripe checkout session for the signed-in account (requires sign-in)
  • POST /api/stripe/webhook — Handle Stripe webhook events (signature verified)

Full source code and README available on GitHub.

Get started free