All posts Engineering

SMTP vs. REST API: how to choose and when to switch

How SMTP and REST API email transports differ in practice (statefulness, serverless fit, templates, idempotency, error handling), when each is the right choice, and a step-by-step plan for migrating from SMTP to a REST API.

Erik Vlčák
Erik Vlčák
Customer Success Engineer
8 min read

SMTP and a REST API are the two ways an application hands an email to a sending service. SMTP is the older, connection-oriented protocol that every mail system understands, while a REST API is a single stateless HTTP request. They differ in how they hold a connection, what features they expose beyond plain delivery, and how they report failure, and that difference decides which one fits modern infrastructure like serverless functions and containers.

How SMTP and a REST API differ

SMTP is a stateful, connection-oriented protocol. The application opens a TCP connection to the mail server, performs a multi-step handshake (EHLO, MAIL FROM, RCPT TO, DATA), transmits the message, and then either keeps the connection open for the next message or closes it. Reusing the connection reduces overhead across a batch, but a single email from a short-lived process pays the full cost of that handshake every time.

A REST API call is stateless. The application sends an HTTP POST request with a JSON body, receives a response, and that's the entire interaction. There's no connection to manage and no session state to clean up.

Why the difference matters in modern infrastructure

In serverless environments like Lambda or Cloud Functions, functions spin up on demand and are frozen or killed when idle. An SMTP connection established in one invocation is usually dead by the next, leaving two options: reconnect on every send (slow) or write connection pooling logic that fights the execution model (fragile). A stateless HTTP request avoids the problem entirely because there's nothing to keep alive between invocations.

Kubernetes and ECS face the same issue at different scales. Containers scale up and down, and an SMTP connection tied to a specific container becomes stale when that container is replaced. REST calls go through a load balancer and don't care which container they hit.

Some platforms, including Lettr, support both protocols, which allows REST from a Node.js Lambda function and SMTP from a legacy CRM that can't be modified, with both flows feeding the same analytics and suppression list.

What the API gives you that SMTP can't

SMTP's job is to deliver a complete email message from one server to another. The protocol doesn't understand templates, metadata, scheduling, or structured errors, so anything beyond "here's a message, deliver it" becomes your problem to solve in application code.

A REST API accepts structured data, which enables two features that materially change the integration: server-side templates and idempotency.

1. Server-side templates

The request carries a template ID and a set of merge variables instead of the full HTML, and the email service renders the final message. The application code never touches the email layout, and non-developers can edit templates without a code deploy.

POST /emails
{
  "to": "user@example.com",
  "template_id": "order-confirmation",
  "merge_data": {
    "name": "Alex",
    "order_id": "ORD-4821",
    "items": [
      { "name": "Widget Pro", "qty": 2, "price": "$24.00" }
    ]
  }
}

The SMTP equivalent builds the HTML in application code before handing it to an SMTP library:

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

msg = MIMEMultipart("alternative")
msg["From"] = "orders@yourapp.com"
msg["To"] = "user@example.com"
msg["Subject"] = "Your order ORD-4821"

# You built this HTML yourself, in your app code
html = render_template("order-confirmation.html", name="Alex", order_id="ORD-4821")
msg.attach(MIMEText(html, "html"))

with smtplib.SMTP("smtp.provider.com", 587) as server:
    server.starttls()
    server.login("apikey", "your-api-key")
    server.send_message(msg)

Both approaches work. The REST version keeps email content on the email platform rather than tying it to your deployment cycle, so a copy change doesn't require a code change.

2. Idempotency

A timed-out network call leaves the outcome unknown: the server may or may not have processed the request. With an idempotency key, retrying is safe: the server recognizes the key from the first attempt and returns the original result instead of reprocessing. SMTP has no equivalent. A connection that drops after DATA but before the 250 OK leaves the message in the same ambiguous state, and a naive retry can deliver it twice.

For password resets, order confirmations, and other transactional flows where duplicates are visible to the user, that ambiguity matters. The API solution requires a single additional request header.

Other features worth knowing about

Two smaller things the API provides that are awkward or impossible over SMTP:

  • Structured metadata. Attach fields like user_id, campaign_name, or environment to a send, and they flow through to webhooks and analytics. The SMTP equivalent is custom X- headers that the provider may or may not parse.
  • Scheduled sending. A send_at timestamp tells the platform to queue the message until the requested time. No cron job required.

Error handling

How a transport reports failure decides how much error-handling code it needs, and this is where the two diverge most sharply. A failed API call returns a JSON response with a status code, an error type, and a readable message:

{
  "status": 422,
  "error": "invalid_recipient",
  "message": "The address user@invalid-domain.test could not be validated. Check the domain exists and has MX records."
}

Switch on the error type and route it to an alert channel. Same pattern as any other API in your codebase.

SMTP errors look like this:

550 5.1.1 The email account that you tried to reach does not exist.

The first digit indicates the category (5xx is permanent, 4xx is temporary). The enhanced status code (5.1.1) carries additional detail, defined in the RFC 3463 table. The text that follows is freeform and varies by provider.

Handling SMTP errors properly means parsing these text responses, mapping provider-specific messages to your own error categories, and handling the worst case: the connection drops mid-handshake with no response, leaving it unknown whether the server accepted the message. With a REST API, the result is unambiguous: either a 2xx with a message ID, or a failure.

When SMTP is the right choice

SMTP isn't always wrong. Many teams are right to stick with it, and the most common reason is that they don't actually own the sending code.

WordPress plugins, legacy CRMs, ERP systems, and network appliances that send alert emails typically expose only an SMTP configuration screen. When the sending code can't be changed, an SMTP relay is the only option. Lettr's relay (smtp.lettr.com) handles this case: set the host, port (465 recommended), and an API key as the password. The existing system then sends through Lettr without any code changes.

The other reason to stay on SMTP is that migration risk doesn't always justify the cost. A tool that's already configured, sending low volumes, and working well is rarely worth the cost of building a custom integration. The same goes for monitoring: if your alerting is built around SMTP logs, connection metrics, or mail queue depth, switching to a REST API means rebuilding that observability layer.

For anything new, the API is almost always the better starting point. When your stack spans both worlds, such as a WordPress site alongside a custom Node.js service, choosing a provider that supports both protocols keeps the analytics and suppression list unified. See how Lettr compares to other providers.

FAQ

Is a REST API faster than SMTP?
For most applications, yes, because there is no connection to establish. A REST call is a single stateless HTTP request, while SMTP pays for a multi-step handshake on every send from a short-lived process. A long-lived server that reuses one SMTP connection across a large batch is the exception where the handshake cost is amortized.
Can I use both SMTP and a REST API with the same provider?
Yes, and it is common when a stack spans both worlds. A provider that supports both lets a serverless function send over the API while a legacy system that only exposes an SMTP screen sends over the relay, with both flows feeding the same analytics and suppression list. Lettr supports both protocols.
When should I keep using SMTP instead of switching to an API?
Keep SMTP when the sending code cannot be modified or when migration risk outweighs the benefit. WordPress plugins, legacy CRMs, ERP systems, and appliances that send alerts usually expose only an SMTP configuration screen, so a relay is the only option. A working low-volume integration with monitoring built around SMTP logs is also rarely worth rebuilding.
What is an idempotency key and why does SMTP lack one?
An idempotency key lets a retried request return the original result instead of sending the message twice. A REST API recognizes the key from the first attempt and does not reprocess it. SMTP has no equivalent, so a connection that drops after DATA but before the 250 OK leaves the outcome unknown, and a naive retry can deliver a duplicate.

Bottom line

New code should use the API; existing SMTP integrations that work should be left alone until a change forces the move. The forcing changes are connection problems in a serverless or container environment and the cost of maintaining templates in application code. When one hits, migrate one email type at a time and verify delivery before the next.

The fundamentals of deliverability are independent of all of this. Proper domain authentication, bounce handling, and engagement monitoring are required whether you're using SMTP or REST. The protocol decision is about how your code communicates with the email service; what happens after the message leaves your application is the same in both cases.

For both transports from a single provider (a drop-in SMTP relay and a REST email API), create a free Lettr account and select the right one for each part of your stack.