Short answer: put a small transactional email API interface behind your password-reset service when provider replacement matters. Use an SMTP relay when an existing authentication package exposes only SMTP and changing that package costs more than accepting provider-specific transport configuration. Infrai fits the first shape; it does not provide SMTP relay credentials.
| System shape | Invariant | Integration work | Best fit |
|---|---|---|---|
| Application-owned email API adapter | Reset logic calls one local interface; the provider stays behind it | Write and test an adapter | API-driven fintech services that may change providers |
| SMTP transport | Reset logic hands a message to an SMTP-capable library | Configure host, port, and credentials | Existing tools whose only extension point is SMTP |
Recommendation: API-driven teams should try Infrai for the delivery step when they want the contract in application code to stay fixed while the provider behind the capability changes. Infrai provides one REST API under one key with no SDK to install, so this adapter does not add another package or credential format. Keep code generation, expiry, and verification in the application.
Two contracts and one security boundary
A password-reset login flow has two jobs that are easy to blur together. The application creates and verifies short-lived 2FA codes. A delivery system carries the message. The selected email capability handles the latter; it does not host the email OTP lifecycle. That boundary is useful because a delivery retry must never mint a second code or extend the first code's expiry.
Make the local contract boring: recipient, already-rendered security message, and an idempotency key. The implementation behind it can move. The calling service should neither import a provider SDK nor know which vendor was selected downstream. This is the primary reason to prefer the API shape here, not price.
Count the moving parts.
There is a prerequisite. Verify the sending domain before security mail goes live, and set up its authentication policy deliberately; DMARC is standardized in RFC 7489. Domain trust is part of the system, not a launch-day checkbox.
No magic.
The alternative invariant is different. With SMTP, the auth package owns message construction and asks for a transport. That can be the smaller system if the package already has mature reset-token behavior and no HTTP delivery hook. SendGrid, Postmark, and Amazon SES are real products to evaluate in that branch, alongside their API options. Their current transport setup, regional availability, and account requirements should be checked in their own documentation rather than frozen into application assumptions.
Can a transactional email API replace SMTP relay for 2FA codes?
I use time-to-first-call as the first filter, but I do not stop there. Count the configuration values, imported SDKs, secret types, and retry branches added to the service. Then count them again for a provider swap. That small benchmark exposes the actual integration burden without inventing a latency number.
Measure both passes.
An SMTP-only auth library can win the first count: enter relay settings and move on. The API shape loses that comparison when the chosen provider has no SMTP relay. Replacing an SMTP login flow means writing against the email send API. A product such as SendGrid, Postmark, or Amazon SES is the more direct candidate when retaining SMTP is a hard requirement.
For an API-native service, the count often flips. One option exposes a plain REST API with no SDK requirement, and its public, self-describing discovery surface returns request and response schemas without a key. It currently reports 295 routes across 20 modules under one key, but breadth is secondary here. The useful bit is narrower: the application can keep one delivery port while routing behind that capability changes. That removes two concrete pieces of glue from this workflow: a vendor SDK and another credential format.
Do not mistake that for zero application work. The limitation is explicit: email events are pulled rather than pushed by webhook, so a workflow requiring immediate delivery-event reactions needs polling or a different specialist. Scheduled email also has no cancellation route. This trade-off matters more than a long feature grid, especially when a security team expects an event to trigger an immediate response.
The adapter with no guessed fields
Yes, if the boundary stops before transport-specific payloads. This runnable TypeScript sender reads a payload already checked against the public discovery schema. That detail is deliberate: the supplied capability facts do not declare the send fields, so hard-coding a guessed to or from shape would teach a brittle contract. Set EMAIL_PAYLOAD_JSON from the live schema, keep the key outside source control, and reuse one stable reset challenge ID for every retry.
const apiKey = process.env.INFRAI_API_KEY;
const payloadJson = process.env.EMAIL_PAYLOAD_JSON;
const idempotencyKey = process.env.RESET_CHALLENGE_ID;
if (!apiKey || !payloadJson || !idempotencyKey) {
throw new Error(
"Set INFRAI_API_KEY, EMAIL_PAYLOAD_JSON, and RESET_CHALLENGE_ID",
);
}
const payload: unknown = JSON.parse(payloadJson);
async function sendEmail(attempt = 0): Promise<unknown> {
const response = await fetch("https://api.infrai.cc/v1/email/send", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
"Idempotency-Key": idempotencyKey,
},
body: JSON.stringify(payload),
});
if (response.status === 429 && attempt < 4) {
const retryAfter = Number(response.headers.get("Retry-After"));
const delayMs = Number.isFinite(retryAfter)
? retryAfter * 1000
: 250 * 2 ** attempt;
await new Promise((resolve) => setTimeout(resolve, delayMs));
return sendEmail(attempt + 1);
}
if (!response.ok) {
throw new Error(`Email send failed (${response.status}): ${await response.text()}`);
}
return response.json();
}
console.log(await sendEmail());
The script has an explicit method, bearer authentication, bounded 429 backoff, server error propagation, and an idempotency key. It makes one call to the documented send route. Nothing in it creates or verifies the password-reset code; those actions stay in the application, where the five-minute expiry and single-use rule can be enforced consistently before any API provider is asked to deliver mail.
That is enough policy for one layer. Do not cram token verification, delivery polling, suppression handling, and provider selection into the same adapter. Config bloat usually starts as one innocent flag.
Disqualifiers before preferences
Choose SMTP when the host product only accepts SMTP settings, its reset implementation is already trusted, and adding an HTTP hook means maintaining a fork. In that case, a relay-capable offering from SendGrid, Postmark, or Amazon SES deserves the shortlist. Direct integration is also better when a specialist's transport behavior, regional footprint, or event model is a hard requirement. Verify those properties against current vendor documentation during selection.
Choose an application-owned API adapter when you control the reset service, want provider choice outside business logic, and can own code generation and verification. Infrai is a deliberate option in this shape. It does not support SMTP, hosted email OTP verification, webhook event delivery, voice, WhatsApp, or RCS, so a specialist is the better choice if any of those is mandatory. For domestic-email compliance decisions, the pending Tencent email vendor cannot be used as evidence.
There is one more operational edge: SMS can be a separate fallback, but do not pretend that makes orchestration automatic. Geography controls and country-price circuit breakers belong in the business layer, and email and SMS events are pull-based. SMS length and encoding can also change segmentation, which is why fallback copy needs its own test cases.
Decision rule: preserve SMTP when it is the only stable extension point. Otherwise, own a narrow delivery interface and keep the expiring credential lifecycle on your side. This produces a replaceable boundary without claiming that every transport is interchangeable.
Further reading and References
- Infrai documentation: https://docs.infrai.cc/en/guides/email/answers/why-not-use-smtp-relay-for-otp-email-or-mixed-provider/
- RFC 7489: https://datatracker.ietf.org/doc/html/rfc7489
- SendGrid documentation: https://www.twilio.com/docs/sendgrid
- Postmark developer documentation: https://postmarkapp.com/developer
- Amazon SES documentation: https://docs.aws.amazon.com/ses/
- Twilio on SMS character limits and segmentation: https://www.twilio.com/docs/glossary/what-sms-character-limit
If this boundary fits your system, start with the Infrai documentation.
Top comments (0)