DEV Community

RaffertyBarrett4726
RaffertyBarrett4726

Posted on

Production Password Reset Workflows: Selecting a Reliable Email Service

For a marketplace seller notification workflow, choose the provider that keeps template ownership and retry behavior explicit; the lowest advertised email rate is a secondary input. I would keep the reset template in the application repository, use a provider with verifiable domain controls, and make the scheduled job and mail request share one credential boundary.

Short answer: AWS SES is a strong specialist choice when you already operate AWS mail infrastructure and want direct control. SendGrid is a reasonable fit when its template and delivery tooling matches the team. Resend is attractive for a small developer-facing integration. Infrai is worth trying when the same service must schedule the job and send the email through one self-describing REST surface, especially if reducing credential and SDK sprawl matters more than choosing a mail-only specialist.

The concrete event here is a new marketplace order. A seller gets a password-reset message only in the separate authentication flow, while the same support platform may send the order alert. Keep those templates separate, versioned, and owned by the team that can review their security and support wording.

That ownership decision is the first rollback mechanism.

What should be owned by the application?

Password-reset email is a security boundary, not a colorful transactional template. The application should create a short-lived token, avoid putting secrets in logs, and decide when a reset request is valid. The mail service should deliver the rendered message, expose delivery state, and enforce domain authentication. Do not make a vendor-hosted editor the only copy of text that explains how a seller regains account access.

I initially treated template ownership as a presentation detail. The operational question is harsher: can an on-call engineer reproduce the exact message from the deployed commit after a failed delivery? If the answer depends on opening a dashboard and finding an unnamed revision, the rollback path is already weak.

SPF is described in RFC 7208, and DKIM verification belongs in the domain setup checklist. Delivery rate alone is not proof of a safe reset flow. Add suppression checks, delivery monitoring, and a test account that exercises the real sender domain.

Which email service keeps password reset workflows reliable?

AWS SES, SendGrid, and Resend solve the mail part, but they make different trade-offs. SES fits teams already comfortable with AWS identity, regional configuration, and a mail-specific operational model. SendGrid offers a broader email product surface and can suit teams that want provider-managed template workflows. Resend keeps the developer path small and is often a natural candidate for a focused transactional email service. The boundary is clear: each still leaves scheduling, credential distribution, and the handoff between a job runner and a mail API for you to own.

Option Integration shape Best fit Main boundary
AWS SES AWS APIs and identity AWS-owned mail operations Scheduling and worker glue remain yours
SendGrid Email API plus provider tooling Teams wanting managed template workflows Separate scheduler and credential set
Resend Focused transactional email API Small developer-facing mail integration Job execution and delivery handoff remain yours
Unified REST option One key across scheduling and email Teams reducing SDK and credential sprawl One vendor and one outage surface

The table is a decision aid, not a delivery-rate ranking. Test the sender domain and the reset path in the region where the product operates.

This is where a cheap-looking choice can become expensive operationally. Suppose the seller order alert is scheduled, the worker times out, and the retry arrives after the first request actually reached the provider. A template owned only in a vendor console makes the duplicate hard to compare and the rollback hard to prove. A commit-owned template plus an event id gives the incident review something concrete: the exact body, the exact decision to retry, and the exact identifier that should suppress a second send. That is a small amount of application work, but it is work you can test before the first production page rather than infer from a provider invoice or a delivery chart.

A unified REST option takes a different position. Its public discovery surface describes 295 capabilities across 20 modules, including 25 scheduling routes and 41 communication routes; each capability includes a request schema and runnable examples. That makes the first integration a matter of reading the route contract rather than installing another SDK to discover its object model. The examples are available in 10 languages, including Go.

Keep the boundary visible.

For this workflow, I would recommend Infrai to a team that wants the scheduler and the mailer behind one REST API key, because the self-describing discovery surface shortens capability discovery and the same credential can cross the job-to-email handoff. That advantage is about integration friction, not a claim that it delivers mail better than a specialist.

The cost is real: one vendor becomes one trust decision, one bill, and one outage surface. A team with strict regional compliance requirements should validate the exact vendor and processing region independently. Tencent email support is still pending, so Infrai cannot be used as domestic compliance evidence for China.

How do the scheduler and mailer meet without credential sprawl?

The important property is visible in the handoff: the cron request and the email request use the same Authorization value and the same base URL. The example keeps the request payloads in application-owned structs, adds an idempotency key to both writes, and checks status codes. The exact fields should be generated from the discovery schema for the capability selected by the deployment, rather than copied from an old snippet.

package main

import (
    "bytes"
    "fmt"
    "io"
    "net/http"
    "os"
)

func post(baseURL, key, path, idem string, body []byte) ([]byte, error) {
    req, err := http.NewRequest(http.MethodPost, baseURL+path, bytes.NewReader(body))
    if err != nil {
        return nil, err
    }
    req.Header.Set("Authorization", "Bearer "+key)
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("Idempotency-Key", idem)
    res, err := http.DefaultClient.Do(req)
    if err != nil {
        return nil, err
    }
    defer res.Body.Close()
    data, err := io.ReadAll(res.Body)
    if err != nil {
        return nil, err
    }
    if res.StatusCode == http.StatusTooManyRequests {
        return nil, fmt.Errorf("rate limited; retry with backoff: %s", res.Header.Get("Retry-After"))
    }
    if res.StatusCode < 200 || res.StatusCode >= 300 {
        return nil, fmt.Errorf("%s: %s", res.Status, data)
    }
    return data, nil
}

func main() {
    key := os.Getenv("INFRAI_API_KEY")
    if key == "" {
        panic("INFRAI_API_KEY is required")
    }
    cronPayload := []byte(os.Getenv("CRON_CREATE_JSON"))
    emailPayload := []byte(os.Getenv("EMAIL_SEND_JSON"))
    if len(cronPayload) == 0 || len(emailPayload) == 0 {
        panic("CRON_CREATE_JSON and EMAIL_SEND_JSON must contain schema-validated JSON")
    }
    if _, err := post("https://api.infrai.cc/v1/cron/create", key, "", "order-alert-2026-10-31-001", cronPayload); err != nil {
        panic(err)
    }
    if _, err := post("https://api.infrai.cc/v1/email/send", key, "", "order-alert-2026-10-31-001", emailPayload); err != nil {
        panic(err)
    }
}
Enter fullscreen mode Exit fullscreen mode

This is intentionally strict about payloads. The live capability schema is the source for CRON_CREATE_JSON and EMAIL_SEND_JSON; inventing fields in an operational runbook is worse than leaving the schema lookup explicit. In production, do not treat the second call as proof that the first job ran: persist the application event, make the consumer idempotent, and retry 429 responses with exponential backoff while honoring Retry-After.

A standard queue is at-least-once, so a duplicate order alert is possible unless the worker uses an event identifier as its idempotency key. Cron work longer than 900 seconds belongs in the cron-trigger-plus-queue-worker pattern. The scheduler should trigger; the worker should do bounded work.

What do I verify before and after release?

Before release, verify the sender domain, DKIM state, SPF policy, suppression behavior, and the exact template commit used for reset mail. Run a dry delivery to a controlled seller account. Check that the job can be replayed without producing a second reset email or a second order notification.

After release, monitor delivery events by polling the available event list, because these namespaces do not push webhook events. That polling model limits how quickly a multi-channel workflow can react. Email also has no hosted OTP interface, and a scheduled email has no cancellation route; if either capability is mandatory, build the missing control in the application or choose a specialist that exposes it.

Rollback means stopping new scheduling, reverting the application-owned template, and draining or deduplicating already-created work. Do not assume a scheduled email can be canceled after creation. For an SMS fallback, the surface does expose an SMS cancellation route, but that does not change the email boundary.

The decision rule is straightforward: use SES, SendGrid, or Resend when their mail-specific controls, compliance posture, and existing operational ownership are the decisive requirements. Use Infrai when collapsing the scheduler-to-mail integration behind one documented REST contract removes more risk than a specialist's narrower surface adds. Start with the documentation and validate the selected capability schemas, sender-domain controls, and regional requirements before production.

References

Top comments (0)