Back to Blog
๐Ÿ—๏ธ
/3 min read/By SMTPfast Team

Email API Best Practices for Production Apps

Lessons from sending millions of transactional emails. Error handling, retry logic, templates, and monitoring.

apibest-practicesproductiontutorial
Share:๐•in

Sending Email Is Easy. Sending It Well Is Not.

98%+
The delivery rate you should aim for. Below this, your sender reputation is at risk.

Calling an email API is one line of code. Making it reliable in production takes more thought. Here are the patterns that matter.

1. Never Send Synchronously

Do not call the email API in your request handler. If the API is slow or down, your entire endpoint blocks.

// Bad: blocks the request
app.post('/signup', async (req, res) => {
  await smtp.emails.send({ ... }); // If this takes 5s, user waits 5s
  res.json({ success: true });
});

// Good: queue it
app.post('/signup', async (req, res) => {
  await queue.add('send-welcome-email', { userId: user.id });
  res.json({ success: true }); // Returns immediately
});

2. Handle Errors Gracefully

Email API calls can fail. Network issues, rate limits, invalid addresses. Always wrap in try/catch and have a fallback.

try {
  await smtp.emails.send({
    from: '[email protected]',
    to: user.email,
    subject: 'Welcome!',
    html: template,
  });
} catch (error) {
  // Log it, but do not crash the app
  console.error('Email send failed:', error);
  // Queue for retry
  await retryQueue.add('email-retry', { to: user.email, template: 'welcome' });
}

3. Use Templates, Not Inline HTML

Hardcoded HTML in your application code is a maintenance nightmare.

// Bad
await smtp.emails.send({
  html: '<div style="font-family: Arial"><h1>Welcome ' + name + '</h1></div>',
});

// Good: use a template
await smtp.emails.send({
  template_id: 'welcome',
  variables: { name: user.name },
});

4. Validate Email Addresses Before Sending

Sending to invalid addresses hurts your sender reputation. Validate at the point of collection.

  • Check format (basic regex is fine)
  • Reject disposable email domains
  • Consider email verification services for critical flows

5. Set Up Webhooks

Do not poll the API to check email status. Use webhooks to get notified in real-time.

// Your webhook endpoint
app.post('/webhooks/email', (req, res) => {
  const event = req.body;

  switch (event.type) {
    case 'delivered':
      updateEmailStatus(event.email_id, 'delivered');
      break;
    case 'bounced':
      handleBounce(event.email_id, event.recipient);
      break;
    case 'complained':
      unsubscribeUser(event.recipient);
      break;
  }

  res.sendStatus(200);
});

6. Monitor Your Sending

Track these metrics:

  • Delivery rate - Should be above 98%
  • Bounce rate - Should be below 2%
  • Complaint rate - Should be below 0.1%
  • Open rate - Varies by email type (transactional should be 60%+)

If any of these drift, investigate immediately before it affects your sender reputation.

7. Use Separate Domains for Different Email Types

Do not send marketing and transactional emails from the same domain. If your marketing emails get flagged, your transactional emails suffer too.

transactional: [email protected]
marketing:     [email protected]

Key Takeaways

  1. Queue emails, never send synchronously
  2. Handle errors and implement retry logic
  3. Use templates for maintainability
  4. Validate addresses before sending
  5. Set up webhooks for delivery tracking
  6. Monitor your metrics weekly
  7. Separate transactional and marketing domains

Ready to get started?

Start sending transactional email today. Free to start, no credit card required.

Get Started for Free