How I helped my org cut email costs by 87%

Migrating from Resend to a custom-built email platform on AWS SES, Next.js, SQS, and PostgreSQL, designed and shipped with AI assistance.

PrathmeshMay 20268 min readEngineering, Cost Optimization

Cost reduction

87%

Per 1,000 emails

$0.10

Build and ship

4 wks

The problem

Our organization was sending a mix of transactional and marketing emails through Resend. Password resets, welcome sequences, course enrollment confirmations, digest emails. The product was growing, and with it, the email bill.

Resend is a genuinely good product. Clean API, React Email integration, excellent developer experience. But as our monthly volume crossed the 100k mark, we were sitting on the Scale plan at $90 per month, heading toward the $160 and $250 tiers. For the volume we were sending, the per-email math stopped making sense.

At 100,000 emails per month, Resend costs $90. AWS SES costs $10. That $80 gap compounds to nearly $1,000 per year at a single volume tier, and we were growing fast.

The conversation in our team shifted from “which plan do we upgrade to” to “why are we paying a platform tax for something we could own.” That question became my project.

The old setup

Before the migration, the email stack was simple: every part of the application called Resend's SDK directly, passing HTML or React Email templates. No queue, no retry logic, no centralized tracking. It worked fine at small scale. At higher volume, we started seeing the limitations.

  • No control over send rate or queue depth during traffic spikes
  • Bounce and complaint webhooks were handled inconsistently
  • Zero visibility into delivery status across every send
  • Template management scattered across codebases
  • Monthly cost scaling linearly with Resend's tier structure

The new architecture

I designed and built a centralized internal email platform with four components: SES for delivery, SQS for queueing, Next.js for the API and admin interface, and PostgreSQL (via Prisma) for state, tracking, and suppression management.

  • AWS SES: Delivery engine. $0.10 per 1,000 emails. Handles DKIM, SPF, dedicated sending identity.
  • AWS SQS: Message queue with FIFO support. Decouples producers from the delivery worker, enables retry and rate control.
  • Next.js API: Internal API for enqueue, template rendering, webhook ingestion, and an admin dashboard.
  • PostgreSQL: Tracks send events, delivery status, bounces, complaints, and suppression lists via Prisma ORM.

How it flows

Any service in our product (course platform, auth, notifications) calls a single internal API endpoint to send an email. That request is validated, the email is rendered server-side using our template engine, and a job is pushed to SQS. A worker process polls SQS, calls SES, and writes the result to PostgreSQL.

SES bounce and complaint notifications flow back through SNS into a webhook endpoint, which updates our suppression list and delivery records in the database.

Simplified send API (Next.js route)

POST /api/email/send
{
  "to": "user@example.com",
  "template": "course-enrolled",
  "data": { "courseName": "Intro to AI", "userName": "Prathmesh" },
  "type": "transactional" // or "marketing"
}

Worker polls SQS, calls SES, records result

const result = await ses.sendEmail({
  Source: process.env.FROM_EMAIL,
  Destination: { ToAddresses: [job.to] },
  Message: {
    Subject: { Data: rendered.subject },
    Body: { Html: { Data: rendered.html } }
  }
});

await db.emailLog.create({
  data: {
    messageId: result.MessageId,
    to: job.to,
    template: job.template,
    status: "sent",
    sentAt: new Date()
  }
});

Suppression and bounce handling

One thing Resend handles for you automatically is bounce and complaint suppression. On SES, you own this. We built a simple suppression table in PostgreSQL. Every bounce and complaint event from SNS hits our webhook, which writes the address to a suppressed_emails table. Every send request checks this table before enqueuing. Hard bounces are permanent, soft bounces after three failures are added too.

Template management

Templates are stored as TypeScript files, rendered using a lightweight custom renderer. No external template service, no drag-and-drop builder. Developers define the template schema with Zod, and the API validates the data payload before rendering. This keeps templates version-controlled alongside the codebase and eliminates an entire category of runtime errors.

How AI accelerated the build

I used AI throughout the design and implementation. Not just for code generation, but for system design reasoning, API schema design, edge case discovery, and writing the internal documentation.

  • Generating the Prisma schema for email logs, suppression lists, and bounce events with proper indexing for delivery status queries
  • Writing the SQS polling worker with exponential backoff, dead-letter queue handling, and graceful shutdown logic
  • Designing the SNS webhook verification flow to ensure only genuine AWS notifications are accepted
  • Drafting the internal API contract with Zod schemas, including union types for transactional versus marketing email payloads
  • Producing the system design document used to get team alignment before writing any code

The result was a four-week build that delivered a production-grade internal platform. Without AI assistance on the boilerplate, infrastructure scaffolding, and documentation, a realistic estimate would have been eight to ten weeks for the same scope.

The cost comparison

Volume (emails/mo)Resend (before)SES platform (after)Monthly savings
50,000$20.00$5.00$15
100,000$90.00$10.00$80
250,000$160.00$25.00$135
500,000~$400.00~$50.00~$350
1,000,000~$700.00~$100.00~$600

At our current volume of 150,000 emails per month: we moved from roughly $120/month on Resend to approximately $15 on SES, saving over $1,200 per year. As volume grows, that gap widens significantly.

The SES numbers above include only the per-email charge. Even adding attachment data transfer (we have minimal attachments) and the SNS notification costs, the total stays well under $20 per month at our current volume.

What the migration involved

Week 1

System design and AWS setup

Designed the architecture, set up SES domain verification, DKIM, and SPF records. Created SQS queues with dead-letter configuration. Drafted Prisma schema for email state tracking.

Week 2

Core API and worker build

Built the internal Next.js API routes for send, status, and webhook ingestion. Implemented the SQS polling worker with retry logic. Wired SNS notifications to the suppression table.

Week 3

Template migration and admin UI

Migrated all email templates from Resend/React Email format to our internal renderer. Built a lightweight admin dashboard to view send logs, delivery rates, bounces, and suppression list management.

Week 4

Staging tests and production cutover

Ran parallel sending in staging, validated delivery rates and bounce handling. Cutover production traffic with a feature flag. Monitored for 48 hours before decommissioning Resend subscription.

Tradeoffs worth knowing

  • You own deliverability. Reputation management, bounce rate monitoring, and suppression hygiene are your responsibility.
  • Setup complexity is higher. DNS configuration, IAM roles, SNS topics, SQS queues, and VPC routing if you need it.
  • No built-in template builder. If your marketing team needs a drag-and-drop interface, you must build or integrate one.
  • Support is AWS support. Resend has fast, developer-friendly support, AWS depends on your plan tier.

For a team with engineering capacity and volumes above 50,000 emails per month, the economics become compelling enough to absorb these tradeoffs. Below that volume, the build cost may outweigh the savings.

What I would do differently

If I were starting this project again, I would spend more time upfront on the admin observability layer. The core send pipeline was solid from day one, but the dashboard for visualizing delivery rates and bounce trends by template was an afterthought.

I would also set up dedicated sending IPs earlier. We started on shared pools, which is fine for transactional email, but for marketing sends at scale, a dedicated IP with a proper warmup schedule gives you better control over reputation.

Conclusion

Moving from Resend to a custom AWS SES platform was one of the highest-leverage infrastructure projects I have shipped. The ongoing cost reduction is significant, but the larger gain is ownership. We now have full visibility into every email we send, complete control over the delivery pipeline, and a platform we can extend as our product scales.

The combination of AI-assisted system design and development meant a solo engineering effort delivered something that would previously have required a team sprint. That is the workflow I will carry into every infrastructure project going forward.

TLDR

We replaced Resend with a custom platform using AWS SES, SQS, Next.js, and PostgreSQL. Monthly email costs dropped by over 87%. Build time was four weeks, accelerated significantly by AI-assisted design and coding. At scale, the savings compound into thousands of dollars per year.

Prathmesh

Full-stack engineer, edtech and AI

Built with Next.js, AWS SES, SQS, Prisma, and PostgreSQL. System designed and shipped with AI.

contact, socials.

Twitter / X.comx.com/prathmeshsadake