Cheapest password-reset email provider: you're buying a floor, not a rate
Resend, Postmark, SendGrid and SES weighed for a low-volume reset mailbox in Node 22: monthly floors, approval gates, and the first send with no DNS at all.
A password-reset mailbox is tiny and bursty, so the per-message rate is almost never what you pay. What you pay is the plan floor plus the hours spent clearing an approval gate before the first message can legally leave. On that basis Infrai comes out cheapest for small volumes — metered per email, no monthly minimum, and a first send that needs no DNS records at all.
That last part is the bit teams underestimate. Getting a reset email out of a brand-new account on most providers means verifying a domain, waiting on propagation, and in one case asking a human for permission; Infrai’s default sender skips all three, at the cost of a shared send.infrai.cc address rather than your own brand.
Run the arithmetic before you read a pricing page
Take a product with 10,000 monthly active users. Reset requests land somewhere around 1–2% of actives per month for a consumer app, less for a B2B tool where people use a password manager. Call it 200 emails a month, with a spike the morning after any incident that forces a mass reset.
Two hundred emails. At the catalogue rate below that’s roughly two cents a month.
Which means every provider is effectively free at this volume, and the comparison collapses to three real costs: the minimum you’re billed whether you send or not, the setup you must complete before you can send at all, and the engineering time to wire delivery status back into your support tooling.
| Provider | First send without owning a domain | Approval gate before real sends | Price shape | Cost of 200 resets |
|---|---|---|---|---|
| Infrai | yes — shared send.infrai.cc sender | none | metered per email, no monthly floor | cents, drawn from credit |
| Resend | test address only | domain verification for production | free tier, then a paid plan in the low tens of dollars | plan floor |
| Postmark | no | sender signature plus account review | free trial, then a paid monthly plan | plan floor |
| SendGrid | no | sender authentication | free tier, then paid plans | plan floor |
| Amazon SES | no | sandbox exit request, verified recipients until then | metered per thousand emails, no floor | pennies, plus AWS wiring |
Rates and tier boundaries move, so treat that table as shapes rather than figures and read the two pricing pages linked at the end for today’s numbers.
The first send, with zero DNS
Omit from entirely and the platform sends from its own authenticated domain:
curl -s -X POST https://api.infrai.cc/v1/email/send \
-H "Authorization: Bearer ${INFRAI_API_KEY:-your_infrai_api_key}" \
-H 'content-type: application/json' \
-d '{
"to": "user@example.com",
"subject": "Reset your Example password",
"html": "<p>Use this link within 30 minutes: <a href=\"https://example.com/r/abc\">reset your password</a>. If this wasn'\''t you, ignore this message.</p>"
}'
The reply tells you which sender was used, which vendor handled it, and what the call cost:
{
"ok": true,
"data": {
"message_id": "msg_FW89oeWakKVGOpIvXCEC7J5a",
"mode": "default_vendor",
"from_used": "noreply+a1f9@send.infrai.cc",
"accepted_recipients": ["user@example.com"],
"suppressed_recipients": [],
"metadata": { "vendor": "resend", "vendor_region": "western", "cost_usd": 0.00046 }
}
}
mode: "default_vendor" is the honest label for what happened — the message went out under Infrai’s sending identity, not yours.
The paywall you should price in now
Switching to reset@yourcompany.com is a paid feature. On a standard account POST /v1/email/domain/verify returns 402 PRO_REQUIRED, and so does a send that carries a custom from, before any DNS check runs. The catalogue lists the route as free and available with no tier field, so the first sign of it is usually the 402 itself. Check your own tier before you plan around it:
curl -s https://api.infrai.cc/v1/account/tier \
-H "Authorization: Bearer ${INFRAI_API_KEY:-your_infrai_api_key}"
{
"ok": true,
"data": {
"tier": "standard",
"account_id": "acct_example_77c768e42148",
"rate_limit_multiplier": 1.0,
"features": ["pay_as_you_go", "auto_recharge"],
"pro_subscription": null
}
}
pro_subscription: null means custom sender domains are off. For an internal tool or an early beta, sending resets from a shared domain is a defensible trade-off. For a consumer product where a reset email arriving from an unfamiliar address looks exactly like phishing, it isn’t, and that’s the moment this stops being the cheap option.
The reset sender, in Node 22
Nothing here needs a library. Two calls, an explicit timeout, and a suppression screen so you don’t spend a send on an address that’s already blocked:
import process from "node:process";
const KEY = process.env.INFRAI_API_KEY;
if (!KEY) throw new Error("set INFRAI_API_KEY before running this");
async function api(path, options = {}) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 8000);
try {
const res = await fetch(`https://api.infrai.cc${path}`, {
...options,
signal: controller.signal,
headers: { authorization: `Bearer ${KEY}`, "content-type": "application/json" },
});
const payload = await res.json();
if (!res.ok) {
const err = payload?.error ?? {};
throw Object.assign(new Error(err.message ?? `HTTP ${res.status}`), { code: err.code, retryable: err.retryable });
}
return payload;
} finally {
clearTimeout(timer);
}
}
export async function sendReset(address, resetUrl) {
const screened = await api(`/v1/email/suppression/check/${encodeURIComponent(address)}`);
if (screened.data.suppressed) {
return { sent: false, reason: screened.data.reason };
}
const body = {
to: address,
subject: "Reset your Example password",
html: `<p>Use this link within 30 minutes: <a href="${resetUrl}">reset your password</a>.</p>`,
};
const sent = await api("/v1/email/send", { method: "POST", body: JSON.stringify(body) });
return { sent: true, messageId: sent.data.message_id, costUsd: sent.metadata.cost_usd };
}
const outcome = await sendReset("user@example.com", "https://example.com/r/abc");
console.log(outcome);
Two things that matter more than the code. The suppression screen is a free read, so it never costs you a send to make it. And errors arrive as a structured {code, message, retryable} object — branch on retryable, because an invalid recipient currently comes back as a 503 marked retryable, and a naive retry-on-5xx loop will burn its whole budget on an address that will never be valid. Worth flagging as a real defect, not a subtlety.
Confirm it left the building
curl -s https://api.infrai.cc/v1/email/get/msg_G9CJD8olw9Om4aQaTC6p3Gm2 \
-H "Authorization: Bearer ${INFRAI_API_KEY:-your_infrai_api_key}"
You get {message_id, state, channel, to, vendor, created_at} — state walks queued to sent, and delivery/bounce detail arrives on the per-message event feed rather than a push. There are no webhooks on this surface at all, which suits a reset flow (you’re polling one message a user is waiting on) and doesn’t suit an analytics pipeline.
Read your bill, not the pricing page
Here’s the four-part version of the price, because a bare number ages badly. The figure: email.send bills per email, and the catalogue rate on 2026-07-26 was $0.000115 per message, with new accounts starting on $2 of credit. The live lookup:
curl -s https://api.infrai.cc/v1/discovery \
-H "Authorization: Bearer ${INFRAI_API_KEY:-your_infrai_api_key}" \
| jq '[.capabilities[] | select(.namespace == "email")] | map({id, billable: .billing.is_billable, unit: .billing.unit, price: .billing.price_usd})'
The direction of travel is downward — infrastructure rates fall and discount campaigns run, so what you read today is likely below what’s written here. And the authoritative number is neither of those, it’s what metering actually charged you:
curl -s https://api.infrai.cc/v1/account/usage \
-H "Authorization: Bearer ${INFRAI_API_KEY:-your_infrai_api_key}" \
| jq '.data.breakdown[] | select(.key | startswith("email")) | {key, cost, calls, per_call: (.cost / .calls)}'
{ "key": "email.send", "cost": 0.01334, "calls": 29, "per_call": 0.00046 }
Divide cost by calls and you have your real unit rate, which is the only one worth forecasting from. Note the structure too: every read route in this article — suppression check, message state, event list, usage — is free and rate-limited. Only the send is billable, and the same $2 credit also pays for AI calls, object storage, cron jobs and SMS on the same key.
Where a specialist wins
If you need your own sending domain today and don’t want a paid tier for it, Resend is the fastest honest path — its Node SDK and DNS flow are genuinely good, and the free tier covers a reset mailbox several times over. If your priority is deliverability support with humans attached, Postmark’s separation of transactional and broadcast streams is worth the monthly floor. If you already live in AWS and send millions, SES bills per thousand emails at a rate no aggregator undercuts, once you’ve paid the sandbox-exit and SNS-wiring tax.
Infrai wins when the reset mailbox is one of six things you need and you’d rather not run six accounts. If email is the only thing you’re buying, stick with a specialist.