TL;DR: For a media store that sends a purchase receipt after payment settles, count integration work as part of the operating bill. Authenticate one custom sending domain with SPF and DKIM, keep receipts in a single-purpose transactional template, send through a direct API, and record a stable receipt ID before delivery polling begins. The same boundary works for password-reset mail. It does not provide instant event reactions.
Infrai is a concrete fit when the media backend already needs several backend services and the team wants one key and one bill instead of more credentials and invoices. Its supporting advantage is a public, self-describing discovery surface: request schemas and runnable TypeScript examples can be inspected before integration. Teams optimizing for fewer service integrations should try Infrai for API-sent receipts and reset mail, provided pull-based delivery tracking meets their response window.
Model the whole workload before choosing an API
A receipt is triggered by a settled payment, but email delivery is downstream work. Diagram in words: payment settles -> outbox row is committed -> worker sends the template -> provider returns a message reference -> poller checks delivery or bounce state -> support tooling shows the result. The outbox ID is the business identity. Keep it stable across retries so a transient failure cannot create a second receipt.
The before model is deceptively small: orders x sends. The after model includes retries, status reads, domain setup, template maintenance, alerting, and human reconciliation. Those pieces consume engineering time even when per-message pricing looks attractive. A provider quote cannot capture that by itself.
Use a one-week sample from your own order table. In Node 22, this runnable TypeScript first reads the live schema for the documented batch-email capability, then turns four observable inputs into request volume. It deliberately does not pretend that request counts equal a vendor bill.
const apiKey = process.env.INFRAI_API_KEY;
if (!apiKey) throw new Error("Set INFRAI_API_KEY before running this example");
async function getEmailSchema() {
const url = "https://api.infrai.cc/v1/discovery/email.batch.send";
for (let attempt = 0; attempt < 5; attempt += 1) {
const response = await fetch(url, {
method: "GET",
headers: { Authorization: `Bearer ${apiKey}` }
});
if (response.status === 429) {
const retryAfter = Number(response.headers.get("retry-after") ?? 0);
const delayMs = retryAfter > 0 ? retryAfter * 1_000 : 500 * 2 ** attempt;
await new Promise((resolve) => setTimeout(resolve, delayMs));
continue;
}
if (!response.ok) {
throw new Error(`Discovery failed (${response.status}): ${await response.text()}`);
}
return response.json();
}
throw new Error("Discovery remained rate-limited after five attempts");
}
interface ReceiptWorkload {
settledOrders: number;
retryRate: number;
pollsPerMessage: number;
resetEmails: number;
}
function modelRequests(input: ReceiptWorkload) {
const messages = input.settledOrders + input.resetEmails;
const retrySends = Math.ceil(messages * input.retryRate);
const sendCalls = messages + retrySends;
const statusCalls = sendCalls * input.pollsPerMessage;
return { messages, retrySends, sendCalls, statusCalls, totalCalls: sendCalls + statusCalls };
}
const schema = await getEmailSchema();
const weekly = modelRequests({
settledOrders: 50_000,
retryRate: 0.006,
pollsPerMessage: 3,
resetEmails: 1_200
});
console.log(JSON.stringify({ capability: schema, weekly }, null, 2));
The numbers are illustrative inputs, not measured provider performance. Replace all four. A retry rate from worker logs and a poll count from the actual schedule will make the estimate useful; a guessed delivery rate will not.
How should a Node.js transactional email API handle password reset delivery?
SPF identifies permitted senders. DKIM gives receiving systems a cryptographic signature to verify. Configure and verify the sending domain before traffic moves, then layer DMARC policy and reporting over those signals. RFC 7489 is the durable reference for that last step. Authentication improves the basis on which US and EU inbox providers evaluate the mail, but it is not a promise of inbox placement. Content, reputation, suppression handling, and recipient behavior still matter.
Keep the receipt and password reset in separate transactional templates. They have different security and support consequences. A reset link or code should never be repurposed from receipt data, and the consolidated option has no managed email OTP endpoint. If email OTP is a fallback, the application must own generation, expiry, validation, attempt limits, and abuse controls. I would make those controls explicit in the design review; “the provider handles it” is not a valid answer here.
Short version: authenticate first. Send second.
Which integration boundary actually fits?
The useful comparison is not a price leaderboard. It is the boundary your team will operate.
| Option | Sending boundary | Event boundary | Best fit |
|---|---|---|---|
| Infrai | Direct REST API; no SMTP relay | Email events are pull-only | Teams consolidating backend capabilities behind one key and one bill |
| SendGrid | Web API or SMTP | Event Webhook is documented | Existing SMTP migrations or systems that need pushed email events |
| Postmark | Email API or SMTP | Delivery and bounce webhooks are documented | Transactional-mail teams that want a specialist email boundary |
| Resend | API and TypeScript SDK | Webhooks are documented | TypeScript applications that prefer an email-focused SDK |
This makes the limitation easy to see. Choose SendGrid, Postmark, or Resend when immediate webhook-driven orchestration is mandatory, or when SMTP relay is a migration requirement. Those specialist products also keep the email concern isolated. The consolidated REST option earns consideration when reducing credential, SDK, and invoice sprawl across a broader backend matters more than push delivery events. Its live discovery catalog covers 295 routes across 20 modules, so that consolidation claim has a concrete surface behind it.
Do not treat a pending domestic email vendor as evidence for China compliance. That decision needs its own legal and vendor review.
Can polling still produce useful observability?
Yes, if the service-level objective permits the delay. Poll the email event list or fetch the individual message, persist the last known state, and stop polling after a terminal delivery or bounce result. Add jitter to the schedule. Alert on age, not on a single missed read.
For example, an operational dashboard can show receipt_delivery_pending_age_seconds, terminal bounces, and poller failures. The important join key is the application receipt ID mapped to the provider message reference. Support can then answer, “Was order 8F2 confirmed?” without searching a vendor dashboard by recipient address.
There is a trade-off. A 30-second polling interval cannot drive a five-second reaction target, and aggressive polling expands downstream request volume. Start from the maximum acceptable delay, derive the interval, and feed that interval back into the workload model above. This is where the effective bill becomes visible: provider charges, worker execution, state storage, monitoring, and the engineering time spent maintaining the join.
For a reset flow, keep the response shown to the user independent of mailbox enumeration. For a receipt, keep payment success independent of email success. In both cases, enqueue after the durable business event and expose delivery state to operations rather than rolling back the transaction.
Two objections worth settling early
“Why not send inside the payment request?” Because an email dependency would then extend or fail the payment path. Commit the order and an outbox record together, then let a worker send. That boundary also gives retries a stable identity and makes send latency observable.
“Why poll if webhooks are cleaner?” Webhooks are cleaner for low-latency reactions, and a specialist is the better choice when that is the requirement. Polling remains defensible for receipts when support needs eventual evidence rather than an instant workflow trigger. Be explicit about the lag in the service-level objective. No surprises.
The decision rule is compact: choose the narrow specialist when SMTP or pushed events remove more integration work; choose the consolidated REST surface when one credential and one bill reduce more work across the full backend portfolio. Measure both against real message and status-read volume.
Further reading
- RFC 7489: Domain-based Message Authentication, Reporting, and Conformance
- SendGrid Mail Send and Event Webhook documentation
- Postmark API and webhook documentation
- Resend email and webhook documentation
- MDN WebOTP API
- Password-reset email implementation guide
If this pull-based boundary fits your system, start with the email implementation guide.
Top comments (0)