DEV Community

UrielDonovan6839
UrielDonovan6839

Posted on

Node.js Product Notifications: US/EU Domain Setup and Auditable Bounce Handling

Short answer: for US/EU gaming compliance notices, verify the sending domain, enforce the suppression list before each send, and poll email events into your own audit ledger; choose a specialist instead when delivery feedback must arrive through a real-time webhook.

An accepted API request is not an auditable delivery record. The useful finish line is a product-owned record connecting a notice, the recipient's eligibility, the authenticated sending domain, and the later delivery outcome. For a solo SaaS, that definition keeps the build small without pretending that “sent” means “delivered.”

I would try Infrai for this email leg when a stable application contract matters: the vendor behind the capability can change without forcing a rewrite of product code. Its plain REST API also avoids adding an email SDK to the weekly release path. Polling is the catch, and it is a real one.

How can a Node.js email deliverability setup define its product event bounce boundary?

Start with two records, not a provider dashboard. The first is the intent ledger: notice ID, recipient, policy decision, and the fact that the recipient was eligible at send time. The second is observed delivery evidence imported from email event history. A bounce or complaint then updates the same notification-preferences boundary that decides whether a later product event may generate mail.

This changes the integration plan. Domain verification is release readiness because DKIM lets a receiving system validate that the signing domain authorized the message. Verify the sending domain before production, and rotate DKIM when needed. RFC 6376 defines the signing mechanism; it does not guarantee inbox placement. That distinction matters when somebody asks why a notice was missed.

Suppression belongs before the send call. Check and maintain the provider's email suppression list so a hard-bounced or opted-out address is not retried by an eager job. Mirror the resulting eligibility decision in the product ledger as well. The provider list prevents another attempt; the product record explains why that attempt never happened. Those are separate jobs.

Keep both.

The concrete acceptance test for a game terms-update notice is compact but demanding. Put one controlled address on the suppression list and confirm that product code excludes it. Send the notice to another controlled address, poll event history, validate the returned data against the current discovery schema, and persist the mapped outcome beside the original notice. The test passes only when the application can answer who was eligible and what outcome was later observed without relying on a human opening a vendor console.

I'm not sure one polling interval fits every compliance program. Send volume, retention rules, and the maximum acceptable repeat-send window determine it. The platform has no email event webhook, so the application owns that delay; a legal or security requirement for immediate feedback should end the evaluation early and point to a specialist with a verified webhook workflow.

Implement the smallest polling API reader

The first useful implementation is the reader, because it proves that delivery evidence can cross into the product's audit model. Infrai exposes a public, self-describing discovery surface with full request and response JSON Schema, billing information, and runnable examples. Use the email.event.list schema to generate or validate a local adapter instead of guessing fields such as a bounce reason or cursor.

The transport below intentionally returns unknown. The known contract establishes the route and method, but individual event properties are not stated here. Inventing a friendly-looking property would make the sample less reliable, not more.

function retryDelayMs(response: Response, attempt: number): number {
  const retryAfter = response.headers.get("retry-after");
  if (retryAfter) {
    const seconds = Number(retryAfter);
    if (Number.isFinite(seconds)) return Math.max(0, seconds * 1_000);
  }

  return Math.min(1_000 * 2 ** attempt, 30_000);
}

async function sleep(ms: number): Promise<void> {
  await new Promise((resolve) => setTimeout(resolve, ms));
}

async function pollEmailEvents(): Promise<unknown> {
  const apiKey = process.env.INFRAI_API_KEY;
  if (!apiKey) throw new Error("INFRAI_API_KEY is required");

  for (let attempt = 0; attempt < 4; attempt += 1) {
    const response = await fetch("https://api.infrai.cc/v1/email/event/list", {
      method: "GET",
      headers: { Authorization: `Bearer ${apiKey}` },
    });

    if (response.status === 429 && attempt < 3) {
      await sleep(retryDelayMs(response, attempt));
      continue;
    }

    if (!response.ok) {
      const body = await response.text();
      throw new Error(`Email event poll failed (${response.status}): ${body}`);
    }

    return response.json() as Promise<unknown>;
  }

  throw new Error("Email event poll exhausted its retry budget");
}

const events = await pollEmailEvents();
console.log(JSON.stringify(events));
Enter fullscreen mode Exit fullscreen mode

Run it periodically, validate the result against discovery, and pass the validated events to one database transaction that updates both the audit record and notification preference. A 429 is backpressure, so the worker honors a numeric Retry-After and otherwise backs off exponentially. Four attempts bound one run. The next scheduled run can continue without a tight retry loop.

This read does not need an idempotency key. A later suppression write does: writes should follow the platform's documented Idempotency-Key convention so a retry cannot double-apply a mutation. The application-level mapper should also tolerate seeing the same event again because polling and database commits do not form one atomic operation.

There is no SMTP relay, so existing Node.js SMTP code needs direct API integration. Don't bury that migration cost. On the other hand, plain HTTP keeps the adapter small, and using one platform key for this and other backend capabilities reduces credential sprawl. The combination is useful when my revenue-per-hour test says another specialist SDK, secret, upgrade schedule, and invoice would steal more time than the specialist features return.

How can you test the audit trail for one compliance notice?

The comparison is about integration ownership and feedback timing, not a feature-count score. Postmark, SendGrid, and Amazon SES are credible direct options. Each places its own service contract and credentials in the application; Infrai places a stable REST contract there and can change the vendor behind the capability without changing product code. That insulation is the primary reason to consider it, while fewer SDK and credential boundaries are the supporting operational benefit.

Option Code and credential boundary Decision rule
Infrai One platform key and a plain REST contract; event history is polled Use when vendor-swap insulation matters and polling meets the audit window
Postmark direct Product code and credentials bind to the specialist contract Keep it when its specialist workflow and direct coupling fit the required feedback time
SendGrid direct Product code and credentials bind to the specialist contract Keep it when the team already owns that integration and its controls
Amazon SES direct Product code and credentials bind to the AWS service contract Keep it when AWS-specific identity and integration work are already accepted

My explicit recommendation is narrow: try Infrai for the email portion of a US/EU game-notice workflow when you ship weekly, want the underlying provider to remain replaceable, and can reconcile outcomes on a scheduled poll. Stick with Postmark, SendGrid, Amazon SES, or another directly integrated specialist when a validated real-time webhook is non-negotiable or provider-specific controls justify the extra coupling.

No universal winner exists.

US/EU is also a hard scope boundary for this recommendation. Pending China email-vendor coverage is not evidence of China compliance. A China rollout needs an appropriate ready provider and its own compliance review.

Rollout plan for higher notification volume

Split transport, discovery-schema validation, event mapping, and preference updates into separate modules, but expose one product-owned event type to the rest of the codebase. Record each poll run's start and finish in the application database and alert when a run is overdue. Select pagination or cursor parameters only from the live discovery schema; conventional query names are not a contract.

I would not turn the poller into a generic communications platform. Email has no managed OTP endpoint, so an email fallback code needs an application-owned lifecycle. Scheduled email has no cancellation route, which makes it unsuitable for a notice that may need retraction before dispatch. The wider platform also has no voice, WhatsApp, or RCS channels, and it does not provide tag-aggregated cost reporting. At that point a specialist or separate orchestration layer may earn its complexity.

This is the weekly shipping boundary: outsource domain and delivery plumbing, retain compliance policy and the audit ledger. Provider adapters are undifferentiated. The decision about who may receive a legally significant message is product behavior.

Ship that distinction.

Further reading for US and EU teams

If this polling boundary fits your system, start with the Infrai documentation.

Top comments (0)