All guides
Tutorial/ 9 min read/

Send Transactional Emails from a Launchverse App: SMTP, Resend, and Postmark

How to wire transactional emails (signups, receipts, password resets) into a Launchverse application — covers SMTP, Resend, Postmark, and the deliverability mistakes that send your mail to spam.

The first feature most apps need after signup-and-login is "send the user an email when X happens." It's also the feature where new applications most commonly stub their toe — emails go to spam, deliverability is invisible, and the bounce rate quietly tanks before anyone notices.

This guide covers the practical setup for sending transactional email from a Launchverse application: which provider to choose, how to wire it, and the DNS records you must set so your mail actually arrives.

Why you can't sendmail directly

In theory, your container can SMTP straight to the recipient's mail server (gmail-smtp-in.l.google.com for @gmail.com). In practice, every major mail provider:

  • Blocks unsolicited connections from cloud IPs (your container has one).
  • Demands authenticated, signed mail (DKIM + SPF + DMARC).
  • Rate-limits unknown senders aggressively.

Run-your-own-SMTP works for ops mail to your own domain inside one corporate network. For real customer mail, you go through a provider whose IPs are known-good and whose mail is signed correctly. The good ones charge cents per thousand messages.

Choosing a provider

ProviderSweet spotFree tierNotes
ResendModern API, great DX3,000 / monthBuilt for the JS ecosystem, has React Email support
PostmarkPremium deliverability100 / month, then $$Premium reputation, great for high-stakes mail
MailgunVolume + EU regionsPay-as-you-goSolid all-rounder, dashboard is dated
SendGridEstablished, large volume100 / dayStrong volume tooling, occasionally flaky support
AWS SESCheapest at scaleFirst 62,000 / month free if from EC2Cheapest dollar-per-thousand; UI is bare
Plain SMTP via Brevo / SendGridLegacy systems / WordPressVariesIf your stack only speaks SMTP

The 80/20 recommendation in 2026: Resend for new projects, Postmark for projects where deliverability matters more than the bill. Both have enough free volume to validate without committing.

DNS records you absolutely must set

Three records make your mail "real" in the eyes of receiving servers:

1. SPF — who is allowed to send mail as your domain?

A TXT record on your sending domain (e.g. example.com):

TXT @  "v=spf1 include:_spf.<provider>.com -all"

Replace <provider> with the provider's published include (Resend: _spf.resend.com; SendGrid: sendgrid.net; etc.).

2. DKIM — cryptographically sign each message

The provider gives you a CNAME or TXT record per signing key (typically two). They look like:

CNAME resend._domainkey  resend._domainkey.resend.com
CNAME resend2._domainkey resend2._domainkey.resend.com

Add them exactly as the provider says. Once these resolve, the provider can sign messages on your behalf and Gmail / Outlook will display them as "from you, signed by Resend."

3. DMARC — policy when SPF/DKIM fail

A TXT record on _dmarc.example.com:

TXT _dmarc "v=DMARC1; p=quarantine; rua=mailto:[email protected]"

Start with p=quarantine. After a few weeks of clean reports, escalate to p=reject. The rua address gets aggregate reports from receiving servers — useful when you're wondering why a customer says "I never get your emails."

Without these three records, your mail goes to spam. It's not optional.

Wiring it into a Launchverse app (Node + Resend)

// app/api/auth/welcome/route.ts
import { Resend } from "resend";

const resend = new Resend(process.env.RESEND_API_KEY);

export async function POST(req: Request) {
  const { to, name } = await req.json();
  const { data, error } = await resend.emails.send({
    from: "Launchverse <[email protected]>",
    to: [to],
    subject: `Welcome, ${name}!`,
    html: `<p>Thanks for signing up.</p>`,
  });
  if (error) return Response.json({ error: error.message }, { status: 500 });
  return Response.json({ id: data?.id });
}

Set RESEND_API_KEY in Launchverse → Settings → Environment Variables. Restart the project. Test with a real recipient (not a @example.com address — providers blackhole those).

Wiring it via plain SMTP (Python + any provider)

If your stack is more SMTP-shaped:

import os, smtplib, ssl
from email.message import EmailMessage

msg = EmailMessage()
msg["From"] = "[email protected]"
msg["To"] = recipient
msg["Subject"] = subject
msg.set_content(body_text)

with smtplib.SMTP(os.environ["SMTP_HOST"], 587) as s:
    s.starttls(context=ssl.create_default_context())
    s.login(os.environ["SMTP_USER"], os.environ["SMTP_PASS"])
    s.send_message(msg)

Set the four env vars in Launchverse: SMTP_HOST, SMTP_USER, SMTP_PASS, plus the From address.

Don't send from a free domain

Don't use gmail.com / outlook.com / yahoo.com as your From address. Even with SPF / DKIM / DMARC perfectly set up on your domain, a From: [email protected] is a different domain that you don't control, and DMARC will fail.

Use a domain you own. If you don't have one, buy a .com for $10 — it pays for itself the first month.

Test deliverability

After setup:

  1. Send a test email to mail-tester.com (their UI shows you a free score out of 10).
  2. Send to a Gmail account, an Outlook account, and a Proton account. Check that all three arrive in inbox (not spam, not Promotions).
  3. Mark a few as "Important" / "Not spam" — early reputation matters.
  4. Set up basic monitoring: a once-a-day cron that sends a known message to a known mailbox and alerts if it bounces.

Bounces, complaints, and unsubscribes

Three signals you need to track:

  • Hard bounces (mailbox doesn't exist). Stop sending immediately; over ~5% bounce rate gets you blacklisted.
  • Complaints (recipient marked you as spam). Stop sending to that recipient forever; even legitimate transactional mail to them is now contributing to your spam reputation.
  • Soft bounces (mailbox full, temporary). Retry with backoff (your provider does this for you).

Most providers expose webhooks for these events. Wire them to your user database — when complaint fires for [email protected], set email_unsubscribed = true and never send to them again.

Deliverability checklist

CheckStatus
Custom domain (not gmail.com)
SPF record
DKIM signing
DMARC at quarantine or reject
From matches signing domain
Plain-text alternative in multipart messages
Unsubscribe link on marketing mail
Bounce handling
Complaint handling
Production sending tested with mail-tester.com

If you can tick all 10, you're a deliverability outlier in a good way.

Further reading


Ready to deploy?

Start free in Naira — no card required, no FX surprises.

Have feedback or a topic to suggest? Talk to us.