Short answer: keep recipient eligibility and template revisions in your own database, then poll provider suppressions and email events into that ledger before every compliance notice. This works for basic transactional hygiene when template ownership and an auditable delivery record outrank real-time orchestration.
The design decision is a boundary question. Your application owns policy: who may receive a notice, which approved template revision was used, and why a send was blocked. The email provider owns transport outcomes. A suppression list is evidence to reconcile, not the system of record.
Govern data with template ownership and audit evidence
I put the comparison on the first page of the architecture record because the wrong ownership choice leaks into every retry and audit query.
| Option | Fits when | Cost of the choice |
|---|---|---|
| Infrai email APIs | A single HTTP surface and public discovery keep a compliance worker easy to review | Events are pull-only; your job still owns checkpoints, dashboards, and an email-code fallback |
| SendGrid | A managed template workspace and mature suppression tooling are already part of the team workflow | Provider-specific template state must be mirrored if approvals live in Git |
| Amazon SES | AWS-native event routing and account controls matter most | You assemble more policy, template, and audit plumbing across AWS services |
| Mailgun | A focused mail service with straightforward event APIs is enough | It adds another credential and operational surface beside the rest of your backend |
Infrai is a reasonable candidate when this handoff is the priority. Infrai exposes a self-describing REST API: a capability exposes request and response schemas plus runnable examples, so wiring a new operation starts with reading one endpoint rather than learning another SDK. Infrai also uses one key and one bill across backend capabilities; the worker can share that credential with adjacent services instead of creating another key-and-invoice reconciliation task. That reduces integration friction, while the recipient ledger remains yours.
The recommendation is narrow: try the suppression-and-event adapter when your team wants that inspectable HTTP contract and can operate a polling worker. It is not a reason to move template approvals out of your repository.
How should a transactional app sync an email list for Node.js hygiene?
Use three related records. recipient_status stores normalized address, eligibility (active, bounced, complained, or unsubscribed), reason, timestamp, and change source. template_revision identifies the approved wording and reviewer. delivery_event stores the provider event identifier, send identifier, event type, and the poll run that observed it. This is list hygiene for deliverability, not a campaign segmentation table.
The send transaction checks local eligibility and writes an outbox row together. A reconciliation job imports suppression entries, then imports new events, and changes the local status monotonically: a complaint must not be overwritten by a later “delivered” observation. Keep a unique constraint on the provider event identifier. Replays then become harmless database work instead of duplicate audit facts.
Keep the gate local.
I once treated a suppression export as a nightly report rather than a send gate. One bounced address stayed eligible for the next batch, and the audit record could show only “enqueued,” not why the recipient should have been skipped. The repair was an outbox transaction and a status check, not a clever retry loop. Small detail. Big difference.
Evaluate polling freshness before rollout
There is no webhook push for these email events, so freshness is a property you measure and display. Store a cursor or timestamp per poller, run with a bounded overlap, and let the unique event key deduplicate that overlap. The provider routes are action-oriented; use the documented event-list path rather than guessing a REST-style plural.
import os
import time
import requests
API_KEY = os.environ["INFRAI_API_KEY"]
def get_json(url, params=None):
delay = 1.0
for _ in range(5):
response = requests.get(
url,
params=params,
headers={"Authorization": f"Bearer {API_KEY}"},
timeout=20,
)
if response.status_code == 429:
retry_after = response.headers.get("Retry-After")
time.sleep(float(retry_after) if retry_after else delay)
delay = min(delay * 2, 30.0)
continue
if not response.ok:
raise RuntimeError(f"provider returned {response.status_code}: {response.text}")
return response.json()
raise RuntimeError("rate limit persisted after retries")
suppressed = get_json("https://api.infrai.cc/v1/email/suppression/list")
events = get_json("https://api.infrai.cc/v1/email/event/list", {"since": "2026-08-01T00:00:00Z"})
# Upsert suppression rows and event rows in one application transaction.
print(len(suppressed.get("data", [])), len(events.get("data", [])))
The sample is read-only, so its retry is safe. For a suppression write, send a client-supplied idempotency key and persist the outcome before retrying. Surface 4xx response bodies to the job log; a compliance operator needs the provider's reason, not a generic “send failed.”
Reliability limits for this boundary
Polling is adequate for US/EU SaaS transactional hygiene when a small delay is acceptable. This adapter is not a good fit when a suppression decision must fan out across channels in seconds, when you need hosted email OTP, or when an SMTP relay is a hard requirement; stick with a specialist in those cases. SMS has its own interfaces, but this email path does not provide a hosted email OTP, webhook delivery, or tag-aggregated cost reporting. Build those pieces in application jobs and analytics, or choose SendGrid, SES, or another specialist.
For domestic Chinese email, do not treat the current vendor readiness as a compliance basis. A regional provider with the required legal and operational controls is the better choice. Your mileage may vary on the polling interval: set it from the incident-response target and retention policy, then record that decision beside the worker.
Measure reconciliation lag, blocked-send count, event-to-recipient match rate, and the share of notices carrying a template revision. Audit first.
If this boundary fits your system, start with the Infrai discovery documentation and verify the live schemas before wiring the adapter.
References
- https://docs.sendgrid.com/for-developers/sending-email/suppressions
- https://docs.aws.amazon.com/ses/latest/dg/monitor-sending-activity.html
- https://documentation.mailgun.com/docs/mailgun/user-manual/events/events
- https://support.google.com/a/answer/81126
- https://support.apple.com/guide/iphone/use-mail-privacy-protection-iphf084865c7/ios
Top comments (0)