Skip to content

Transactional email for vibe-coded apps: Resend, Brevo, and the AI defaults that bite

Robert Boylan7 min read

You ship the app. A user signs up, stares at the screen for thirty seconds, then checks their inbox for a verification link that never arrives. They try the password reset. That one doesn't arrive either. They close the tab. You never know they existed.

This is the most common way email quietly kills early traction: not through spam filters or fancy deliverability issues, but because the AI coding tool either skipped email entirely or wired it up against a local SMTP server that only works on your machine.

If you're building with Cursor, Lovable, Bolt.new, or any other AI-first tool, email is the integration that gets glossed over in the spec and breaks silently in production. Here's how to pick a provider, what four emails your app actually needs at launch, and the six spec lines that stop the AI from improvising.

The four emails every vibe-coded app needs before launch day

Transactional email (the automated, one-at-a-time messages your app sends in response to user actions, as opposed to newsletters or broadcast campaigns) gets lumped together in most indie dev conversations as "email stuff I'll sort later." Later never comes. Here's what the minimum viable email layer looks like.

Verification email. Required if you're doing email-based sign-up. Without it, anyone can create an account with someone else's email address. Your auth provider (Supabase, Auth.js, Clerk) usually handles this, but the actual sending still goes through your email provider. Don't let the AI leave it on localhost SMTP.

Password reset. A broken reset flow is the second-fastest way to lose a user after a broken sign-up. This also ships through your auth provider in most setups. Same caveat applies.

Receipt or subscription confirmation. If your app charges money, send a plain-text receipt immediately after payment. The email doesn't need to be beautiful. It needs to exist, have the amount, have a way to contact you, and land in the inbox. Legal requirement in many jurisdictions; basic trust signal everywhere.

Welcome email. This one can wait until the week after launch, but not much longer. A single email that tells a new user what to do next has outsized impact on whether they come back. Not an onboarding sequence. One email. One suggestion. Done.

Everything else (account activity summaries, feature announcements, billing dunning) is optional at launch and can be added later. Get these four right first.

Resend, Brevo, Postmark, or SendGrid: which one to pick

There are four providers indie devs actually use. Here's an honest breakdown, without the affiliate-blog pitch.

Resend is the newest and the one with the cleanest developer experience. The API is simple, the dashboard is clear, and the free tier covers 3,000 emails/month. One limitation: it's purely transactional. If you later want to send newsletters, you'll need a second tool. Good default if you just need working email as fast as possible.

Brevo (formerly Sendinblue) is the pick if you want transactional and marketing under one roof. Welcome email today, drip sequence next month, newsletter eventually, all from the same account. The free tier is 300 emails/day; the API is more verbose than Resend's but solid. Better for apps that are going to grow into lifecycle marketing.

Postmark is the deliverability-first option. More expensive (no real free tier), but its inbox reputation is excellent. Worth it if a missed password reset is a genuine problem for your use case (fintech, medical, legal).

SendGrid is the legacy default. The AI tools know it because it's been around the longest. The API works; the free tier (100 emails/day) is thinner than Resend's; the dashboard is confusing. Pick it only if the AI generates SendGrid code first and you'd rather ship than reconfigure.

The short version: start with Resend. Move to Brevo if you need marketing features. Pay for Postmark if deliverability is critical. Skip SendGrid unless it falls out of the AI's first pass and time is short.

Why the AI's first attempt at email usually breaks

Ask Cursor or Lovable to "add email to this app" without specifics and you'll get one of three outcomes. The AI spins up a Nodemailer setup pointed at a local SMTP server that stops working the moment you deploy. Or it writes code that references environment variables you haven't set. Or it generates a SendGrid integration where the domain verification step is missing, so the emails land in spam because the sending domain has no DKIM or SPF records.

DKIM (DomainKeys Identified Mail) and SPF (Sender Policy Framework) are DNS records that tell receiving email servers "yes, this sender is allowed to send email on behalf of this domain." Without them, your emails are unauthenticated and spam filters treat them with suspicion. Every email provider requires you to add these DNS records manually. It takes ten minutes. The AI cannot do it because it can't touch your DNS registrar. But it also, by default, won't tell you to do it.

The domain verification gap is the single biggest reason indie dev email goes to spam. The code is correct. The API key works. The DNS records are missing because nobody wrote "configure DKIM and SPF for the sending domain" into the spec.

Environment variable discipline is the second failure mode. The AI will happily put RESEND_API_KEY in the code, but it won't remind you to add it to your Vercel or Railway deployment environment. The app fails silently in production. Users get nothing.

A third failure: the "from" address. Sending from noreply@gmail.com is rejected by modern providers. Sending from hello@yourdomain.com requires the domain to be verified with your email provider first. The AI often defaults to an address that looks plausible but will be immediately rejected.

Six lines in your spec that prevent each of these issues

Before you let the AI start writing email code, add this block to your project spec. It sounds like overkill for a vibe-coded app. It isn't. These six lines are the difference between email that works on launch day and email that works on your laptop.

  1. Provider: "Use Resend (or Brevo/Postmark) for all automated email sending. Do not use Nodemailer, local SMTP, or any provider not listed here."
  2. Environment variables: "All API keys go in environment variables. Names: RESEND_API_KEY (or equivalent). Never hardcode. Document each variable with a comment."
  3. Sending domain: "All emails send from hello@[domain] or noreply@[domain]. Remind me to complete domain verification in the provider dashboard (DKIM + SPF) before going to production."
  4. Emails required at launch: "Wire the following four emails: email verification, password reset, purchase receipt, welcome message. Auth provider handles verification and reset flows; route them through [chosen provider] not the default auth SMTP."
  5. Plain text fallback: "All emails must include a plain text alternative, not just HTML. This improves deliverability and accessibility."
  6. Error handling: "If an email fails to send, log the error with the user ID and email type. Do not crash the request. Email failure should not block the user action that triggered it."

Line 3 is the one most likely to get skipped. Write it explicitly anyway; it prompts the AI to add a comment in the code reminding you to do the DNS step.

Accessibility and deliverability: small things that send mail to spam

This section is mostly for the non-technical reader who's been nodding along and wants to know the practical stuff.

Deliverability (whether your email actually lands in the inbox versus spam) comes down to a few things: the DNS records mentioned above, sending reputation, and the content of the email itself. For a new domain sending low volume, reputation builds slowly. Here are the content-level things worth getting right from day one.

Don't use gradient text or gradient buttons. Many email clients (including Gmail and Apple Mail) strip CSS that email providers can't render safely. A gradient button that looks beautiful in your preview might render as invisible text in someone's inbox. Use solid background colors, plain system fonts, and enough contrast that the email is readable in dark mode too. The rule of thumb: if it looks too good, it probably doesn't work in Outlook.

Don't use images as the entire email. A signup confirmation that's one big image looks nice in a browser and renders as a blank rectangle in some email clients. Keep the core content in HTML text. Images are decoration; words carry the information.

Write a useful subject line. "Welcome!" gets ignored. "Your account is ready, here's what to do next" tells someone why to open it.

Include a plain-text unsubscribe path, even for automated email. Gmail and others will add one automatically for bulk senders, but doing it yourself gives you control over where it goes and how it's worded. For strictly triggered messages (receipts, password resets), this is less critical, but a contact address at the bottom of every email is good practice regardless.

None of this is technically hard. It's the kind of thing that takes five minutes to get right in the spec and half a day to debug in production.

Get email right before your first user signs up

Transactional email indie SaaS builders need isn't a hard problem. It's a skipped-on-purpose problem. The AI won't remind you about it because you didn't mention it. The email provider won't yell at you until you've already shipped. And users won't tell you the verification link never came; they'll just close the tab.

The billing post in this series covers the same pattern applied to Stripe integrations: the code is mostly fine, the spec is missing. Email is identical. When you're ready to make sure nothing else in your launch setup falls through the gaps, the vibe-coded app launch checklist covers what to verify before you hit publish.

Pick a provider, add six lines to your spec, and make sure someone on your launch day actually gets a welcome email. Everything else is details.