Back to Home

Building FreeResend

Building FreeResend

A Self-Hosted, Open-Source Alternative to Resend

The Problem: Email Infrastructure Is Expensive

As a solopreneur building multiple SaaS products, I needed reliable transactional email. The options weren't great:

  1. Resend: Beautiful API and DX, but $20/month for 50K emails—adds up fast across multiple products
  2. SendGrid: Enterprise pricing, complex configuration, overkill for transactional use cases
  3. Postmark: Excellent deliverability but expensive per-email pricing
  4. Amazon SES Direct: Dirt cheap ($0.10/1K emails) but raw API, no dashboard, manual DKIM/DMARC setup

I wanted Resend's beautiful API with SES pricing. So I built it.

FreeResend: self-hosted email infrastructure with a 100% Resend-compatible API, running on your own AWS account.

The Vision: Drop-In Resend Replacement

The core principle was simple: change one environment variable, keep everything else the same. If you're using the Resend SDK, switching to FreeResend should be as easy as:

# Before (Resend)
RESEND_API_KEY=re_xxxxx

# After (FreeResend)
RESEND_BASE_URL=https://your-freeresend.com/api
RESEND_API_KEY=frs_xxxxx  # Your FreeResend API key

100% API Compatible

Same endpoints, same request/response format. The Resend SDK works out of the box—just point it at your server.

Your AWS Account

Emails send through your own SES. Full control, full visibility, SES pricing ($0.10/1K emails).

Automatic DKIM Setup

Domain verification and DKIM key generation handled automatically. Integrates with DigitalOcean DNS for zero-touch setup.

Open Source Forever

MIT licensed. Self-host on any platform—Vercel, Docker, Kubernetes. No vendor lock-in.

The Tech Stack: Simple and Production-Ready

Next.js 15 + TypeScript

The latest Next.js with Turbopack for fast development. API routes handle all email operations. TypeScript ensures type safety across the codebase—especially critical when matching Resend's API contract exactly.

PostgreSQL + Direct SQL

Chose raw SQL over Prisma for this project. The schema is simple (users, domains, api_keys, email_logs, webhook_events), and direct pg queries give full control. No ORM overhead, easy to understand what's happening at the database level.

AWS SDK v3 for SES

The modular AWS SDK v3 keeps bundle size small. Only import what you need: @aws-sdk/client-ses for email operations. Full support for DKIM verification, domain identity management, and both simple and raw email sending.

DigitalOcean DNS API (Optional)

If your domains are on DigitalOcean, FreeResend automatically creates all required DNS records—TXT for domain verification, CNAME for DKIM, MX, SPF, and DMARC. Zero manual DNS configuration. For other providers, records are displayed for manual setup.

JWT + bcrypt for Auth

Simple, secure authentication. Admin credentials stored with bcrypt hashing. JWT tokens for API access. API keys are hashed before storage—even if the database leaks, keys remain secure.

The Architecture: Resend API Contract

The key architectural decision: match Resend's API exactly. This means existing codebases using the Resend SDK work without modification.

API Endpoint Structure

POST /api/emails → Send email (Resend-compatible) GET /api/emails/{id} → Get email details GET /api/emails/logs → List email logs POST /api/domains → Add domain for verification GET /api/domains → List all domains POST /api/domains/{id}/verify → Check domain verification status DELETE /api/domains/{id} → Remove domain POST /api/api-keys → Generate new API key GET /api/api-keys → List API keys (masked) DELETE /api/api-keys/{id} → Revoke API key POST /api/webhooks/ses → SES SNS webhook endpoint

Email Sending Flow

When an email is sent through FreeResend:

  1. API Key Validation: Extract key from Authorization: Bearer header, verify against hashed keys in database
  2. Domain Check: Ensure sender domain is verified and associated with the API key
  3. Payload Validation: Zod schema validates request body matches Resend's expected format
  4. SES Send: Call AWS SES SendEmail or SendRawEmail based on content type
  5. Log Creation: Store email metadata in email_logs table with SES message ID
  6. Response: Return Resend-compatible response with { id: messageId }
// Resend SDK works unchanged
import { Resend } from 'resend';

const resend = new Resend('frs_your_api_key');

const { data, error } = await resend.emails.send({
  from: 'onboarding@yourdomain.com',
  to: ['user@example.com'],
  subject: 'Hello World',
  html: '<strong>It works!</strong>'
});

Domain Verification: The Hard Part Made Easy

Email deliverability depends on proper DNS configuration. Most developers dread setting up DKIM, SPF, and DMARC. FreeResend automates all of it.

What Gets Created

When you add a domain, FreeResend:

  • TXT Record: _amazonses.yourdomain.com for SES domain verification
  • 3 CNAME Records: *._domainkey.yourdomain.com for DKIM signatures
  • MX Record: For receiving bounce notifications via SES
  • SPF Record: Declares SES as authorized sender
  • DMARC Record: Policy for handling authentication failures

Automatic DNS with DigitalOcean

If you provide a DigitalOcean API token, FreeResend creates all DNS records automatically:

// lib/digitalocean.ts
async function createDNSRecords(domain: string, records: DNSRecord[]) {
  for (const record of records) {
    await fetch(`https://api.digitalocean.com/v2/domains/${domain}/records`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.DO_API_TOKEN}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        type: record.type,
        name: record.name,
        data: record.value,
        ttl: 1800
      })
    });
  }
}

For other DNS providers, the dashboard displays all required records with copy buttons. Manual setup takes 5 minutes.

API Key Security: Never Store Plain Text

API keys are sensitive. A database leak shouldn't expose them. FreeResend uses a secure key generation pattern:

Key Structure

// Format: frs_{keyId}_{secretPart}
// Example: frs_abc123_xYz789defGHI...

const keyId = nanoid(6);        // Public identifier
const secretPart = nanoid(32);  // Secret portion
const fullKey = `frs_${keyId}_${secretPart}`;

// Only store the hash
const keyHash = await bcrypt.hash(secretPart, 10);

await db.query(
  'INSERT INTO api_keys (id, key_hash, domain_id) VALUES ($1, $2, $3)',
  [keyId, keyHash, domainId]
);

// Return full key ONCE - never stored in plain text
return { apiKey: fullKey };

Validation Flow

When validating an API key:

  1. Parse the key: extract keyId and secretPart
  2. Look up record by keyId (fast index lookup)
  3. Compare secretPart against stored hash with bcrypt
  4. Return associated domain if valid

This pattern means: even if an attacker gets database access, they can't use the API keys. They'd need to crack bcrypt hashes first.

SES Webhooks: Real-Time Delivery Tracking

SES provides delivery notifications via SNS (Simple Notification Service). FreeResend captures these for email tracking:

  • Delivery: Email accepted by recipient's mail server
  • Bounce: Hard bounce (invalid email) or soft bounce (mailbox full)
  • Complaint: Recipient marked email as spam
  • Open: Email opened (if tracking pixel enabled)
  • Click: Link clicked (if link tracking enabled)
// /api/webhooks/ses/route.ts
export async function POST(request: Request) {
  const body = await request.json();
  
  // Handle SNS subscription confirmation
  if (body.Type === 'SubscriptionConfirmation') {
    await fetch(body.SubscribeURL);
    return NextResponse.json({ status: 'confirmed' });
  }
  
  // Parse notification
  const message = JSON.parse(body.Message);
  const { notificationType, mail } = message;
  
  // Update email log status
  await db.query(
    'UPDATE email_logs SET status = $1, updated_at = NOW() WHERE ses_message_id = $2',
    [notificationType.toLowerCase(), mail.messageId]
  );
  
  // Store webhook event for debugging
  await db.query(
    'INSERT INTO webhook_events (type, payload) VALUES ($1, $2)',
    [notificationType, JSON.stringify(message)]
  );
  
  return NextResponse.json({ received: true });
}

The Dashboard: Everything You Need

FreeResend includes a full admin dashboard for managing your email infrastructure:

Domain Management

  • • Add/remove sending domains
  • • View verification status
  • • See required DNS records
  • • One-click verification check

API Key Management

  • • Generate keys per domain
  • • View masked key list
  • • Revoke compromised keys
  • • Copy key on creation

Email Logs

  • • Full send history
  • • Delivery status tracking
  • • Bounce/complaint alerts
  • • Search and filter

Webhook Events

  • • SES event log
  • • Delivery confirmations
  • • Bounce details
  • • Debug payload viewer

The Challenges and Solutions

1. Matching Resend's API Contract

The Resend SDK expects specific response formats. I used Zod schemas to validate both incoming requests and outgoing responses match exactly. Any deviation breaks SDK compatibility. Extensive testing with real Resend SDK calls ensures parity.

2. DKIM Key Retrieval from SES

When you verify a domain with SES, it generates DKIM keys. But there's a race condition: callingGetIdentityDkimAttributes immediately afterVerifyDomainDkim returns empty tokens. Solution: retry with exponential backoff until tokens are available.

3. SNS Webhook Security

Anyone could POST fake webhook events to the endpoint. AWS signs SNS messages with a certificate. FreeResend validates the signature before processing. Additionally, message IDs are checked against known SES message IDs to prevent injection attacks.

4. API Key Display UX

API keys can only be shown once (we don't store plain text). Users were copying the masked version from the table instead of the full key shown on creation. Solution: prominent green success message with the full key, copy button, and clear warning that it won't be shown again.

The Results: Enterprise Email at SES Prices

Using Resend

  • • Free tier: 3,000 emails/month
  • • Pro: $20/month for 50K emails
  • • Scale: $80/month for 100K emails
  • Per project cost adds up fast

Using FreeResend + SES

  • • SES: $0.10 per 1,000 emails
  • • 50K emails: $5/month
  • • 100K emails: $10/month
  • Same API, 75-90% cost reduction

For 10 products sending 10K emails each: $200/mo with Resend vs $10/mo with FreeResend

Feature Parity with Resend

Send email via API
Resend SDK compatibility
Domain verification
Automatic DKIM setup
API key management
Email logging
Webhook notifications
Bounce handling
HTML and plain text support
Attachments support
Reply-to headers
Custom headers

Technical Highlights

Next.js 15 with Turbopack
TypeScript throughout
PostgreSQL with raw SQL
AWS SDK v3 for SES integration
bcrypt for API key hashing
JWT for authentication
Zod for validation
DigitalOcean API for DNS automation
Docker ready for self-hosting
MIT licensed open source

Deployment Options

FreeResend is designed for flexible deployment:

Vercel

One-click deploy. Connect repo, set environment variables, done. Serverless functions handle all API routes.

Docker

Dockerfile included. Run anywhere Docker runs—your VPS, AWS ECS, Google Cloud Run, or home server.

Kubernetes

Production-grade deployment with horizontal scaling, health checks, and rolling updates.

Conclusion: Own Your Email Infrastructure

FreeResend proves you don't need to choose between great developer experience and cost efficiency. By leveraging AWS SES as the delivery backbone and matching Resend's API exactly, you get:

  • Drop-in replacement: Existing Resend SDK code works unchanged
  • 90% cost reduction: SES pricing vs SaaS email services
  • Full control: Your AWS account, your data, your infrastructure
  • Open source: Inspect, modify, contribute—it's your code now

For solopreneurs and teams running multiple products, the savings compound quickly. And when you own the infrastructure, you never worry about API pricing changes or service shutdowns.

Email is critical infrastructure. Now you can own it completely.

Complete Tech Stack

Frontend: Next.js 15, React 19, TypeScript, Tailwind CSS, Lucide Icons

Backend: Next.js API Routes, PostgreSQL, JWT Authentication

Email: AWS SES (SendEmail, SendRawEmail), SNS Webhooks, DKIM/SPF/DMARC

DNS: DigitalOcean API (optional), Manual setup for other providers

Security: bcrypt for key hashing, Zod for validation, SNS signature verification

Deployment: Docker, Vercel, Kubernetes-ready

Ready to Own Your Email Infrastructure?

FreeResend is open source and ready to deploy. Check out the repo, star it, or reach out if you need help with custom email infrastructure.