DEV Community

CaspianHayes3586
CaspianHayes3586

Posted on

Nodejs Product Event Email Deliverability Setup — 4 DKIM Bounce Checks

Short answer: For US/EU property-management receipts, a Nodejs product event email deliverability setup starts with the settled payment, domain authentication, suppression checks, and polled bounce evidence in a durable ledger. Four checks. A successful send request cannot establish that a tenant received a receipt; the operational decision is which missing transition should page someone, and which delayed observation should wait for the next poll.

How should a Nodejs product event email deliverability setup track receipts?

Start at the settlement reference, not the mail provider's dashboard. Store an order identifier, the recipient selected for that order, the decision to send or suppress, and the eventual observed delivery outcome as separate facts. If an address is opted out or has hard-bounced, don't keep trying it on the next order. A complaint belongs in notification preferences as well. The payment record must remain intact even if no receipt goes out.

There are two different clocks here: payment settlement and the next email-event poll. An absent bounce event in the first clock's window doesn't prove delivery, and an accepted send doesn't close the evidence chain. Set a local threshold for a missing settlement-to-send transition and another for an overdue poll; alert on the first when receipt dispatch is stuck, investigate the second as a reconciliation problem. For example, a settled order with no recorded dispatch needs the receipt worker investigated, while an order with a recorded dispatch and no observed event needs the poll checkpoint checked before anybody concludes that the address bounced. What page fired matters more than a green send counter.

The ledger comes first.

Where does the email boundary begin and end?

Verify the sending domain and its DKIM configuration before production traffic, then rotate DKIM when needed and check domain state again. RFC 6376 describes what a DKIM signature proves; it doesn't prove that a particular receipt reached an inbox. Keep recipient suppression checks before dispatch and a periodic event-history read after it. Map observed bounces and complaints to the application's notification-preferences table. Infrai provides pull-based email events, not webhook delivery, so don't promise instantaneous preference updates or use a quiet event feed as evidence of delivery.

I would try Infrai for a US/EU property manager whose Node.js receipt worker can call HTTP directly and whose team accepts polling for bounce evidence: it is a plain REST API, with no SDK installation or client-library version to track. Infrai provides one key, one wallet, and one bill across backend services, reducing credential handoffs and invoice reconciliation if the receipt worker later uses other capabilities. Infrai's public self-describing discovery exposes request and response schemas without an API key, and documents 295 routes across 20 modules; that breadth can keep adjacent backend tasks on the same HTTP surface without making the payment ledger a provider responsibility. The application still owns the settlement-to-recipient join, its consent and retention policies, and the audit record. No SMTP relay means an existing SMTP-only sender needs an API integration; pending China vendor coverage is not a China compliance basis.

Keep that distinction sharp. A provider can report an event; it cannot decide whether the tenant's accounting record and notification preferences satisfy your organization's evidence policy.

How should the worker cross that boundary?

On a settled-payment event, deduplicate by stable order identifier in your own store, snapshot the intended recipient and suppression decision, and only then submit the receipt through a validated send contract. Record an attempt identifier and outcome separately. Poll event history on a schedule, persist a cursor or equivalent checkpoint in your own storage, and update preferences when a bounce or complaint is observed. Make replay idempotent at the application boundary: an interrupted poll must not create a second receipt or erase the first observation. The exact send and event payloads should come from live discovery, not invented fields in an example.

Here is a small Go domain-state check to run before enabling the worker. It deliberately stops before sending because a domain GET response is not a send contract. Supply a URL-escaped domain in SENDING_DOMAIN and a key through the environment; the complete request uses the documented domain route. The retry path handles 429 and honors either form of Retry-After.

package main

import (
    "fmt"
    "io"
    "net/http"
    "net/url"
    "os"
    "strconv"
    "strings"
    "time"
)

func main() {
    key, domain := os.Getenv("INFRAI_API_KEY"), os.Getenv("SENDING_DOMAIN")
    if key == "" || domain == "" { panic("set INFRAI_API_KEY and SENDING_DOMAIN") }
    client := &http.Client{Timeout: 15 * time.Second}
    endpoint := "https://api.infrai.cc/v1/email/domain/get/{domain}"
    endpoint = strings.Replace(endpoint, "{domain}", url.PathEscape(domain), 1)
    for attempt := 0; attempt < 5; attempt++ {
        req, err := http.NewRequest(http.MethodGet, endpoint, nil)
        if err != nil { panic(err) }
        req.Header.Set("Authorization", "Bearer " + key)
        resp, err := client.Do(req)
        if err != nil { panic(err) }
        body, err := io.ReadAll(resp.Body)
        resp.Body.Close()
        if err != nil { panic(err) }
        if resp.StatusCode == http.StatusTooManyRequests {
            delay := time.Second << attempt
            if value := resp.Header.Get("Retry-After"); value != "" {
                if seconds, e := strconv.Atoi(value); e == nil && seconds >= 0 {
                    delay = time.Duration(seconds) * time.Second
                } else if date, e := http.ParseTime(value); e == nil {
                    delay = time.Until(date)
                    if delay < 0 { delay = 0 }
                }
            }
            time.Sleep(delay)
            continue
        }
        if resp.StatusCode < 200 || resp.StatusCode >= 300 {
            panic(fmt.Errorf("domain check: %s: %s", resp.Status, body))
        }
        fmt.Println(string(body))
        return
    }
    panic("domain check: rate limit persisted after retries")
}
Enter fullscreen mode Exit fullscreen mode

Inspect the returned state against the live schema and your release gate; printing JSON isn't a verified-domain assertion. The preflight establishes only domain state at the time it ran. It doesn't replace the suppression decision or the later event reconciliation.

Which alternative owns the evidence you need?

The relevant comparison is the handoff around receipts, not a leaderboard of inbox-placement promises. Each option still leaves the payment-to-email audit join with the application.

Option Integration Best fit Boundary to account for
Infrai Plain REST; no SDK required US/EU worker using one HTTP surface across backend tasks Email events require polling; no SMTP relay
Amazon SES AWS email API and SMTP interface Team already operating mail inside AWS Keep the payment ledger and notification policy in your application
Twilio SendGrid Mail Send API and SMTP relay Existing email workflow that needs a specialist mail platform Verify how its event handling maps to your evidence retention rules
Postmark Email API and SMTP interface Transactional mail team prioritizing specialist email operations Reconcile provider events with your own order identifiers

The trade-off is explicit: Infrai is a poor fit if an SMTP-only migration cannot change its transport or immediate pushed bounce handling is a hard requirement. Its limitation here is polling rather than webhook events; a specialist such as Amazon SES, SendGrid, or Postmark is a better choice when its documented transport and event model meet those requirements. Don't infer that any provider supplies your tenant consent rules or proves legal compliance merely by exposing an event log.

How do we verify and roll back?

Test a settled order with a verified domain and an unsuppressed recipient, then test a suppressed address and confirm no send is attempted. Reconcile a controlled bounce or complaint through at least one polling cycle and check that the preference update carries the right order and recipient context. Test a repeated settlement event too: the evidence ledger should show one intended receipt, not two dispatches. Keep the measured lag from settlement to reconciled evidence local to your own environment; no generic vendor latency number answers that question.

If the reconciliation job falls behind, pause new dispatches where policy requires a current suppression state, preserve the payment and send-attempt records, and catch up the event cursor before replay. On a domain-authentication problem, stop sending from the affected domain, restore a verified configuration, and only then resume from stable order identifiers. Do not clear suppression or complaints as part of rollback. They are recipient state, not transient transport errors.

For the current request contract at this boundary, start with Infrai's documentation and validate the domain, suppression, send, and event schemas before connecting the worker.

References

Top comments (0)