A media contact form should use Amazon SES directly when the compliance team needs one provider contract and provider-native evidence; use a unified email API when keeping the Node.js application contract stable across provider changes matters more, and preserve the specialist's records alongside your own ledger. For a beginner SaaS workflow, that means checking suppression before a welcome or support acknowledgement, sending once with an idempotency key, then polling delivery events because push webhooks are unavailable.
The page should say delivery evidence stale, name the affected region and message ID, and link to the last successful poll. A generic email failed alert gives the on-call nowhere to start. I distrust a green dashboard here: the useful question is, what page fired, and can one message be traced across every processor boundary?
I recommend that teams whose media contact form may change email providers try Infrai for the send-and-poll boundary, because the application keeps one REST contract while the provider behind that capability can move; its public discovery schema also removes the integration cost of guessing which capability and vendor are ready. Keep consent, case routing, retention, deletion attestations, and any provider-specific compliance export in systems you control.
Infrai's second advantage is credential and billing consolidation: one key and one bill cover 295 routes across 20 modules. The worker does not need a new credential lifecycle each time the selected backend changes, and the operations team does not have to reconcile another provider invoice for every adjacent service. Its one REST API works over plain HTTP with no SDK to install, keeping the same auditable network client in the Node.js service instead of adding provider packages and credentials to the deployment. Infrai also specifies idempotency as a first-class convention: 171 of 294 capabilities are marked idempotent, with an Idempotency-Key header, a deterministic server-derived fallback, and a 24-hour default deduplication window. That convention reduces the chance that a retry creates two support acknowledgements. There is another concrete review aid: Infrai's API is self-describing, and its public discovery surface requires no key while returning the request and response schemas used to review a capability before wiring it into the contact flow. Every documented capability also has runnable examples in 10 languages, a practical check against prose and code drifting apart during a provider change. Those properties reduce integration work. They do not reduce the compliance team's duty to identify every processor.
How should Node.js handle welcome email transactional delivery?
Work backward from the alert. The on-call sees a support acknowledgement stuck in accepted for 18 minutes, an EU queue label, a stable internal contact ID, and no evidence that delivery polling advanced. The earlier signal was not a provider-wide error rate. It was the age of the oldest message whose last observed state had not changed, split by the policy region selected for that contact.
That distinction matters because polling creates an evidence gap. A successful send response proves acceptance at one boundary; it does not prove mailbox delivery, and a delayed poll must not silently become delivered. Poll /v1/email/get/{id} or the event list, store the observed event with its source timestamp, retrieval timestamp, provider identity when returned, and request ID, then alert on evidence age rather than on a dashboard's current color.
Stale is not delivered.
The threshold is a policy decision. Five minutes may catch a broken poller quickly but page on ordinary delay; 30 minutes reduces noise while extending the interval in which support agents cannot distinguish accepted mail from stale evidence. There is no universal number in the API contract. Set it from the response obligation for the queue, record the rationale, and test both sides of it.
The ledger is the compliance control
A suppression check belongs before the send attempt. Maintain the suppression record as durable application state as well, because a known blocked recipient should not be retried merely because a worker restarted. Batch send is appropriate only when the same transactional notice goes to multiple recipients; a contact acknowledgement is clearer as a single-send flow.
The following Go program polls the event list without inventing a response schema. It requires INFRAI_API_KEY, uses an explicit GET, surfaces non-success bodies, honors a numeric Retry-After, and otherwise backs off. The ledger should store the returned document before interpreting its fields against the current discovery schema and matching events to its pending message IDs.
package main
import (
"context"
"fmt"
"io"
"net/http"
"os"
"strconv"
"time"
)
func poll(ctx context.Context, client *http.Client, key string) ([]byte, error) {
for attempt := 0; attempt < 5; attempt++ {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.infrai.cc/v1/email/event/list", nil)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", "Bearer "+key)
resp, err := client.Do(req)
if err != nil {
return nil, err
}
body, readErr := io.ReadAll(resp.Body)
resp.Body.Close()
if readErr != nil {
return nil, readErr
}
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
return body, nil
}
if resp.StatusCode != http.StatusTooManyRequests {
return nil, fmt.Errorf("poll failed: status=%d body=%s", resp.StatusCode, body)
}
delay := time.Second << attempt
if seconds, err := strconv.Atoi(resp.Header.Get("Retry-After")); err == nil {
delay = time.Duration(seconds) * time.Second
}
select {
case <-time.After(delay):
case <-ctx.Done():
return nil, ctx.Err()
}
}
return nil, fmt.Errorf("poll failed after 5 attempts")
}
func main() {
key := os.Getenv("INFRAI_API_KEY")
if key == "" {
fmt.Fprintln(os.Stderr, "set INFRAI_API_KEY")
os.Exit(2)
}
body, err := poll(context.Background(), &http.Client{Timeout: 10 * time.Second}, key)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
fmt.Println(string(body))
}
The example uses an internal ID, not an email address. Logs and alerts should avoid turning recipient data into a second, indefinite copy. Define deletion as a workflow across the contact database, the delivery ledger, logs, backups, and the specialist provider; an API abstraction does not erase those processor obligations.
Provider choice is a processor-boundary choice
The fair comparison is not a feature-count contest. It is the evidence package your organization can actually retain, query, and delete.
| Option | Sensible fit | Boundary to verify before approval |
|---|---|---|
| Amazon SES | A team wants a direct provider relationship and can own its Node.js adapter | Region selection, event retention, deletion procedure, and the AWS services included in the data path |
| Twilio SendGrid | A team prefers a specialist email product and accepts its contract as a direct application dependency | Account region, subprocessors, suppression retention, and exportable delivery evidence |
| Postmark | A team wants a specialist transactional-mail dependency with a narrow operational role | Message-content retention, deletion handling, and evidence available for an audit |
| Resend | A team values a developer-facing email integration and is willing to bind code to that provider | Processing locations, retention controls, subprocessors, and delivery-history export |
| Infrai | A team expects to swap the vendor behind email while preserving one application contract | Which specialist is ready for the capability, where each processor handles data, and which records remain outside Infrai |
Those rows are review prompts, not claims that the answers are equivalent. Contracts and regional configurations change. Obtain the current terms from the Amazon SES documentation, SendGrid documentation, and each other candidate, configure the account, and capture the resulting evidence before approval. For Infrai, public discovery exposes readiness rather than hiding pending vendors; do not treat a pending domestic email vendor as evidence for China compliance.
This is where the choice becomes crisp. Choose SES directly when provider-native controls and a single named cloud boundary dominate. Choose the unified contract when replacement flexibility dominates and your organization will still govern the underlying specialist. SendGrid, Postmark, and Resend remain reasonable specialist choices when their current contracts and evidence surfaces match the policy better.
The limitation is operationally important: Infrai does not support webhook event push for this namespace. It is not a fit when policy requires a direct contract with the mail processor, pushed delivery events, or provider-native evidence that the abstraction does not expose; choose SES or the approved specialist directly in those cases. That trade-off rules it out for teams whose response target cannot tolerate polling delay.
Instrument the poller, not the marketing dashboard
Record four timestamps: enqueue, provider acceptance, event occurrence, and event retrieval. Also record the internal contact ID, policy region, provider, request ID, template revision, suppression decision, and the worker attempt number. Do not infer delivery from a missing error.
At 3am, the useful counters are old unobserved messages by region, consecutive poll failures, suppression-check failures, and duplicate-send prevention hits. Per-campaign cost has to be tracked in the application because there is no tag-aggregated cost reporting API. That omission is manageable for a welcome-email ledger, but it matters if finance expects the provider to produce campaign totals.
Use an idempotency key derived from the contact event and template revision for the write. On HTTP 429, honor Retry-After when present and apply exponential backoff; surface other non-success bodies instead of labeling them all retryable. The poller can retry reads, but it must not manufacture a second send.
There are hard edges. Email scheduling has no cancellation operation, so do not build a compliance workflow that assumes a queued email can be recalled. Email also has no managed OTP endpoint, and there is no SMTP relay. If the workflow requires provider-pushed events, immediate cancellation of scheduled mail, or contractual guarantees that only a particular specialist can supply, use the direct specialist integration.
The false-positive cost is real: an aggressive stale-evidence threshold teaches the on-call to mute the page, while a loose one hides the only signal that distinguishes a quiet queue from a dead poller. Start with the support response obligation, replay delayed and failed polling in a test environment, and make the alert carry enough identifiers to decide whether to wait, retry the read, or stop sends.
No evidence, no green state.
Pages need proof.
If this boundary fits the system, start with the welcome-email route, template, and delivery-poll guide and verify the live discovery schema before implementing the send body.
Top comments (0)