API vs SMTP: Which to Use for Transactional Email
Technical comparison of REST API and SMTP for sending transactional email. Performance, error handling, and implementation examples.
Modern email services offer two ways to send transactional email: REST API and SMTP. Both work, but they have different trade-offs. This guide helps you choose.
Quick Comparison
| Factor | REST API | SMTP |
|---|---|---|
| Ease of Use | Simple | More complex |
| Error Handling | Structured JSON | Error codes |
| Connection Overhead | Per request | Persistent connection |
| Bulk Sending | Batched API calls | Persistent connection |
| Legacy Support | Requires code | Works with any client |
| Firewall Issues | Port 443 (HTTPS) | Port 587/465 may be blocked |
REST API
REST APIs use standard HTTP requests. Send a POST with JSON payload, get a JSON response. Modern and straightforward.
Advantages
- Structured error responses with detailed information
- Uses standard HTTPS on port 443 (rarely blocked)
- Easy to debug with standard HTTP tools
- SDK support in every language
- Batch sending in single requests
Example: Sequenzy API
import { Sequenzy } from '@sequenzy/sdk';
const sequenzy = new Sequenzy({ apiKey: process.env.SEQUENZY_API_KEY });
try {
const result = await sequenzy.send({
to: 'user@example.com',
template: 'password-reset',
variables: {
resetLink: 'https://app.example.com/reset/abc123'
}
});
console.log('Message ID:', result.id);
} catch (error) {
// Structured error handling
if (error.code === 'invalid_recipient') {
console.log('Invalid email address');
} else if (error.code === 'rate_limited') {
console.log('Too many requests, retry after:', error.retryAfter);
}
} Example: Resend API
import { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY);
const { data, error } = await resend.emails.send({
from: 'noreply@example.com',
to: 'user@example.com',
subject: 'Reset your password',
html: '<p>Click here to reset...</p>'
});
if (error) {
console.error('Failed to send:', error.message);
} else {
console.log('Sent:', data.id);
} Example: Raw HTTP Request
curl -X POST https://api.sequenzy.com/v1/send \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"to": "user@example.com",
"template": "password-reset",
"variables": {
"resetLink": "https://app.example.com/reset/abc123"
}
}' SMTP
SMTP (Simple Mail Transfer Protocol) is the original email protocol. Connect to a server, authenticate, send the message using SMTP commands.
Advantages
- Works with any email client or library
- Persistent connections for high-volume sending
- Required for some legacy systems
- Can use existing email infrastructure
Example: Node.js with Nodemailer
import nodemailer from 'nodemailer';
const transporter = nodemailer.createTransport({
host: 'smtp.sequenzy.com',
port: 587,
secure: false, // TLS
auth: {
user: 'apikey',
pass: process.env.SEQUENZY_API_KEY
}
});
try {
const info = await transporter.sendMail({
from: 'noreply@example.com',
to: 'user@example.com',
subject: 'Reset your password',
html: '<p>Click here to reset...</p>'
});
console.log('Message sent:', info.messageId);
} catch (error) {
// SMTP error codes are less descriptive
console.error('SMTP error:', error.message);
} Example: Python with smtplib
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
msg = MIMEMultipart('alternative')
msg['Subject'] = 'Reset your password'
msg['From'] = 'noreply@example.com'
msg['To'] = 'user@example.com'
html = '<p>Click here to reset...</p>'
msg.attach(MIMEText(html, 'html'))
with smtplib.SMTP('smtp.sequenzy.com', 587) as server:
server.starttls()
server.login('apikey', os.environ['SEQUENZY_API_KEY'])
server.send_message(msg) When to Use API
- Building a new application
- You want better error handling
- Using templates managed by the email service
- You need batch sending capabilities
- Firewall blocks SMTP ports
When to Use SMTP
- Integrating with legacy systems
- Using existing email-sending code
- Sending from email clients (Outlook, Thunderbird)
- Very high volume with persistent connections
- CMS or application only supports SMTP
Performance Considerations
Connection Overhead
Each SMTP session requires a TCP handshake, TLS negotiation, and authentication. For single emails, this overhead is significant. APIs have similar overhead per request but handle it more efficiently.
// SMTP: Keep connection open for multiple sends
const transporter = nodemailer.createTransport({...});
// Send many emails on same connection
for (const recipient of recipients) {
await transporter.sendMail({
to: recipient.email,
...
});
}
// Close when done
transporter.close(); API Batching
Many APIs support sending to multiple recipients in one request:
// Batch sending with API
await sequenzy.sendBatch([
{ to: 'user1@example.com', template: 'welcome' },
{ to: 'user2@example.com', template: 'welcome' },
{ to: 'user3@example.com', template: 'welcome' }
]); Recommendation
Use API for most applications. Better error handling, easier debugging, and simpler code. The modern approach.
Use SMTP when required. Legacy systems, CMS integrations, or sending from desktop email clients.
Most services like Sequenzy, Postmark, and Resend recommend their API but support SMTP for compatibility.
Compare email services
Find the right transactional email service with great API design.
View Full Comparison