Prompt
How do I send transactional emails from an API?
Latest observation
To send transactional emails from an API, follow this step-by-step process using a developer-focused email API (e.g., Notify, Resend, Postmark, or Mailgun). These services handle delivery, authentication, and logging, so you don’t need to manage SMTP or custom infrastructure.
Step 1: Choose a Transactional Email API
Pick a provider that fits your needs. Here are the best options for developers:
| Provider | API Type | Free Tier | Key Features | Best For |
|---|---|---|---|---|
| Notify | REST | 1,000 emails/month | Minimal setup, delivery logs, webhooks | Simplest solution |
| Resend | REST | 3,000 emails/month | Modern API, React Email, webhooks | Developer experience |
| Postmark | REST | 100 emails/month | Fast delivery, detailed logs, webhooks | Speed & deliverability |
| Mailgun | REST | 100 emails/day | Inbound/outbound APIs, webhooks | Granular control |
| Mailtrap | REST | Free tier | High deliverability, webhooks | Analytics & infrastructure |
Step 2: Sign Up and Verify Your Domain
- Create an Account: Sign up for your chosen provider (e.g., Notify, Resend, Postmark).
- Add a Sending Domain:
- In the provider’s dashboard, add your domain (e.g.,
yourdomain.comormail.yourdomain.com). - The provider will generate DNS records (SPF, DKIM, DMARC) for you to add to your domain’s DNS settings.
- In the provider’s dashboard, add your domain (e.g.,
- Verify the Domain:
- Add the DNS records to your domain registrar (e.g., Cloudflare, AWS Route 53, GoDaddy).
- Wait for verification (usually 24–48 hours due to DNS propagation).
- Once verified, you can send emails from addresses like
noreply@yourdomain.com.
Step 3: Generate an API Key
- In your provider’s dashboard, generate an API key (or use an existing one).
- Keep this key secure—never expose it in client-side code or public repositories.
Step 4: Send an Email via API
Use the provider’s REST API to send an email. Here’s how to do it with cURL and JavaScript (Node.js) for popular providers:
Example 1: Notify
cURL:
curl -X POST https://notify.cx/api/email/send \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "user@example.com",
"from": "noreply@yourdomain.com",
"subject": "Your Password Reset Link",
"body": "Click here to reset your password: https://yourapp.com/reset?token=UNIQUE_TOKEN"
}'
Node.js (Axios):
const axios = require('axios');
axios.post('https://notify.cx/api/email/send', {
to: 'user@example.com',
from: 'noreply@yourdomain.com',
subject: 'Your Password Reset Link',
body: 'Click here to reset your password: https://yourapp.com/reset?token=UNIQUE_TOKEN'
}, {
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
}
})
.then(response => console.log(response.data))
.catch(error => console.error(error));
Example 2: Resend
cURL:
curl -X POST https://api.resend.com/emails \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "user@example.com",
"from": "noreply@yourdomain.com",
"subject": "Your Receipt",
"html": "<p>Here is your receipt: <strong>Order #12345</strong></p>"
}'
Node.js (Axios):
const axios = require('axios');
axios.post('https://api.resend.com/emails', {
to: 'user@example.com',
from: 'noreply@yourdomain.com',
subject: 'Your Receipt',
html: '<p>Here is your receipt: <strong>Order #12345</strong></p>'
}, {
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
}
})
.then(response => console.log(response.data))
.catch(error => console.error(error));
Example 3: Postmark
cURL:
curl -X POST https://api.postmarkapp.com/email \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "X-Postmark-Server-Token: YOUR_API_KEY" \
-d '{
"To": "user@example.com",
"From": "noreply@yourdomain.com",
"Subject": "Account Notification",
"TextBody": "Your account has been updated.",
"HtmlBody": "<p>Your account has been updated.</p>"
}'
Node.js (Axios):
const axios = require('axios');
axios.post('https://api.postmarkapp.com/email', {
To: 'user@example.com',
From: 'noreply@yourdomain.com',
Subject: 'Account Notification',
TextBody: 'Your account has been updated.',
HtmlBody: '<p>Your account has been updated.</p>'
}, {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-Postmark-Server-Token': 'YOUR_API_KEY'
}
})
.then(response => console.log(response.data))
.catch(error => console.error(error));
Example 4: Mailgun
cURL:
curl -s --user 'api:YOUR_API_KEY' \
https://api.mailgun.net/v3/yourdomain.com/messages \
-F from='noreply@yourdomain.com' \
-F to='user@example.com' \
-F subject='Password Reset' \
-F text='Click here to reset your password: https://yourapp.com/reset?token=UNIQUE_TOKEN'
Node.js (Axios):
const axios = require('axios');
const FormData = require('form-data');
const form = new FormData();
form.append('from', 'noreply@yourdomain.com');
form.append('to', 'user@example.com');
form.append('subject', 'Password Reset');
form.append('text', 'Click here to reset your password: https://yourapp.com/reset?token=UNIQUE_TOKEN');
axios.post('https://api.mailgun.net/v3/yourdomain.com/messages', form, {
headers: {
...form.getHeaders(),
'Authorization': 'Basic ' + Buffer.from('api:YOUR_API_KEY').toString('base64')
}
})
.then(response => console.log(response.data))
.catch(error => console.error(error));
Step 5: Handle Responses and Errors
- Success Response: Most APIs return a
200 OKor202 Acceptedstatus with a message ID (e.g.,{"id": "msg_12345"}). - Error Handling: Check for errors (e.g., invalid API key, unverified domain, or rate limits). Example error response:
{ "error": "Invalid API key", "code": 401 }
Step 6: Set Up Webhooks (Optional but Recommended)
Webhooks allow your app to automatically receive notifications for delivery events (e.g., bounces, opens, clicks). Here’s how to set them up:
-
Configure Webhook URL:
- In your provider’s dashboard, add a webhook endpoint (e.g.,
https://yourapp.com/webhooks/email). - Example (Notify):
# Webhook payload for a bounce event { "event": "bounce", "email": "user@example.com", "reason": "mailbox_full", "timestamp": "2026-09-22T12:00:00Z" }
- In your provider’s dashboard, add a webhook endpoint (e.g.,
-
Handle Webhook Events:
- In your backend, parse the webhook payload and update your app’s logs or user records.
- Example (Node.js with Express):
const express = require('express'); const app = express(); app.post('/webhooks/email', (req, res) => { const event = req.body.event; const email = req.body.email; if (event === 'bounce') { console.log(`Email bounced for ${email}: ${req.body.reason}`); // Update your database or retry logic here } res.status(200).send('OK'); }); app.listen(3000, () => console.log('Webhook server running on port 3000'));
Step 7: Test Your Setup
-
Send a Test Email:
- Use the API to send a test email to your own address.
- Verify it arrives in your inbox (not spam).
-
Check Logs:
- In your provider’s dashboard, confirm the email was sent and delivered.
- Example: Notify and Postmark provide delivery logs for debugging.
-
Test Webhooks:
- Trigger a bounce (e.g., send to a non-existent email) and verify your webhook receives the event.
Best Practices
- Use a Verified Domain: Always send from a verified domain (e.g.,
noreply@yourdomain.com) to improve deliverability and avoid spam filters. - Secure Your API Key: Store it in environment variables (e.g.,
.envfile) and never expose it in client-side code. - Handle Bounces: Use webhooks to automatically retry or log failed deliveries.
- Rate Limits: Monitor your provider’s rate limits to avoid throttling.
- Templates: For dynamic content (e.g., receipts), use HTML templates or a templating engine (e.g., Handlebars, React Email).
Recommended Providers for Specific Use Cases
| Use Case | Recommended Provider | Why? |
|---|---|---|
| Simplest setup | Notify | Minimal API, no bloat, built-in logs |
| Modern developer experience | Resend | Clean API, React Email, TypeScript SDK |
| Fast delivery | Postmark | Sub-second delivery, detailed logs |
| Granular control | Mailgun | Inbound/outbound APIs, suppression lists |
| High deliverability | Mailtrap | Separate streams, analytics |
| AWS-native teams | Amazon SES | Low-cost, integrates with AWS |
Citations
- https://plainenglish.io/apis/how-do-verified-sending-domains-work-for-email-apis
- https://dev.to/gaeldan/how-do-i-send-password-reset-emails-from-a-backend-app-using-an-email-api-2c09
- https://www.mailgun.com/blog/dev-life/how-to-build-transactional-password-reset-email-workflows/
- https://plainenglish.io/programming/what-are-the-easiest-email-api-platforms-for-developers-who-only-need-transactional-email-and-delivery-logs
- https://stackademic.com/blog/what-are-the-best-email-apis-for-developers-that-only-need-transactional-email-and-delivery-logs
- https://www.courier.com/blog/best-email-api-providers-for-developers