Back to blog
GuideFebruary 1, 20269 min read

Transactional Email Best Practices for SaaS Apps

How to set up reliable transactional emails for your SaaS application. From infrastructure to templates to monitoring.

Why Transactional Emails Matter

Transactional emails — password resets, order confirmations, welcome emails — have the highest open rates of any email type (80%+ average). They're critical for user experience and retention.

If a user can't reset their password because your email didn't arrive, you lose that user forever.

Infrastructure Decisions

Dedicated Domain

Never send transactional emails from your marketing domain. Use a subdomain:

  • mail.yourapp.com for transactional
  • news.yourapp.com for marketing

This protects your transactional reputation if marketing emails cause spam complaints.

API vs SMTP

FactorREST APISMTP
SpeedFaster (single HTTP call)Slower (multi-step handshake)
ReliabilityBetter error handlingConnection timeouts
FeaturesFull API featuresBasic send only
SetupSimple (HTTP client)Requires SMTP library

Recommendation: Use REST API for new applications. Use SMTP only for legacy systems.

Essential Transactional Emails

Every SaaS app should have these:

  • Welcome email — Sent immediately after signup
  • Email verification — Confirm the address is real
  • Password reset — Time-limited, secure tokens
  • Invoice/receipt — After payment
  • Usage alerts — Approaching plan limits

Template Best Practices

  • Keep it simple — Transactional emails should be functional, not flashy
  • One clear CTA — Each email should have one primary action
  • Mobile responsive — 60%+ of emails are opened on mobile
  • Consistent branding — Same logo, colors, and footer on every email
  • Plain text fallback — Always include a text version

Error Handling

async function sendEmailWithRetry(params: EmailParams, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      const { data, error } = await unosend.emails.send(params);
      if (error) throw new Error(error.message);
      return data;
    } catch (err) {
      if (i === retries - 1) throw err;
      await new Promise(r => setTimeout(r, 1000 * Math.pow(2, i)));
    }
  }
}

Key points:

  • Retry with exponential backoff — Don't hammer the API on failure
  • Log failures — Track which emails fail and why
  • Alert on critical failures — Password resets and verifications must succeed
  • Queue non-urgent emails — Notifications can be slightly delayed

Monitoring

Set up webhooks to track:

  • Delivered — Email accepted by recipient's server
  • Opened — Recipient opened the email (pixel tracking)
  • Clicked — Recipient clicked a link
  • Bounced — Email rejected (remove from list!)
  • Complained — Marked as spam (stop emailing this person!)
// Webhook handler
app.post('/webhooks/email', (req, res) => {
  const event = req.body;

  switch (event.type) {
    case 'email.bounced':
      suppressEmail(event.data.to);
      break;
    case 'email.complained':
      suppressEmail(event.data.to);
      alertTeam(event.data);
      break;
  }

  res.sendStatus(200);
});

Quick Setup Guide

  • Sign up for an email API (Unosend gives 5,000 free/month)
  • Verify your sending domain (SPF + DKIM)
  • Build your core email templates
  • Implement send with retry logic
  • Set up webhook handlers for bounces/complaints
  • Monitor deliverability in your dashboard
SaaSBest PracticesInfrastructure

Ready to send your first email?

Get started with 5,000 free emails/month. No credit card required.

Start for free