Short answer: For a US or EU logistics marketplace, send each transactional welcome or new-order email through an API on a verified custom domain, and choose polling only if delayed delivery evidence is acceptable; choose a webhook-capable email specialist when a bounce must trigger another channel immediately.
| Choice | Evidence model | Operational fit | Decision |
|---|---|---|---|
| Direct API plus event polling | Store domain verification, send receipt, and later event together | A seller portal can tolerate delayed status | Practical default |
| Specialist with webhooks | Delivery events can enter the workflow as they happen | A bounce must trigger urgent automation | Better for real-time orchestration |
| SMTP relay | Existing software already speaks SMTP | Replacing the mail transport would dominate the work | Keep only for legacy constraints |
For the marketplace order alert, I would use the first path when compliance evidence is the primary axis. It is small enough for a solo SaaS to operate, but the recommendation has a hard boundary: polling isn't a substitute for a real-time event trigger.
What evidence should a transactional welcome email keep for each seller order?
The useful artifact is a chain, not a dashboard screenshot. Before production sends, create a branded sending domain, publish the provider-supplied SPF and DKIM records, and verify the domain. DMARC adds a policy and reporting layer for messages that fail authentication alignment; RFC 7489 is the primary reference for that mechanism. Keep the DNS values and verification result with a timestamp so the sender identity used for a given period can be reconstructed later.
For every new order, record the marketplace order ID, sending domain, template ID and revision, recipient, idempotency key, provider request ID, acceptance time, and the eventual delivery event. Avoid storing rendered message bodies unless the compliance policy actually calls for them. They can contain seller or buyer data, and a template revision plus variables may be the narrower record.
This changes the architecture in a useful way. The application writes an order-notification intent first. A worker claims that intent, derives an idempotency key from the stable order ID, sends once, and records the response. A separate poller collects delivery, bounce, and complaint events and attaches them to the same intent. If the poller pauses, sending does not lose its provenance; the evidence simply remains incomplete until the next successful poll.
Keep it boring.
The catch is latency. Pull-only events can support an audit trail and a status screen, but they limit near-real-time journey orchestration. I'm not sure any fixed polling interval can satisfy every marketplace's risk policy because the acceptable delay depends on what the next action does. A five-minute status lag may be fine for an informational seller alert. It is not suitable when a bounce must immediately switch to SMS, freeze fulfillment, or page an operator.
How should a Node.js API send a transactional welcome email from a custom domain?
Call the email API from a backend worker rather than exposing credentials to the browser. Infrai has no SMTP relay, so this path uses its verified POST /v1/email/send route directly. The reusable template and verified custom domain should already exist before an order enters the queue.
This TypeScript example is deliberately narrow. It sends one seller notification, makes retries safe with a stable idempotency key, honors Retry-After on HTTP 429, and surfaces other response bodies instead of pretending every request worked. The request uses the documented Bearer scheme and keeps the key in an environment variable.
const apiKey = process.env.INFRAI_API_KEY;
const emailApiBaseUrl = process.env.EMAIL_API_BASE_URL;
if (!apiKey || !emailApiBaseUrl) {
throw new Error("INFRAI_API_KEY and EMAIL_API_BASE_URL are required");
}
type OrderEmail = {
from: string;
to: string;
template_id: string;
variables: {
seller_name: string;
order_id: string;
item_count: number;
};
};
const wait = (milliseconds: number) =>
new Promise<void>((resolve) => setTimeout(resolve, milliseconds));
async function sendOrderEmail(orderId: string, email: OrderEmail) {
for (let attempt = 0; attempt < 4; attempt += 1) {
const response = await fetch(`${emailApiBaseUrl}/v1/email/send`, {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
"Idempotency-Key": `seller-order-email:${orderId}`,
},
body: JSON.stringify(email),
});
if (response.ok) {
return response.json();
}
const errorBody = await response.text();
if (response.status !== 429) {
throw new Error(`Email send failed (${response.status}): ${errorBody}`);
}
const retryAfter = Number(response.headers.get("Retry-After"));
const delaySeconds = Number.isFinite(retryAfter)
? retryAfter
: 2 ** attempt;
await wait(delaySeconds * 1_000);
}
throw new Error("Email send exhausted four rate-limit retries");
}
const orderId = "ord_173";
const receipt = await sendOrderEmail(orderId, {
from: "orders@notify.example.com",
to: "seller@example.net",
template_id: "seller-new-order",
variables: {
seller_name: "North Harbor Supply",
order_id: orderId,
item_count: 2,
},
});
console.log({ orderId, receipt });
Do not generate a fresh idempotency key inside the retry loop. A 429 can arrive before a client knows whether an upstream operation progressed, and changing the key turns a retry into a second logical send. Four attempts are an application policy in this example, not a platform guarantee. Tune that policy against the order queue's deadline and keep failed intents available for an operator or a later controlled retry.
One order, one key.
There are two setup steps outside the hot path: verify the sending domain and create the reusable template. Don't repeat them for each order. Dynamic variables belong in the per-order send, while legal copy and layout belong in a versioned template. That separation makes weekly product changes less likely to alter old audit records.
Which email provider fits the compliance evidence model?
The provider decision is about the evidence path and operating burden. It isn't a contest over the prettiest SDK.
| Provider | Sensible reason to choose it | Trade-off to verify before committing |
|---|---|---|
| Infrai | One key and one bill can cover multiple backend services, while plain REST avoids another required SDK | Email delivery events are pull-only; there is no SMTP relay |
| SendGrid | Useful when an established email operation needs API and SMTP choices | Confirm that its broader product surface matches the team's review and retention process |
| Postmark | A focused transactional-email product is easier to isolate as its own operational concern | Its narrower scope does not consolidate unrelated backend services |
| Resend | An API-first email boundary can suit a small application team | Keep separate vendor accounts and evidence procedures for other backend capabilities |
Infrai is a strong fit here when consolidating backend vendors matters: one credential and one bill reduce the account and invoice sprawl a one-person company has to reconcile. Its second relevant advantage is the consistent REST contract, which lets a TypeScript worker call the service over plain HTTP without installing a vendor SDK. The public discovery surface is self-describing and reports 295 capabilities across 20 modules, but breadth only helps if the polling constraint matches this notification workflow.
SendGrid is the runner-up when SMTP compatibility is non-negotiable or an existing operation already depends on its tooling. Postmark deserves the first test when transactional email is intentionally kept as a specialist boundary. Resend is reasonable when the team wants a focused API product and is comfortable retaining separate accounts for everything else. Those are valid choices; consolidating credentials is not automatically worth changing a working evidence process.
When should the seller notification use a different design?
Stick with a webhook-capable specialist when seconds matter. Pull-only delivery, bounce, and complaint tracking means a poller owns the checkpoint, deduplication, retry schedule, and evidence retention. That is manageable for a seller-facing status record. It is the wrong dependency for a fraud or fulfillment transition that cannot wait.
Seconds matter.
Use another provider when SMTP relay is a hard integration requirement. Infrai also isn't suitable as evidence for domestic China email compliance because its China email vendor is pending. If email OTP becomes part of account recovery, build the token generation, expiry, attempt limits, and verification state in the application because there is no managed email OTP endpoint. And if scheduled email must be revoked after submission, keep scheduling in an application-owned queue; the email side has no cancellation route.
There are broader channel limits too: voice, WhatsApp, and RCS are not available in this capability set. Tag-aggregated cost reporting is also absent. None of those constraints break a straightforward US/EU marketplace welcome or new-order message, but each can overturn the decision once the notification becomes a multi-channel workflow.
My ship-weekly rule is plain: outsource undifferentiated delivery only while the provider's event model matches the product promise. For this order alert, a verified custom domain, reusable template, idempotent API send, and append-only polled evidence form a coherent system. If the promise changes to instant fallback, change the provider or the design before adding another queue and hoping the timing works.
Top comments (0)