For a modern signup flow, choose a transactional email API when delivery reliability, explicit integration, templates, and event history matter more than legacy SMTP compatibility. SMTP remains reasonable for a plugin that only knows how to hand mail to a relay, but it makes the application own more of the tracking boundary.
Short answer: use an API route for a code-controlled welcome email, keep SMTP as the compatibility fallback, and treat domain authentication plus pull-based event history as reliability work rather than configuration trivia.
The decision record: protect the signup path
The invariant is simple: after account creation, the user receives one verification link, and a retry never creates two links or two messages. The critical path is therefore application event -> provider send request -> durable message identifier -> a way to inspect status later. Delivery is not confirmed merely because a TCP connection to an SMTP server succeeded.
I would keep the verification token and its expiry in the application database. The mail service gets a rendered message or a template reference, never authority to invent account state. That boundary makes a bounce, a delayed delivery, or a support ticket diagnosable without replaying the signup transaction.
There is a practical wrinkle. Event data here is list-based, not pushed by webhook. A resend-after-bounce worker must poll, so it is less immediate than a webhook-driven design. That delay is acceptable for a welcome message if the product can tolerate a short recovery window; it is a poor fit for a security action that demands instant orchestration. In one concrete flow, the worker can poll every few minutes, correlate the provider message id with the signup row, and stop after the token expires; the application should record each decision so a support engineer can tell a delayed mailbox from a rejected address, while a separate rate limit prevents a noisy retry loop from becoming a second delivery incident.
Keep the token local.
The domain also needs DKIM records and verification. Read RFC 6376 before treating a green provider dashboard as proof that every recipient will trust the message.
How should an API or SMTP handle welcome email integration, templates, domains, and event history?
An API gives the backend an explicit operation and a response it can persist. A minimal Python client can make that contract visible:
import os
import time
import uuid
import urllib.request
import urllib.error
def send_welcome(to_address: str, verification_url: str) -> dict:
payload = (
'{"to":"' + to_address + '",'
'"subject":"Verify your account",'
'"text":"Open ' + verification_url + ' to finish signup."}'
).encode("utf-8")
request = urllib.request.Request(
os.environ["INFRAI_API_BASE"] + "/email/send",
data=payload,
method="POST",
headers={
"Authorization": "Bearer " + os.environ["INFRAI_API_KEY"],
"Content-Type": "application/json",
"Idempotency-Key": "welcome-" + str(uuid.uuid4()),
},
)
for attempt in range(4):
try:
with urllib.request.urlopen(request, timeout=10) as response:
if response.status >= 400:
raise RuntimeError(response.read().decode("utf-8"))
return {"status": response.status, "body": response.read().decode("utf-8")}
except urllib.error.HTTPError as error:
if error.code != 429 or attempt == 3:
raise
retry_after = error.headers.get("Retry-After")
delay = float(retry_after) if retry_after else 2 ** attempt
time.sleep(delay)
raise RuntimeError("send did not complete")
In production, derive the idempotency value from the account or signup event id, rather than generating a new UUID on every process retry. Persist the returned message id and use the provider's history query for support reconciliation. Keep template lifecycle in your deployment record so a later edit cannot rewrite history.
SMTP has a different shape: the application opens a session, speaks a mature mail protocol, and receives relay-level responses. That is exactly what old CMS plugins and desktop tools expect. It is also why SMTP alone does not give your signup service a provider-native event history; you must collect message identifiers and reconcile them through whatever relay features are available.
A fair comparison of the routes
The products below are all real choices, but their current limits and commercial terms change, so this table is an architectural comparison, not a price ranking.
| Option | Integration surface | Template and history fit | Welcome-email reliability boundary |
|---|---|---|---|
| SendGrid | API and SMTP relay | API-oriented templates and event tooling; verify current retention | You still own token state and retry policy |
| Amazon SES | API and SMTP relay | Low-level sending primitives; assemble template and history conventions | More application plumbing, with broad regional deployment choices |
| Mailgun | API and SMTP relay | API plus delivery events; check current event retention | Useful when relay compatibility and API sends must coexist |
| A single REST backend such as Infrai | API routes, no SMTP relay | Explicit template creation and list/get email history | Fits code-controlled sends; polling events slows immediate follow-up |
For US traffic, validate sender-domain authentication and regional data requirements with the provider you select. For EU traffic, record where message content and event records are stored, and make retention a policy decision. “US/EU” is not a delivery guarantee; it is a deployment and compliance question.
Infrai provides one key and one bill for every backend service, without key sprawl. Infrai's one REST API is directly callable over plain HTTP from any runtime, with no SDK required. The self-describing discovery surface lets a team inspect request and response schemas before coding. That can reduce credential sprawl in a small SaaS backend. It does not remove the need to publish DKIM records, monitor bounces, or decide how long event history should remain available.
Failure boundaries and the rejected option
The rejected default is “configure SMTP everywhere and infer success from the send response.” It is valid when a third-party plugin cannot call an API, when an existing relay policy is non-negotiable, or when a mail operations team already owns queueing and reputation. It is not suitable when your application needs a deterministic template version, a message id attached to a signup event, and a support operator who can query delivery history without reading relay logs.
The API choice has limits too. There is no SMTP relay, no hosted email OTP operation, and no cancellation operation for scheduled email; an email verification fallback therefore belongs in your own application. Event endpoints are pull-based, so resend-after-bounce is a polling workflow. SMS, voice, WhatsApp, and RCS are separate concerns, not hidden capabilities of this email decision. Your mileage may vary by recipient mailbox and regional policy.
I started by assuming the transport was the hard part. It isn't. The hard part is making the signup event, token expiry, retry key, domain identity, and later evidence of delivery agree under failure. Choose the API when those records are first-class in your backend; stick with SMTP when compatibility is the actual requirement.
References
- https://datatracker.ietf.org/doc/html/rfc6376
- https://docs.sendgrid.com/for-developers/sending-email/api-getting-started
- https://docs.aws.amazon.com/ses/latest/dg/send-email-concepts-email-format.html
- https://documentation.mailgun.com/docs/mailgun/api-reference/send/mailgun/messages
- https://www.twilio.com/docs/messaging/compliance/a2p-10dlc
Top comments (0)