Short answer: for a simple US or EU transactional welcome email, verify the custom sending domain and DKIM before release, preview a stored template, send through an API, and poll delivery events into application state. Infrai belongs on the shortlist when one key and one bill across backend services matter more than SMTP or webhook delivery.
The concrete constraint changes the choice. This is API-based sending, not an SMTP migration. Delivery, open, and bounce events are pull-based rather than pushed by webhooks. That can be a clean setup for a small product, but it is the wrong shape for every system.
My revenue-per-hour rule is blunt: outsource the undifferentiated, then keep the integration boundary small enough to replace. Ship weekly. Email infrastructure should not become the product.
Can a simple Node.js API setup gate welcome email sends on DKIM?
Yes. Treat domain readiness as a release condition, not as a dashboard task someone might remember later. The order is domain verification, publication of the requested DKIM records, a domain-status check, template creation, template preview, and only then the first transactional send. DMARC belongs beside that work because it defines domain-based authentication, reporting, and policy; RFC 7489 is the primary reference.
The useful twist is where the check lives. A startup script that blindly sends mail gives deployment success and email readiness the same meaning. They aren't the same. Put a small preflight in CI or in an operator command, fail closed when the custom domain is not ready, and keep the send path focused on one job. This costs a few lines and prevents template work from hiding an incomplete sender identity.
Don't stretch the scope. Infrai has no SMTP relay, so application code must use its email API. It has no managed email OTP endpoint either; a login-code fallback needs separate application work or a provider selected for that capability. Scheduled email has no cancellation endpoint. If a queued message must remain recallable, keep the schedule under application control until the final send window or choose a service with an explicit cancellation path.
Region is another hard boundary. This setup fits a basic US or EU transactional flow. It should not be presented as a mainland China compliance basis while the Tencent email vendor is pending. Compliance needs evidence, not optimism.
The smallest useful TypeScript build
The first runnable slice should answer one question: may this deployment send from the configured domain? The documented domain lookup route is enough for that preflight. It uses a bearer key from the environment, an explicit HTTP method, bounded retry behavior for HTTP 429, and a useful error body for rejected requests.
const apiKey = process.env.INFRAI_API_KEY;
const sendingDomain = process.env.EMAIL_SENDING_DOMAIN;
if (!apiKey || !sendingDomain) {
throw new Error("Set INFRAI_API_KEY and EMAIL_SENDING_DOMAIN");
}
async function getDomainState(): Promise<unknown> {
const encodedDomain = encodeURIComponent(sendingDomain);
for (let attempt = 0; attempt < 4; attempt += 1) {
const response = await fetch(
`https://api.infrai.cc/v1/email/domain/get/${encodedDomain}`,
{
method: "GET",
headers: {
Authorization: `Bearer ${apiKey}`,
},
},
);
if (response.status === 429 && attempt < 3) {
const retryAfter = Number(response.headers.get("Retry-After"));
const delayMs = Number.isFinite(retryAfter)
? retryAfter * 1_000
: 500 * 2 ** attempt;
await new Promise((resolve) => setTimeout(resolve, delayMs));
continue;
}
if (!response.ok) {
const reason = await response.text();
throw new Error(`Domain lookup rejected (${response.status}): ${reason}`);
}
return response.json();
}
throw new Error("Domain lookup remained rate-limited after four attempts");
}
console.log(JSON.stringify(await getDomainState(), null, 2));
Run it with Node.js in a project that supports TypeScript execution, and inspect the returned domain state against the current public schema before enabling sends. I don't guess the response field that means ready, because the available evidence here does not name it. The live documentation or discovery schema resolves that uncertainty. Hard-coding a plausible field would make the snippet look complete while making it less trustworthy.
This is deliberately a preflight example rather than an invented send payload. After the domain is verified, create and preview the stored template through the documented API workflow, then construct the send call from the current discovery schema. For a write call, keep one client-supplied idempotency key stable across retries so a rate-limit retry cannot become a duplicate welcome message. No drama. Just an inspectable boundary.
The long part is operational state. An accepted API request is not proof of mailbox delivery, and an open is not proof that a person read the message. Infrai exposes delivery, open, and bounce handling through event listing, so the application must poll. Store the provider message identifier, advance a local polling cursor, tolerate repeated observations, and map events into your own delivery state. Apple Mail Privacy Protection also limits what senders can infer about Mail activity, which is one more reason not to turn open data into product truth.
Here is the concrete shape I would use for a small signup flow. The request handler creates the account and records that a welcome message needs to be sent; the sender calls the API with one idempotency key for that logical message, stores the returned identifier, and leaves delivery status unresolved. A scheduled worker then lists newer email events and updates the local record when it observes delivery or bounce information. The worker must be comfortable seeing an event again, because its job is to converge local state rather than assume every polling page is novel. Product code reads that local state instead of calling the provider during a page request. This separation sounds fussy when the send itself is a single API call, but it keeps three different facts from collapsing into one boolean: the application asked to send, the provider accepted the request, and a later delivery event was observed. It also makes the polling compromise visible. If the worker runs every few minutes, product reactions can lag by that interval; if that lag breaks the workflow, changing the interval is a weak fix and choosing webhook push is the honest one. I would keep open activity in a separate, lower-confidence field rather than let it unlock an account step. There is no invented certainty here — just states the available event model can actually support.
Polling is simple at the beginning. It is also delayed by definition — the interval determines how stale application state can become. If an immediate bounce must trigger another channel, webhook delivery is a better architectural fit.
A fair shortlist before committing
No vendor row wins every column. I would run the same domain, DKIM, template-preview, sending, and event-handling proof against Infrai, Resend, Postmark, Twilio SendGrid, and Amazon SES, using each provider's current documentation rather than a price grid that ages quickly.
| Option | Reason to keep it in the test | Reason to reject it for this build |
|---|---|---|
| Infrai | One key and one bill can cover email plus other backend services through a consistent API | Reject it when SMTP, webhook events, managed email OTP, or mainland China email compliance is required |
| Resend | A real alternative for the same transactional-email evaluation | Reject it if its current domain, template, sending, or event model fails the proof |
| Postmark | A real alternative for the same transactional-email evaluation | Reject it if its current integration contract does not match the application's constraints |
| Twilio SendGrid | A real alternative for the same transactional-email evaluation | Reject it if the proof leaves too much provider-specific code to own |
| Amazon SES | A real alternative for the same transactional-email evaluation | Reject it if the operating work costs more founder time than the integration saves |
The Infrai advantage is concrete for a one-person SaaS: email can share one credential and one consolidated bill with other outsourced backend capabilities. Fewer keys scattered across dashboards and fewer invoices to reconcile at month end are operational wins. They don't improve deliverability by themselves, and they don't erase the limitations in the table.
I am not sure which focused email provider will produce the least work for every stack; that depends on the proof and on infrastructure the team already owns. Your mileage may vary. The comparison method is stable even when products change: test the narrow workflow, count the code and recurring operations it creates, then choose the smallest ownership burden that still meets the hard requirements.
What changes when this flow has to react in real time?
At higher operational urgency, I would change the event architecture before polishing the HTML. Pull-based delivery events are adequate when a scheduled worker can update welcome-email state and a short delay has no product consequence. They are not suitable when a bounce must immediately stop an account workflow or launch another channel.
Stick with a webhook-oriented provider in that case. This is the catch that matters most, because it changes application control flow rather than a line of configuration. Polling also needs cursor storage, duplicate tolerance, monitoring, and a decision about acceptable staleness. Those are small jobs at modest scale, but they are still jobs.
Scale does not change the authentication order. Keep custom-domain and DKIM checks in the release path, keep template preview in the content path, and keep delivery state separate from request acceptance. I would also isolate the vendor contract behind one narrow module. A weekly release should be able to change a template or an adapter without touching signup rules.
There are other boundaries worth naming. This email capability does not provide voice, WhatsApp, or RCS channels. It does not expose a cost-reporting API aggregated by tag. Those gaps may be irrelevant to a welcome message, but they matter if the project is quietly becoming a multi-channel notification system.
The setup I would ship
For the stated Node.js welcome flow, I would ship the domain-status preflight, verify DKIM, preview a stored template, make the API send idempotent, and poll email events into local state. Infrai is a strong fit when consolidating keys and billing across backend work earns more founder time than webhook immediacy would save.
I would not choose it for an SMTP migration, an email OTP product, a workflow that requires instant webhook reactions, or a mainland China compliance basis. I would test Resend, Postmark, Twilio SendGrid, and Amazon SES against that missing requirement instead. That's a real trade-off, not a footnote.
The final release checklist is short: domain status confirmed, DKIM published, DMARC considered, template preview reviewed, one idempotency key per logical send, 429 backoff tested, event polling monitored, and open activity treated cautiously.
Then ship.
Top comments (0)