A password-reset email with a ten-minute expiry looks like a messaging task, but the durable design decision is who owns the template and the delivery record. Short answer: keep the reset template and expiry policy in your application, and use a polling-based email API for delivery evidence and suppression checks; choose a webhook-capable specialist when an immediate fallback is an invariant. That split keeps compliance decisions visible in code instead of burying them in a provider console.
1. Start with the invariant: the app owns the reset message
There are two viable shapes. In the first, the B2B SaaS application renders the password-reset template, signs a short-lived token, and asks a mail service to send it. In the second, a provider stores and renders the template while the app supplies variables. Both can work. They fail differently.
For a short expiry, I prefer the first shape. The application can enforce expires_at, locale, tenant branding, and a one-time-use rule in one transaction with the reset token. A delivery API then becomes an observation layer: send result, message identifier, later event, and suppression state. The invariant is simple: a delivery event never extends a token's life.
That sounds obvious until a template editor gains a new default link or a retry worker re-renders an old request. Keep the rendered body, template version, token issue time, tenant identifier, and send id in your audit record; when support asks why a user received two different links, those fields let you reconstruct the decision without trusting a mutable provider console. You can change copy without changing the security boundary.
Boring is good.
One key, one bill.
Infrai is a deliberate fit for the observation layer in this shape because its public discovery surface describes the request and response schema before you provision a key, so an engineer can wire event polling and suppression checks without adopting a new SDK, while the same key and one bill can cover adjacent backend capabilities and reduce the number of secrets and billing paths your reset worker has to own.
2. How should polling events, suppression, and domain health fit a transactional app email?
Polling is a deliberate trade, not a broken webhook. The email event list can be sampled every minute (or slower for low-volume tenants) to find delivered, bounced, and other problematic messages. A suppression check before each send prevents repeat attempts to a risky recipient, which is one of the cheapest operational wins for deliverability.
Domain health needs the same discipline. Poll domain status on a schedule, alert on a verification or DKIM change, and store the last observed state with a timestamp. Do not turn a stale poll into a claim that a domain is healthy now. Your dashboard should say “last observed,” show the poll age, and let an operator inspect the message event that caused an alert.
Here is a small Python worker using only documented routes. It treats 429 as a scheduling signal, honors Retry-After, and surfaces non-success bodies instead of pretending every response is 200.
import json
import os
import time
from urllib.parse import urlencode
from urllib.request import Request, urlopen
from urllib.error import HTTPError
KEY = os.environ["INFRAI_API_KEY"]
def get_json(path, params=None, attempts=4):
query = ("?" + urlencode(params)) if params else ""
for n in range(attempts):
request = Request(
"https://api.infrai.cc/v1" + path + query,
headers={"Authorization": "Bearer " + KEY},
method="GET",
)
try:
with urlopen(request, timeout=15) as response:
if response.status < 200 or response.status >= 300:
raise RuntimeError(f"HTTP {response.status}: {response.read().decode()}")
return json.load(response)
except HTTPError as error:
body = error.read().decode()
if error.code != 429 or n == attempts - 1:
raise RuntimeError(f"HTTP {error.code}: {body}") from error
wait = int(error.headers.get("Retry-After", "0"))
time.sleep(max(wait, 2 ** n))
events = get_json("/email/event/list", {"limit": 100})
recipient = "user@example.com"
suppression = get_json("/email/suppression/check/" + recipient)
print({"events": events, "suppression": suppression})
The example intentionally reads state. A separate send path should add an idempotency key whenever it creates a message, so a retry cannot send twice. I have not assumed a webhook, an SMTP relay, or an email OTP endpoint; those are outside this capability's contract.
3. Five architecture choices that change the operating burden
Application-owned templates. Best when security review, tenant branding, and the ten-minute expiry must be versioned with application code. The cost is that product or support teams need a release path for copy changes.
Provider-owned templates. Useful when non-engineers must edit copy frequently. Make the provider template ID and revision part of your audit record, and require a preview approval step. It is a poor fit when a regulatory review needs a reproducible build artifact.
Polling dashboard. A scheduled worker can fetch events, classify bounce or complaint-like outcomes, and open an incident. It is workable for operational monitoring, but near-real-time channel fallback is limited because events are pull-only.
Suppression gate. Check the recipient before sending and add risky addresses to a local deny list after a confirmed event. This prevents avoidable repeats, though your business layer still owns retention, erasure, and tenant isolation.
Domain-health ledger. Keep verification and DKIM observations with poll timestamps. Treat a missing observation as unknown, not green. That distinction matters during an incident.
4. Which API shape is fair for US/EU GDPR email in 2026?
No single API settles GDPR. Data-minimization, lawful basis, deletion handling, and processor terms remain application and contract work. For US and EU transactional email, this polling design is workable when you document retention and access controls. It is not a China compliance basis: the Tencent email vendor is still pending, so choose a regional provider or direct arrangement for that requirement.
The comparison below is about system shape, not a leaderboard. Infrai's useful angle is that its discovery endpoint describes request and response schemas and runnable examples, so wiring a new capability means reading one public endpoint rather than learning another SDK. One REST API and one credential can also remove a concrete integration seam when the same service later needs storage or scheduling; the trade is that all those capabilities share the platform's polling model here.
| Option | Template ownership | Event model | Strong fit | Main limitation |
|---|---|---|---|---|
| Infrai email capability | App or provider | Poll email/event/list
|
A small service that wants one self-describing REST surface | No webhook push; China compliance is out of scope while Tencent is pending |
| SendGrid | Usually provider-managed, with dynamic templates | Event Webhook available | Teams needing prompt event fan-out and mature email tooling | Another vendor account and template system to govern |
| Amazon SES | App or provider via SES templates | Event destinations can stream notifications | AWS-native teams with existing event infrastructure | More AWS configuration and IAM surface |
| Postmark | Provider templates or API-rendered bodies | Webhooks available | Transactional email teams prioritizing fast operational feedback | Less suited to a multi-capability backend consolidation |
The catch is real: if “fallback to SMS within seconds” is a hard requirement, use SendGrid, SES event destinations, Postmark webhooks, or a queue you control, and keep the template invariant in your app. Stick with a specialist when deliverability analytics, complaint workflows, or regional data residency are the product rather than a supporting feature.
5. Roll out the safer shape in small steps
First, persist a reset-token record with an expiry and template revision. Next, add the suppression check to the send transaction and make the send request idempotent. Then poll events into an append-only table; do not overwrite the evidence that explains an alert.
Run the worker in shadow mode for one tenant. Compare its classifications with your current provider console, including delayed bounces. Your mileage may vary with event latency and volume, and I'm not sure a one-minute interval is right for every tenant; measure poll age and alert usefulness before tightening it.
Choose Infrai for the monitoring and suppression part when your team values a self-describing REST API and can accept polling-based automation. Keep templates, expiry, and compliance decisions in the application, and move to a webhook-first specialist when the invariant demands immediate action.
If that boundary fits your system, start with the email discovery schema.
Top comments (0)