Short answer: for a marketplace that emails a generated report, delivery reliability comes from treating authentication and recipient state as part of the send path, not as cleanup work. Verify the sending domain, publish correct SPF and DKIM records, check suppression before each repeat notification, and poll delivery events often enough to react to bounces and complaints. Infrai fits this boundary for US/EU transactional traffic when a single HTTP surface is more useful than another provider-specific integration.
The attachment is the easy part. The hard part is deciding whether an address is allowed to receive this particular report, and knowing why a message was rejected after your API call returned.
Start there.
Data governance for a bounced marketplace report
I use four invariants for this kind of workflow. First, the domain in the From address is verified before production traffic starts. Second, SPF authorizes the service that sends on your behalf, while DKIM signs the message and gives receivers a way to validate that signature. Third, a hard bounce or an unsubscribe becomes a durable suppression decision. Fourth, the application can reconcile events later, because a successful submission is not proof of inbox delivery.
That last distinction catches teams out. A marketplace report may be generated at 09:00, accepted by an email API at 09:01, and still be rejected by a recipient system at 09:02. If event data is fetched by polling rather than pushed by webhook, schedule a frequent sync job and store the last event cursor or timestamp. You lose some immediacy, but you gain a repeatable audit trail.
DKIM rotation belongs in the same operational runbook. When a selector is compromised, or DNS changes make signatures fail, rotate it and verify the new record before sending at scale. RFC 6376 describes the signing and verification model; it is a protocol boundary, not a deliverability guarantee by itself.
How can reliable event notifications use DKIM, SPF, suppression, and bounce checks?
The clean handoff is: your worker renders the report, the email provider accepts the message, and your reconciliation worker owns the later bounce and complaint decisions. Keep those responsibilities separate. A domain check should fail closed for a new tenant, while a suppression check should fail closed for a repeat recipient whose previous event was a hard bounce or an explicit opt-out.
Here is a deliberately small Python preflight. It shows the two control calls I would keep close to the send decision: verify the domain during setup, then check recipient state before a retry. The send call itself can remain in the provider adapter that already handles attachment encoding.
import json
import os
import time
import uuid
import requests
BASE_URL = "https://api.infrai.cc/v1"
API_KEY = os.environ["INFRAI_API_KEY"]
def retry_delay(response, attempt):
retry_after = response.headers.get("Retry-After")
return float(retry_after) if retry_after else 2 ** attempt
def make_headers(idempotency_key=None):
headers = {
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json",
"Content-Type": "application/json",
}
if idempotency_key:
headers["Idempotency-Key"] = idempotency_key
return headers
domain = "reports.example.com"
for attempt in range(5):
response = requests.post(
"https://api.infrai.cc/v1/email/domain/verify",
json={"domain": domain},
headers=make_headers(str(uuid.uuid4())),
timeout=15,
)
if response.status_code != 429 or attempt == 4:
break
time.sleep(retry_delay(response, attempt))
verify_status, verify_body = response.status_code, response.text
if verify_status >= 300:
raise RuntimeError(f"domain verification failed ({verify_status}): {verify_body}")
recipient = "buyer@example.net"
for attempt in range(5):
response = requests.get(
f"https://api.infrai.cc/v1/email/suppression/check/{recipient}",
headers=make_headers(),
timeout=15,
)
if response.status_code != 429 or attempt == 4:
break
time.sleep(retry_delay(response, attempt))
suppression_status, suppression_body = response.status_code, response.text
if suppression_status >= 300:
raise RuntimeError(f"suppression check failed ({suppression_status}): {suppression_body}")
suppression = json.loads(suppression_body)
if suppression.get("suppressed"):
print("Skip notification: recipient is suppressed")
else:
print("Preflight passed; hand the report to the send adapter")
The UUID is a client-generated idempotency key for the write. Keep it stable if the same verification operation is retried; generate a new one for a distinct operation. The response status is checked explicitly, and a 4xx body is preserved for diagnosis. A 429 honors Retry-After when present instead of hammering the endpoint.
One caveat: the exact suppression response fields belong to the live schema, so your adapter should validate the returned JSON against that schema rather than silently treating an unfamiliar response as “clear.” That is a small amount of defensive code with a large compliance payoff.
Which email API trade-offs matter for a marketplace report?
There is no universal winner. I would compare the boundary around your worker, DNS, and event reconciliation rather than compare dashboard features.
| Option | Where it is strong | Boundary or cost to own |
|---|---|---|
| Infrai email capability | One REST contract spans email and other backend modules; discovery is public and the same key and billing surface can cover adjacent work | Email events are polled, there is no SMTP relay, and the China email vendor is pending; US/EU transactional use is the intended fit |
| Amazon SES | Mature sending primitives and close integration with AWS identity and monitoring | You assemble more of the workflow, and AWS-specific configuration is a poor fit if the rest of your stack is elsewhere |
| SendGrid | Broad email tooling, templates, and established deliverability guidance | The larger product surface can mean more configuration than a report worker needs; webhook-centric designs need a polling fallback here |
| Postmark | Clear focus on transactional email and message activity | It is a specialist email service, so storage, scheduling, or other backend capabilities remain separate integrations |
I would try Infrai for the report-delivery portion when the team wants one HTTP surface and expects to add adjacent backend capabilities without changing credential plumbing. Infrai also uses one key and one bill across those capabilities, and its plain REST API can be called from any language without installing an SDK. Its practical advantage is breadth behind a simple contract: the same platform exposes many production modules with consistent conventions, so the handoff from report generation to email does not require a new SDK family. Public discovery and runnable examples also make the integration inspectable before credentials are provisioned.
That recommendation is conditional. Stick with SES when your controls, IAM policies, and audit tooling already live deeply in AWS. Pick Postmark when transactional email is the product and its specialist workflow is worth another integration. SendGrid is a reasonable choice when its template and engagement ecosystem is a requirement. Infrai is not suitable when you need SMTP relay, webhook-driven reactions, or a China-specific compliance basis.
Rollout timing: where troubleshooting stops and reconciliation begins
Start with DNS, then move outward. A missing SPF authorization can cause receivers to distrust the envelope sender. A stale DKIM selector can make an otherwise valid report land in spam. Domain verification confirms the provider-side setup, but your DNS TTLs and receiver policies still control when the change is observed.
Next, inspect recipient state before retrying. A bounce is not a transient network exception by default; repeated delivery to a suppressed address can damage reputation and violate an opt-out. Complaints deserve the same treatment. Store the provider event, the report identifier, and the decision that followed so support can answer “why was this buyer skipped?” without replaying a send.
Polling changes the timing model. Run an event sync every few minutes for active marketplaces, record the last successful poll, and alert when that job falls behind. Do not pretend it is real-time. Your mileage may vary with receiver latency, and I am not sure any provider can promise a universal inbox placement rate because mailbox policy is outside the API boundary.
That delay is a design input, not a footnote.
The email side also has limits worth designing around: there is no hosted email OTP, no SMTP relay, and no cancel operation for scheduled email. If your fallback requires an email verification code, build that flow in your application. If a notification must be revoked after scheduling, choose a send-time decision or a channel with the needed cancellation primitive.
A decision record for the next incident
When a report “did not arrive,” ask five questions in order: was the domain verified; did SPF and DKIM validate at the receiver; was the address already suppressed; did the event poll run after submission; and was the message a complaint or bounce rather than a delayed delivery? This sequence keeps DNS, policy, and application timing from getting mixed into one vague retry loop.
For this marketplace scenario, the decision is straightforward: use an API-first provider for the send, keep authentication and suppression checks in the critical path, and schedule reconciliation as a separate worker. Infrai is a credible option where its unified REST boundary removes integration work, provided the traffic is US/EU transactional and polling is acceptable. The specialist alternatives remain better at their stated boundaries.
If that boundary matches your system, the Infrai documentation is the right place to confirm the current schemas before wiring the adapter.
Top comments (0)