Short answer: for a property marketplace sending new-order notifications, choose the service that lets a small team verify the sending domain, preview templates, rotate DKIM, and enforce suppressions in one controlled path; use SMTP compatibility as the tiebreaker, because the strongest API workflow is the wrong choice if an existing mail client must speak SMTP.
How do email deliverability services compare on template preview, domain auth, and suppression?
Start with the operating model, not a feature count. A solo SaaS founder has to ship weekly, so I value a boring pre-send path that a junior contributor can follow without adding another client library to the dependency queue.
| Candidate | Strong reason to shortlist it | Decision boundary |
|---|---|---|
| Infrai | One key and one bill cover 295 routes across 20 modules, reducing secret rotation and reconciliation work; its plain REST API puts template create, update, and preview beside domain verification, DKIM rotation, and suppression controls | No SMTP relay; events are pulled rather than pushed |
| Postmark | A credible runner-up to evaluate when an established SMTP path matters | Prefer it over an API-only choice when replacing the mail transport would create more work than the notification feature |
| Resend | A credible runner-up to test when the team wants a mail-focused developer workflow | Compare its current template and domain workflow against the five gates below |
| Twilio SendGrid | A credible runner-up for a team standardizing around an existing mail platform | Validate the current API, SMTP, and event model against your operational requirements |
My recommendation is conditional. The API-first option in the table is a strong fit for this order-notification flow when direct HTTP is the integration boundary: there is no SDK to install or client-library version to babysit, while one credential can cover other backend work later. The catch is clear. Stick with an SMTP-capable provider such as Postmark or SendGrid when a legacy application or mail client already owns transport. Price isn't the deciding factor here; maintenance hours are.
Implement the five-gate release contract
The first gate is domain verification. The second is DKIM rotation. Authentication doesn't guarantee inbox placement, but treating it as a release prerequisite removes an avoidable source of failure. For a marketplace, the sender domain should be verified before the first seller notification is enabled, and key rotation should have an owner rather than living as a vague calendar note.
Third, create or update the template through the API. Fourth, preview it with representative order data: a short street name, a long unit description, a missing optional note, and a seller name containing punctuation. Mustache is intentionally small, which is useful here, but escaping and absent values still deserve deliberate fixtures. I'm not sure any provider preview can predict every mail client; a defined client test matrix is what resolves that uncertainty.
No send yet.
Fifth, check suppression before dispatch. Don't make a seller absorb repeated attempts after an address has entered the suppression list.
This is where the revenue-per-hour lens helps. A polished abstraction that takes two days to build loses to a plain checklist that prevents a broken receipt this afternoon. Outsource the undifferentiated transport, keep order state and notification policy in the product, and make those five gates observable in review.
Inspect the template schema in TypeScript
Don't guess at a provider payload. This Node example requests the live schema for template creation through the verified discovery route, uses an explicit method and Bearer authentication, and deals with HTTP 429 without a tight retry loop. The base URL and key stay in environment variables, so the unlinked comparison doesn't publish a vendor URL or embed a secret.
const baseUrl = process.env.INFRAI_BASE_URL;
const apiKey = process.env.INFRAI_API_KEY;
if (!baseUrl || !apiKey) {
throw new Error("Set INFRAI_BASE_URL and INFRAI_API_KEY");
}
function retryDelay(response: Response, attempt: number): number {
const retryAfter = response.headers.get("retry-after");
if (retryAfter) {
const seconds = Number(retryAfter);
if (Number.isFinite(seconds)) return seconds * 1_000;
}
return Math.min(1_000 * 2 ** attempt, 8_000);
}
async function loadTemplateSchema(): Promise<unknown> {
const endpoint = `${baseUrl}/v1/discovery/email.template.create`;
for (let attempt = 0; attempt < 4; attempt += 1) {
const response = await fetch(endpoint, {
method: "GET",
headers: { Authorization: `Bearer ${apiKey}` },
});
if (response.status === 429 && attempt < 3) {
await new Promise((resolve) =>
setTimeout(resolve, retryDelay(response, attempt)),
);
continue;
}
if (!response.ok) {
throw new Error(
`Discovery request failed (${response.status}): ${await response.text()}`,
);
}
return response.json();
}
throw new Error("Discovery retry limit reached after HTTP 429 responses");
}
console.log(JSON.stringify(await loadTemplateSchema(), null, 2));
Validate the template payload against the returned request schema, then run the provider preview in CI beside product-owned fixtures. Keep cases such as order-171, a 68-character property label, an omitted seller note, a suppressed address, an unverified domain, and a preview awaiting approval in the repository. Those numbers aren't delivery benchmarks; they are stable regression inputs. The longer case is valuable: it forces a contributor to see wrapping in the seller's order card, inspect the plain-text alternative, confirm that an absent note doesn't leave stray punctuation, and prove that a suppressed address stops before the provider adapter is called. The provider preview remains part of release, but product policy stays testable without network access.
Postmark, Resend, and SendGrid win at different boundaries
Choose Postmark or SendGrid when SMTP relay is a hard requirement. Choose a mail-focused option such as Resend when consolidating unrelated backend capabilities under one key has no operational value and its current workflow better matches your team's tooling. These aren't edge cases. They are valid reasons to pass on the API-first option.
The API-first choice is also not suitable when the workflow needs real-time webhook orchestration, managed email OTP, or a cancellable scheduled email. Email OTP fallback must be built by the application, event ingestion is pull-based, and a scheduled email cannot be canceled through the API. For domestic Chinese email compliance, don't rely on the pending Tencent email vendor as evidence of readiness. If any one of those constraints defines the product, select the provider whose documented capability meets it now.
For the property marketplace case, I would use the five-gate API workflow only if polling fits the delivery target. It keeps the integration surface small and gives template rendering, authentication, and suppression explicit places in the release process. If sellers need sub-minute delivery-state reactions driven by push events, the runner-up with verified webhook support should win after a current documentation check.
Operate polling as an order-state machine
Delivery reliability continues after the request is accepted. The reviewed API exposes suppression and event-list capabilities, but its email and SMS namespaces don't push webhook events. The application must poll and reconcile. For a new-order notice, store the internal order ID and provider message ID together, then run a bounded poller that advances delivery state without resending the notification.
Keep it idempotent.
The distinction matters because "request accepted" and "seller informed" are different product states. A worker can lose its lease after sending but before persisting the result; without a stable notification key, an eager retry may produce two messages for one order. The platform specifies an Idempotency-Key convention with a 24-hour default deduplication window for idempotent capabilities, but the product database still needs its own durable uniqueness rule. The API convention protects a request window. Your order ledger protects the business invariant. Scheduled email adds another constraint: it exists, but has no cancel operation, so the application must own the delay whenever cancellation is part of the product promise. SMS does expose cancellation, yet it still needs application-level geographic abuse controls and per-country pricing circuit breakers.
Top comments (0)