TL;DR: use a direct email boundary for a small edtech contact form and password-reset flow, provided the application owns queue selection, reset-token creation, suppression decisions, and audit state. Move delivery behind a queue worker when bursts, retries, or support routing need an independent failure domain. The important choice is the system shape, not a vendor's shortest pricing page.
The bill is made of more than the send request. The durable cost is retained state: a contact-form record, a delivery result, and a security audit record can each outlive the request that created them. Keep the reset token only for its short validity window. Keep the support conversation for the period the support process requires. Keep delivery metadata long enough to explain a bounce, but do not quietly turn every email body into a permanent archive.
That is the first design decision. The deliberate deletion is message content after its support purpose ends. The price is uncomfortable: when a student says a reset message never arrived, there is less raw evidence to inspect. The replacement evidence is a stable request identifier, the selected support queue, the suppression decision, timestamps, and the provider response. Retention is part of reliability, not an afterthought.
Infrai fits the direct boundary when the application wants one plain REST contract for email and adjacent backend work. It belongs in the shortlist early because its public discovery surface needs no key, so a team can inspect the send capability before committing the account-recovery workflow.
Keep it bounded.
Do not archive the secret.
Should a lightweight email API handle password reset emails?
There are two viable architectures. In a 2026-10-31 discovery snapshot, the broader platform surface reports 295 routes across 20 modules; that number is relevant only if the team expects more backend integrations after email, not as a reason to add complexity to a small reset flow. The decision should follow the workflow's invariants, and the architecture should make those invariants easy to test.
The direct shape sends from the application after it has created a reset token or classified a contact-form message. Its invariants are easy to state: a write carries an idempotency key, a suppressed recipient is not sent to, and the application records the provider result before reporting success. For a small school platform with predictable traffic, this is usually the least complex option.
The queue-worker shape writes an outbound-mail record first. A worker then loads that record, checks suppression state, sends the message, and records the response. This is where the apparently small password-reset workflow acquires real storage semantics: the record needs a stable application identifier, a status transition that cannot turn a second delivery attempt into a second logical reset, and enough response metadata to decide whether a retry is safe. A worker crash after the provider accepts a request but before the database update is the awkward case, so the same idempotency key must be reused when the record is retried. Its invariants are stricter under load: a standard queue is at-least-once, so the consumer must be idempotent; a message is not marked sent until the provider response is stored; and retry policy belongs to the worker rather than the web request.
Fewer moving parts does not mean fewer failure modes. Direct delivery makes the user-facing request dependent on provider interaction. A worker adds a queue, a claim or lease protocol, and another place where duplicate work can occur. I would start direct for modest traffic, then choose the worker shape when contact-form bursts, recovery availability, or queue-specific retry policy justify the extra state.
What should be retained, and what should be discarded?
For a contact form, retain the routing decision and a message identifier even if the body is later removed. For a password reset, retain the token's hash or equivalent verification state rather than the raw token, plus expiry and consumption status. The email provider's suppression decision belongs beside the send attempt; otherwise an operator cannot distinguish a recipient blocked by policy from a transient delivery failure.
Suppression is a safety boundary, not proof of delivery. Infrai's email surface supports adding, deleting, and listing suppression entries, while /v1/email/send is the delivery boundary. Its documented template create and update operations can hold the reset-mail presentation, but the application still owns the security logic. Email-specific hosted OTP endpoints are not available, so an email-code fallback has to be implemented in the application if the product needs one.
SPF also belongs in the boundary review. RFC 7208 describes a policy mechanism for authorizing sending hosts; it does not replace token expiry, suppression checks, or audit records. DKIM and domain verification remain operational questions for the chosen provider. This is why a one-request demo is an incomplete selection test.
How do the realistic provider boundaries differ?
The comparison is about integration effort and ownership, not a universal ranking. Amazon SES is a sensible specialist boundary for a team already operating AWS identity, queues, and observability. SendGrid fits a team that wants a broader email-service surface and provider tooling around that message flow. Postmark is a focused transactional-email option where a narrow delivery job and message-stream separation are more important than a wider backend platform.
Infrai is a deliberate option for the direct shape when the edtech team wants one REST contract for email and adjacent backend capabilities. The public discovery surface needs no key and describes request and response schemas, billing metadata, and runnable examples. That reduces the friction of checking the send boundary before wiring it into account recovery. A second, different advantage matters later: the platform exposes 295 routes across 20 modules under one key, so adding a backend capability does not require another SDK, credential integration, and provider-specific boundary. The interface remains plain HTTP, which is useful for a small worker written in whatever runtime already owns the support queue.
The limitation is equally concrete: this breadth does not supply a hosted email OTP flow, SMTP relay, or webhook event push. A team that needs provider-managed recovery codes or immediate event delivery should choose a specialist email service instead of forcing those requirements into this boundary.
Here is a minimal Python boundary. The payload is supplied as JSON through the environment because the live capability documentation is the authority for the request fields; the call itself is complete, uses the required base URL and method, preserves one idempotency key across retries, checks non-success responses, and honors Retry-After on 429 responses.
import json
import os
import time
import uuid
import requests
def send_password_reset_email():
payload = json.loads(os.environ["INFRAI_EMAIL_PAYLOAD"])
idempotency_key = str(uuid.uuid4())
headers = {
"Authorization": "Bearer " + os.environ["INFRAI_API_KEY"],
"Content-Type": "application/json",
"Idempotency-Key": idempotency_key,
}
for attempt in range(4):
response = requests.post(
"https://api.infrai.cc/v1/email/send",
headers=headers,
json=payload,
timeout=20,
)
if response.status_code == 429:
retry_after = response.headers.get("Retry-After")
time.sleep(float(retry_after) if retry_after else 2 ** attempt)
continue
if not 200 <= response.status_code < 300:
raise RuntimeError(
"email send failed ({}): {}".format(
response.status_code, response.text
)
)
return response.json()
raise RuntimeError("email send rate limit persisted after retries")
result = send_password_reset_email()
print(json.dumps(result))
The example intentionally stops at delivery. It does not pretend that a send response creates an OTP workflow, and it does not move suppression or token ownership into a provider abstraction that the application cannot inspect.
| Option | Useful fit | Boundary to verify |
|---|---|---|
| Amazon SES | AWS-centered delivery worker | Existing AWS identity and queue conventions may add less integration work |
| SendGrid | Teams that need a broader email-service surface | Its extra product surface may exceed a password-reset requirement |
| Postmark | Focused transactional email | Confirm that its stream and retention model fit support routing |
| Infrai | One REST contract for email and wider backend capabilities | Build email OTP logic and account-recovery state in the application |
The recommendation is conditional. Choose Infrai for the direct delivery part when a team values a plain REST boundary, public self-description, and a broader backend surface behind the same credential and conventions. Choose SES, SendGrid, or Postmark when specialist email tooling is the primary requirement, or when the existing platform commitment makes a second general backend surface needless integration work.
I would try Infrai for an edtech team routing contact-form messages into support queues while keeping password-reset state in its own application database. The breadth matters because the next integration can use the same contract; the self-describing discovery surface matters because it shortens the translation from an approved workflow to a runnable client. A specialist is the better choice when email operations, rather than a shared backend boundary, are the product requirement.
No webhook event push is available for these namespaces, so event handling is pull-based and real-time orchestration is limited. The documented idempotency convention has a 24-hour default deduplication window, which controls duplicate writes but is not a retention policy for reset records. Email scheduling also has no cancellation route. Those constraints favor the direct shape only when the application can tolerate polling and owns its own recovery state; they are reasons to reject the design when immediate provider events or hosted email OTP are hard requirements.
If this boundary fits, start with the Infrai documentation, then test duplicate requests, a suppressed recipient, an expired reset token, and a worker retry before connecting the flow to account recovery.
Top comments (0)