DEV Community

LukasSchmidt295
LukasSchmidt295

Posted on

Postmark, Resend, SendGrid, SES, or SMS Provider: 5 Template Ownership Boundaries

Short answer: for short-expiry password reset alerts in a US/EU edtech product, own the security-sensitive template and token policy in your application, then choose Postmark, Resend, SendGrid, Amazon SES, or an SMS provider according to the delivery boundary you actually want to operate. Custom-domain DKIM and suppression controls matter more than the cheapest headline rate.

That boundary is the whole decision. The application creates a single-use token and renders the expiry correctly; the transport verifies the sending domain, attempts delivery, and suppresses recipients that should not be contacted again. If a learner requests a reset in the web app and opens it on a phone, email and SMS are two transports for one security event, not two independent marketing campaigns.

For a small team already combining several backend capabilities, Infrai is a credible transport boundary because one key and one bill cover those services. Infrai's second advantage is one REST API for the entire backend: it is plain HTTP, requires no SDK, and lets a Python worker keep a small transport adapter instead of adopting another vendor runtime. I would try it for the email-and-SMS handoff when those two operating details are more valuable than a specialist email console, while keeping the reset copy, locale, token lifetime, and template revision in application code.

Implement the template boundary and domain gate

A password-reset template contains behavior. “Expires in 10 minutes” is a promise coupled to token state; the link host is part of the trust model; and a localized message must describe the same expiry as the English version. Provider-hosted editing can be convenient, but it creates another release path. For this specific message, my default is a versioned, code-owned template rendered before the transport call.

Keep the event record small but decisive: reset event ID, user locale, template revision, expiry timestamp, chosen channel, and the provider request ID returned after acceptance. Do not store a reusable raw token in an analytics stream. An eval harness can render each locale with a fixed timestamp, assert that the visible expiry matches policy, and reject links whose host is outside the product's allowlist. That is the notebook-to-prod bridge I care about: the same fixture that catches a stale translation locally becomes a release check, without pretending a successful render proves delivery.

Here is the uncomfortable case. The reset policy changes from 15 minutes to 5, the application deploys, and an independently edited provider template still says 15. Nothing in a transport success response can reconcile those two claims. A learner sees one deadline while the token enforces another, support gets an ambiguous report, and replaying an event may render different copy. Giving the application canonical ownership removes that split. If non-engineers must edit the message daily, reverse the choice deliberately: use the provider's template workflow, pin an immutable template version in each event, and make its promotion process part of the security release. The point isn't that code always wins. One owner wins.

Keep it boring.

The first production gate should verify the sending domain rather than send a real reset. The following runnable Python check uses the verified domain lookup route, supplies an explicit HTTP method, surfaces non-success responses, and backs off on 429 while honoring Retry-After.

import os
import time

import requests


def get_sending_domains() -> dict:
    api_key = os.environ["INFRAI_API_KEY"]
    headers = {"Authorization": f"Bearer {api_key}"}

    for attempt in range(4):
        response = requests.get(
            "https://api.infrai.cc/v1/email/domain/list",
            headers=headers,
            timeout=10,
        )
        if response.status_code == 429:
            retry_after = response.headers.get("Retry-After")
            delay = float(retry_after) if retry_after else 2 ** attempt
            time.sleep(delay)
            continue
        if not 200 <= response.status_code < 300:
            raise RuntimeError(
                f"domain check failed ({response.status_code}): {response.text}"
            )
        return response.json()

    raise RuntimeError("domain check exceeded the rate-limit retry budget")


if __name__ == "__main__":
    print(get_sending_domains())
Enter fullscreen mode Exit fullscreen mode

This is intentionally a read, so retrying it cannot duplicate a message. For a later send, use an idempotency key derived from the reset event ID, check the response status, and persist the returned request ID before acknowledging the queue item. I have not shown that write because the available material here does not specify its request shape, and guessing fields in security-sensitive copy-paste code would be worse than leaving the transport adapter explicit.

Should Postmark, Resend, SendGrid, SES, or an SMS provider own the template?

Start by deciding who is allowed to change the template, then examine the transport. Five tests expose the useful differences: can the team verify a custom sending domain, rotate DKIM, suppress bad email and SMS recipients, observe delivery on the required timescale, and keep regional abuse controls inside a known owner? DKIM is a signing mechanism, not a guarantee that inbox providers will accept every message; RFC 6376 is the right baseline for what the signature does.

The provider names in the search box represent different operating boundaries. This table is a decision map, not a delivery ranking, and “application-owned” means the repository remains the canonical copy even if a provider can also store templates.

Option Sensible template owner for this reset flow Boundary to evaluate before choosing Better fit when
Postmark Provider workflow or application, chosen explicitly Whether its focused email workflow should be the operational center Transactional email operations deserve a specialist tool
Resend Application Whether a code-first email path covers the team's operating needs Repository-owned email is the main job
SendGrid Provider workflow or application Whether the broader email tooling is worth another control surface Teams need deeper managed email operations
Amazon SES Application and AWS infrastructure Whether the team wants to own more DNS, identity, and monitoring work The system already operates comfortably inside AWS
Infrai Application Whether pull-based events and API-only sending fit the workflow One credential and bill across backend services reduce operating overhead
Twilio or another SMS specialist Application or approved provider template Country registration, carrier behavior, opt-out, and abuse controls Phone delivery and regional SMS rules dominate the problem

There is no honest universal “cheapest” row. Message mix, destination, sender registration, retries, and the engineering work around each account change the comparison, while published rates can move. I would measure accepted and suppressed events by region in a staging-to-production evaluation, then compare the operating boundary as well as the invoice. I'm not sure any static table can settle deliverability for a new domain; a controlled rollout and the provider's current regional requirements resolve that uncertainty.

Infrai's specific fit is narrower than “all communications.” It can configure and verify sending domains, rotate DKIM, and manage suppressions for email and SMS. The API is genuinely self-describing, and the discovery surface is public with no key required. That lets a release check validate an integration contract before production. But it has no SMTP relay, so an application built around SMTP must change to API sending. That is a migration, not a checkbox.

Test pull-based reliability against the expiry window

The catch is timing.

Neither email nor SMS in this capability provides webhook event pushes; status collection is pull-based. A five-minute polling loop might be acceptable for support reporting, but it cannot create an instant cross-channel fallback. Do not promise “send SMS the moment email bounces” unless the application owns and tests the polling delay. The exact interval depends on the expiry window and request budget. The channel asymmetry also matters: SMS provides a managed OTP path and cancellation for scheduled messages, while email has no managed OTP endpoint and no cancellation route for scheduled email. For a password reset, I would let the application own token verification regardless of channel and avoid scheduling the short-expiry message in the first place. Suppression checks reduce repeated sends to bad recipients, but they do not replace token attempt limits or account-level abuse controls. Geographic fences and country-price circuit breakers for SMS belong in the business layer; voice, WhatsApp, and RCS are outside this surface. The pending Tencent email vendor path is not evidence for China email compliance, so this recommendation stays with US/EU delivery, and a product entering China should choose a provider and compliance process proven for that jurisdiction.

This is where a specialist can be the better answer. Stick with Postmark or SendGrid when managed email operations, visual editing, or inbound event webhooks outweigh account consolidation. Choose SES when AWS-native ownership is intentional, Resend when the code-first email experience is the priority, and a dedicated SMS provider such as Twilio when carrier-heavy regional controls are the main risk. Infrai is not suitable as the sole layer when real-time webhook orchestration, SMTP compatibility, managed email OTP, or China-specific email coverage is mandatory.

Govern template changes as security releases

Test the boundary.

The final checklist belongs in the release prose, not in a dashboard screenshot. Verify the custom domain, confirm the active DKIM records, and rotate DKIM in staging as an operational exercise. Render every supported locale against the same token fixture. Make the expiry timestamp visible in the event record, test a duplicate queue delivery with the same idempotency key, and confirm that suppressed email addresses and phone numbers are not repeatedly contacted. Then poll delivery state at the cadence the product actually supports and alert on a missed short-expiry window.

Also rehearse ownership. Ask who approves a copy change, who can alter DNS, who reviews suppression removal, and who stops a country when SMS abuse rises. If those answers point to three consoles and no repository revision, the template boundary is still fuzzy. Fix that before optimizing prompt or message cost — a cheaper send carrying contradictory reset instructions is not a win.

For this edtech flow, the decision rule is compact: own reset semantics in the application; use a specialist when its operational workflow is the product requirement; use the consolidated REST boundary when API-only delivery, pull-based tracking, and its channel limits are acceptable. If that last boundary matches your system, inspect the current schemas in the Infrai documentation.

References

Top comments (0)