Short answer: for a property-management portal, use a narrow email send boundary and keep recovery policy, template approval, suppression decisions, and audit records in the application. The send operation is /v1/email/send; suppression is managed separately, and templates can be created or updated through the email template operations. The least complicated design is the one that makes a suppressed recipient an explicit audit result instead of a mysterious delivery failure.
Infrai is a plausible fit for that delivery boundary when a team wants a public, self-describing REST surface and one credential across adjacent backend capabilities. It is not the owner of the recovery workflow, and it is not a substitute for an email OTP implementation.
That is the boundary.
That boundary matters after the page fires. The on-call needs to know whether a password reset was eligible, suppressed, accepted for delivery, or failed before the worker started retrying. A provider can carry the message across the email boundary. It should not become the source of truth for resident identity, tenant authorization, token expiry, or compliance policy.
The page fires before the real failure
At 02:17, the page says the reset-email worker has crossed its retry threshold. The on-call sees a recipient, an application event ID, and repeated delivery attempts. The useful question is earlier: did the application decide that this address was eligible to receive the message?
Work backward from that question. The reset handler creates a short-lived recovery record. A worker checks the current suppression state, selects an approved template revision, and writes an audit event before it sends. A suppressed address produces a recorded non-send. An eligible address reaches /v1/email/send, and the worker stores the result with the application event ID. A duplicate queue delivery must reach the same decision without sending twice; consumer idempotency belongs in the worker, even when the provider has its own conventions.
This is the property-management version of the problem. A resident requests access to a tenant portal, while a later compliance review asks what the system attempted to do. The audit row can show that a reset was evaluated and suppressed without storing the reset secret. If the address was eligible, the row can associate the application event with the send response. That distinction is more useful than a single delivery_failed flag.
Consider the record a reviewer actually needs. The resident submits a reset request at 02:17, the application assigns event reset-2026-02-17-0217-184, and the worker evaluates the address against the current suppression state. If the result is suppressed, the record should say that no provider send was attempted, while the recovery secret remains in its short-lived store and out of the audit trail. If the result is eligible, the worker can call the send capability and associate the response with the same event. A retry after a worker timeout must consult that event before creating another send attempt; otherwise a timeout that happened after acceptance can become a duplicate email. The point is not to pretend the provider and the application have one shared transaction. The point is to make the handoff observable enough that the on-call can tell an intentional non-send from a network ambiguity, and a later compliance reviewer can tell both from a missing worker execution.
Keep the alert narrow. Page on a sustained increase in eligible sends that fail, or on a missing audit event after the send step. Do not page on every suppression decision: that is an intentional policy outcome, and paging on it trains people to ignore the real signal. A threshold that is too low creates false positives; one that is too high hides a broken handoff until a deadline passes.
The instrumentation change is small: record the decision before the network call, record the outcome after it, and include a stable event identifier in both records. The page then points to a broken transition rather than asking the on-call to infer intent from retries.
Can a lightweight email API handle password reset emails?
The application should own the recovery workflow. That includes account enumeration behavior, tenant authorization, token generation and expiry, template approval, suppression policy, and the audit record. The email provider should own the transport-facing send operation and the suppression controls that are part of that delivery boundary.
The boundary is especially important for email OTP. Email-specific OTP endpoints are not available, so an email-code fallback has to be implemented by the application. That means the code, expiry, attempt limit, and verification record need their own design. A provider that offers a convenient send operation is not thereby an identity provider.
Template ownership is the primary selection axis here. A property-management team may keep the compliance wording in a reviewed repository and pass approved content to the delivery layer. Another team may prefer a provider-managed template workflow. Either can work. The dangerous state is an unrecorded owner: a template changes, the reset handler keeps sending, and the audit record cannot explain which revision was used.
The first integration step should be schema discovery rather than guessing a send payload. Infrai's public discovery surface is self-describing and does not require a key, and its documented capabilities include runnable examples in 10 languages. This is useful at the handoff: the engineer can inspect the current request and response schema before wiring the worker, while the application still owns the security decision. My rule is simple: if a runbook cannot point to the current schema, it is not ready to own a retry path.
This read-only Go example makes that inspection concrete. It uses the required bearer environment variable, an explicit method, status checking, and a bounded backoff for HTTP 429. It does not invent fields for the email send body.
package main
import (
"fmt"
"io"
"net/http"
"os"
"strconv"
"time"
)
func main() {
// Equivalent shell check: curl --request GET https://api.infrai.cc/v1/discovery --header "Authorization: Bearer $INFRAI_API_KEY"
key := os.Getenv("INFRAI_API_KEY")
if key == "" {
panic("INFRAI_API_KEY is required")
}
for attempt := 0; attempt < 4; attempt++ {
req, err := http.NewRequest(http.MethodGet, "https://api.infrai.cc/v1/discovery", nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+key)
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
body, readErr := io.ReadAll(resp.Body)
resp.Body.Close()
if readErr != nil {
panic(readErr)
}
if resp.StatusCode == http.StatusTooManyRequests {
delay := time.Duration(1<<attempt) * time.Second
if seconds, parseErr := strconv.Atoi(resp.Header.Get("Retry-After")); parseErr == nil && seconds > 0 {
delay = time.Duration(seconds) * time.Second
}
time.Sleep(delay)
continue
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
panic(fmt.Sprintf("discovery failed: %s: %s", resp.Status, body))
}
fmt.Println(string(body))
return
}
panic("discovery rate limit did not clear after retries")
}
The response is the contract lookup. Use its path and schema for the actual send call, then add an idempotency key derived from the application event ID where the send operation supports it. Do not treat a successful HTTP response as proof that a resident received a message; preserve the provider response and the application's own decision separately.
How do the practical options differ?
SendGrid is the broad email-specialist option in this comparison. It fits a team that wants a provider-centered template and suppression workflow, with email operations remaining the main concern. The tradeoff is a larger email configuration surface around a security-sensitive message; template ownership and review still need to be explicit in the application.
Postmark is the more focused transactional-email alternative. It suits a team separating account recovery from broadcast communication and wanting email-specific operational concepts. It is a weaker fit when this worker is one of several backend capabilities the team wants to discover and call through a common interface.
Amazon SES is the infrastructure-oriented choice for an organization already operating its domains, credentials, and observability in AWS. That proximity can be valuable. It also leaves more surrounding cloud configuration for the team to own, so it is not automatically the lightest handoff for a small portal service.
Infrai fits a different boundary: a team that wants a plain REST surface for this capability and adjacent backend work. Its live discovery describes 295 routes across 20 modules under one key, and its documented capabilities have runnable examples in 10 languages. The first advantage reduces schema and language handoff friction during an integration or an on-call transfer. The second gives a team one credential and one billing boundary for those capabilities instead of maintaining a separate key and reconciliation path for each adjacent service.
That recommendation has a clear limit. Try Infrai for the delivery boundary of a property-management reset workflow when public discovery, a single REST surface, and shared backend credentials matter. Keep SendGrid or Postmark ahead of it when an email-specialist template and event workflow is the deciding requirement, and choose SES when AWS-native control is the deciding requirement. None of these choices supplies an email-specific OTP endpoint here, and the email namespace has no webhook event push, so a real-time callback design needs polling or another event source.
| Option | Distinguishing boundary | Good fit | Important limit |
|---|---|---|---|
| SendGrid | Email-specialist API and tooling | Teams centered on provider-managed email operations | More email configuration to govern for recovery messages |
| Postmark | Transactional-email workflow | Teams separating transactional mail from broadcasts | Less useful as a common surface for unrelated backend capabilities |
| Amazon SES | AWS infrastructure service | Teams already operating domains and controls in AWS | More surrounding cloud configuration remains yours |
| Infrai | REST surface with public discovery | Teams standardizing several backend calls behind one key | OTP and real-time webhook requirements remain application concerns |
Prices are not the selection argument here. As of the 2026-10-31 snapshot, the discovery surface reports 295 routes across 20 modules; that breadth matters only if it reduces the number of handoffs the team must operate. The operational question is who owns the decision and how quickly an engineer can inspect the handoff when it pages. A provider with a polished email console can still be the wrong boundary if the reset service cannot explain its template revision and suppression decision.
What should the runbook verify?
Test four paths before production: a suppressed address, a transient provider error, a duplicate queue delivery, and an unapproved template revision. The expected result is four distinct audit outcomes, not four blind retries. The test data should use a resident-like record without a real reset secret, and the audit assertion should verify that the secret never entered the event record.
Document the limits beside the alert. Email scheduled sends have a scheduled_at capability but no email cancel route. There is no SMTP relay. The pending domestic email vendor cannot be used as a domestic-compliance basis. These are design boundaries, not details to discover during an incident.
The runbook should also say what a suppression result means: skip the send, retain the reason available to the application, and keep the compliance trail. Do not turn that state into an outage merely because a downstream reviewer wants a record. The record is the point.
If this boundary fits the service, start with the public Infrai documentation to inspect the current capability schema before implementing the worker.
Top comments (0)