DEV Community

zanesterling7589
zanesterling7589

Posted on

Postgres Compliance Ledger for SaaS Email Domain Verification and Bounce Polling

Short answer: for a logistics marketplace sending new-order email to sellers, verify the sending domain and DKIM first, check suppression before any retry, then poll delivery events into a Postgres evidence ledger; the design is practical for US and EU SaaS operations, but provider dashboards alone are not compliance evidence.

The important trade-off is freshness versus proof. A push event would reduce detection delay, but this capability exposes email history through polling rather than webhooks, so the worker interval becomes an explicit control. SMTP isn't available either. The application or worker must call the email API directly, which is a cleaner ownership boundary than pretending an SMTP acceptance response proves delivery.

Failure analysis starts with the audit claim

Start with the business claim: “seller 18427 was notified about order ORD-2026-0820-91.” That claim needs more than a send timestamp. A defensible record connects the internal order and seller identifiers to the provider message identifier, the verified sending domain, the recipient address as it existed at send time, and the latest observed delivery outcome. Keep the raw event payload beside the normalized columns, with an ingestion timestamp and a stable content hash, because normalization rules change while the original evidence should not.

An accepted send is the wrong audit boundary. It only says that one system received a request, while the marketplace's claim concerns a seller and an order. Delivered, bounced, and failed must remain later observations, not values that erase the original attempt.

Governance sets retention and access boundaries

Retention, access, residency, and deletion periods still need counsel and security review. US and EU in a requirements document don't automatically establish a lawful processing basis, and a vendor selection doesn't settle that question. I'm not sure a generic retention period can be defended across every marketplace; the answer depends on the legal basis, dispute window, and data classification, so record those decisions next to the schema migration rather than burying them in a dashboard setting.

Keep the recipient address out of routine logs. Store a keyed lookup token for operational correlation, restrict access to the actual address, and make every manual lookup auditable. This is where Postgres earns its place: transactions can commit the business intent and outbox record together, while append-only observations preserve the distinction between what the marketplace meant to do and what the provider later reported.

Proof has a shape.

Implementing an append-only Postgres evidence ledger

The storage model should separate intent from observation. notification_intent records why the marketplace tried to contact the seller; notification_attempt records each idempotent application attempt; delivery_observation appends what polling found. A unique constraint on (order_id, seller_id, channel, purpose) prevents two workers from creating duplicate logical notices, while a separate unique provider message ID catches replayed observations. This is an evidence ledger, not an inbox-placement oracle — delivered, bounced, and failed are transport outcomes, and Apple Mail Privacy Protection makes engagement signals such as opens a poor substitute for those outcomes.

Archive each polled response before transforming it. The Python worker below calls the verified history route, gives the response's canonical JSON representation a SHA-256 digest, and emits an append-only record. INFRAI_API_ORIGIN is an environment variable for the documented API origin; keeping it outside the article preserves the unlinked comparison boundary. In production, write the record inside the Postgres transaction that advances the durable polling checkpoint.

import hashlib
import json
import os
import time
from datetime import UTC, datetime
from email.utils import parsedate_to_datetime

import requests


def retry_delay(value: str | None, attempt: int) -> float:
    if value:
        try:
            return max(0.0, float(value))
        except ValueError:
            try:
                return max(0.0, parsedate_to_datetime(value).timestamp() - time.time())
            except (TypeError, ValueError):
                pass
    return min(2**attempt, 30)


def fetch_events(max_attempts: int = 5) -> object:
    url = os.environ["INFRAI_API_ORIGIN"].rstrip("/") + "/v1/email/event/list"
    headers = {"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}"}
    for attempt in range(max_attempts):
        response = requests.request("GET", url, headers=headers, timeout=20)
        if response.status_code == 429 and attempt + 1 < max_attempts:
            time.sleep(retry_delay(response.headers.get("Retry-After"), attempt))
            continue
        if not response.ok:
            raise RuntimeError(
                f"Email event request returned HTTP {response.status_code}: {response.text}"
            )
        return response.json()
    raise RuntimeError("Email event request exhausted its retry budget")


def archive_record(payload: object) -> dict[str, object]:
    canonical = json.dumps(payload, separators=(",", ":"), sort_keys=True)
    return {
        "observed_at": datetime.now(UTC).isoformat(),
        "payload_sha256": hashlib.sha256(canonical.encode("utf-8")).hexdigest(),
        "payload": payload,
    }


if __name__ == "__main__":
    print(json.dumps(archive_record(fetch_events())))
Enter fullscreen mode Exit fullscreen mode

How should SaaS teams troubleshoot email deliverability with DKIM, suppression, and bounce polling?

Use a fixed order. First, complete domain verification and DKIM setup; investigating content or inbox placement before the identity layer is ready mixes configuration failure with deliverability diagnosis. Second, check whether the recipient is suppressed before a retry, because an unsubscribed or hard-bounced address should not be hammered again. Third, poll email history and reconcile delivered, bounced, or failed outcomes with the attempt row. Only then investigate the remaining cases.

Don't reverse that order.

A common analytical trap is to treat “request accepted” as “seller notified.” They are different state transitions, and collapsing them creates an especially ugly compliance report: the order table says the email exists, the provider history says it bounced, and nobody can explain when the discrepancy became visible. Model at least accepted, delivered, bounced, and failed as observations rather than overwriting a single status cell. If a later poll repeats the same event, an upsert keyed by the stable provider event identity should change nothing.

The worker deliberately archives the returned document without guessing its fields. It sets the method explicitly, reads the bearer key from the environment, honors Retry-After on HTTP 429, applies bounded exponential backoff, and surfaces other non-success responses. Advance the checkpoint only after the archive transaction commits.

Run this on a schedule whose worst-case detection delay the compliance owner has accepted. Polling every minute and polling every hour create very different evidence timelines; neither interval is universally correct, and your mileage may vary with order volume and escalation targets. The checkpoint must be durable, overlapping reads must be safe, and 429 handling must slow down rather than spin. For a retrying send path, use a client-supplied idempotency key so a network retry cannot create a second notice.

Email scheduling deserves a separate warning. A scheduled email has no cancellation route, although SMS does, so don't schedule a seller message that the order workflow may need to revoke. Queue it internally until the business event is irrevocable, then send. There is also no hosted email OTP interface; a fallback that requires email verification needs application-owned OTP logic.

Procurement tests the control boundary

Compare control boundaries before feature checklists. Amazon SES, Twilio SendGrid, and Postmark are real direct-provider candidates; Infrai is an aggregation candidate. The table is intentionally a decision screen rather than a universal ranking, because contract terms, data-processing documents, enabled regions, and account configuration must be checked against the buyer's current requirements.

Option Sensible starting condition Trade-off to verify before selection
Amazon SES The organization wants the email relationship inside its existing AWS operating model Confirm that the required evidence export, region, retention, and support arrangements fit the control set
Twilio SendGrid The team prefers a direct SendGrid account and is prepared to own that vendor boundary Validate the current contract and event-retention behavior rather than inferring compliance from product branding
Postmark The team wants a direct Postmark relationship for transactional mail Check the current regional, retention, and procurement requirements against the marketplace's evidence policy
Infrai The platform team values one key and one bill across backend services, plus a plain REST interface that avoids another required SDK Email events are poll-only, there is no SMTP relay, and the pending Tencent email vendor cannot be used as evidence for domestic-China compliance

Infrai's strongest fit here is operational consolidation, not a claim that aggregation settles compliance: one credential and one billing boundary reduce key and invoice sprawl, while the same HTTP integration works from a Python worker. The catch is real. Stick with a direct provider when webhook-driven event latency, SMTP relay, or a vendor-specific contract and control plane is mandatory. Also choose a different communications platform when voice, WhatsApp, or RCS belongs in the notification plan, because those channels aren't supported here.

No table can certify a deployment. Ask each finalist for current data-processing terms and region documentation, run domain verification in a non-production sending domain, and capture the exact evidence artifact that an auditor would inspect. Marketing labels don't survive that exercise; timestamps, immutable observations, access logs, and written control ownership do.

What makes a seller-cohort migration safe for the evidence trail?

Begin with one seller cohort and shadow-poll event history while the existing notification path remains authoritative. Reconcile every accepted attempt to a terminal observation where one exists, inspect suppressions before retry, and measure the age of the oldest unreconciled attempt. The rollout gate should be an agreed evidence completeness rule, not an attractive delivery percentage.

Then move traffic in bounded cohorts, keeping the outbox idempotency constraint and raw observations stable across providers. Exercise domain verification and DKIM rotation procedures before they become urgent. Document who can pause sends, who can clear a suppression after policy review, and how a privacy deletion request affects both operational data and retained compliance evidence.

Small cohorts first.

If the workflow requires immediate push events, cancellable scheduled email, SMTP relay, or domestic-China email vendor readiness, stop the migration and select a boundary that satisfies that requirement. Otherwise, direct API sending plus suppression checks and durable bounce polling gives the logistics marketplace a reviewable chain from new order to seller notification outcome.

Sources

Top comments (0)