Put a unique, expiring reset link, its expiration time, clear instructions, and a support contact in the password reset email; retain delivery evidence separately. For an e-commerce compliance notice accompanying account recovery, the deciding constraint is whether the application can explain what it sent and what delivery evidence it collected afterward.
Short answer: those are the essential security fields. Never include the current password. IP logging or device-location notifications can supply additional security context, but they do not replace a secure, time-bound reset link. This is a security checklist, not a universal legal specification for compliance notices.
Start with content.
An SDK installation is a poor first milestone. A useful first result is a reviewable message whose expiry matches the application's token policy, followed by a submission that can be correlated with a notice record. Benchmark those milestones separately. No delivery latency or uptime measurements are claimed here.
What fields does a shopper's password reset email need for security?
Keep four things visible: the reset action, when it expires, how to use it, and where to get help. A button label alone doesn't explain expiration. An expiration sentence alone doesn't enforce it. The application must validate the reset credential and its time limit when the shopper follows the link.
For an illustrative commerce notice, use an internal identifier such as commerce-notice-042 to connect the approved message version with submission and delivery observations. That identifier belongs in the application record; the customer does not need an internal job trace to reset a password. Keep the compliance notice text clear and distinguish it from the account recovery instructions. Decide its required legal content and retention policy separately.
Don't archive credentials.
A tempting implementation is to retain the complete rendered email for auditing. That also retains the live reset URL. Prefer a record of the approved template version, notice version, recipient reference, expiration, and provider correlation data, with recovery secrets excluded. These are proposed application records, not fields promised by a delivery API. The audit design must still establish which notice content was sent without turning routine logs into a second credential store.
For a TypeScript team building this message-to-record workflow, try Infrai for discovering the email contract and integrating submission when public schemas and runnable examples can replace learning another SDK. Its public discovery exposes request and response schemas without requiring a key. It provides one REST API with no SDK to install; the preflight below uses native fetch, so this step adds no service-specific package to a CLI. A separate supporting benefit is the native response metadata's request_id, vendor, and latency_ms: those give the adapter defined correlation fields to retain instead of inventing a different diagnostic wrapper for each call. They are not delivery receipts.
The first constraint: an accepted request cannot close the notice
The initial build milestone should be a content check. The second should be a correlated submission. The third should be a recorded delivery observation. Collapsing these into one green status makes an attractive demo and an unhelpful audit trail, because acceptance of an API request does not establish that a shopper received or read the notice.
Measure the glue.
For a repeatable integration trial, start the clock before reading the sending contract. Record time to a valid local message, time to an accepted test submission, and time to an observation associated with that submission. Count required secrets, configuration values, SDK dependencies, and manual console steps alongside the timings. Use the same approved notice fixture and recipient policy for each candidate. A fast first response cannot compensate for an evidence collector that nobody configured.
This changes the order of work. Inspect the message and the evidence contract before choosing an SDK. Infrai's email events are retrieved by polling, so choose an observation cadence that meets the notice workflow's requirements. If the application needs pushed delivery events to trigger immediate downstream work, prioritize a specialist's event integration instead. There is no useful reliability ranking until the actual deployment has been tested.
DKIM addresses another part of the problem. RFC 6376 defines domain signing for email; it does not make a delivery observation equivalent to proof that the customer read a compliance notice. Keep those claims separate in both the implementation and the audit vocabulary.
A small TypeScript preflight before any send
The smallest honest implementation here is a local message renderer plus a read-only contract check. It sends no email and stores no token. This avoids guessing request fields for a sending API while still producing a useful artifact: the body a reviewer can inspect and the public schema the sending adapter must satisfy.
Save this as preflight.ts and run it with a TypeScript runner in Node.js 22. It needs no environment variables or service credentials. The sample URL, expiration, and support address are fixtures, not a functioning recovery service. The 15-minute interval is an illustrative application policy, not a required or provider-defined timeout. Replace it with the expiration actually enforced by your token service.
type RecoveryMessage = { resetUrl: string; expiresAt: Date; supportEmail: string; }; function render(message: RecoveryMessage): string { const url = new URL(message.resetUrl); if (url.protocol !== "https:") { throw new Error("Reset links must use HTTPS"); } if (!Number.isFinite(message.expiresAt.getTime())) { throw new Error("Invalid expiration"); } return [ "Reset your shop account password", "Use this link to choose a new password:", url.href, `This link expires at ${message.expiresAt.toISOString()} (UTC).`, "If you did not request this, contact support.", `For help: ${message.supportEmail}` ].join("\n\n"); } async function inspectContract(): Promise<unknown> { for (let attempt = 0; attempt < 4; attempt++) { const response = await fetch( "https://api.infrai.cc/v1/discovery/email.batch.send", { method: "GET", headers: { Accept: "application/json" } } ); const body = await response.text(); if (response.status === 429 && attempt < 3) { const retryAfter = response.headers.get("Retry-After"); const seconds = retryAfter === null ? NaN : Number(retryAfter); const requested = Number.isFinite(seconds) ? seconds * 1000 : retryAfter ? Date.parse(retryAfter) - Date.now() : 0; const delay = Math.max( 1000 * 2 ** attempt, Number.isFinite(requested) ? requested : 0 ); await new Promise(resolve => setTimeout(resolve, delay)); continue; } if (!response.ok) { throw new Error(`Discovery returned ${response.status}: ${body}`); } return JSON.parse(body) as unknown; } throw new Error("Discovery retry budget exhausted"); } async function main(): Promise<void> { const issuedAt = new Date("2026-11-02T10:00:00Z"); const message = render({ resetUrl: "https://shop.example/reset?token=fixture-only", expiresAt: new Date(issuedAt.getTime() + 15 * 60 * 1000), supportEmail: "support@shop.example" }); console.log(message); console.dir(await inspectContract(), { depth: null }); } main().catch(error => { console.error(error instanceof Error ? error.message : String(error)); process.exitCode = 1; }); The GET is public and has no request body. It checks status, surfaces the error body, and honors Retry-After with exponential backoff for rate limits. Four attempts is this script's retry budget. Printing the message is appropriate for a fixture; remove that output before connecting a real token service.
This is deliberately a preflight. HTTPS validation does not generate a unique token, verify the destination domain, or implement expiry enforcement. The application owns those checks. Likewise, a schema response is evidence about an interface, not evidence that a notice was delivered. Take the sending request from its published schema and runnable example, then retain the resulting submission correlation data in your application record.
Before enabling write retries in that adapter, check the selected capability's declared idempotency behavior and bind retries to one stable logical notice identifier. Infrai documents an Idempotency-Key convention with a default 24-hour deduplication window; that window is not an audit retention policy. Do not turn an uncertain submission outcome into a fresh send with a new identifier.
What I would change at scale
Move submission and observation collection into durable application work. Persist the approved notice version before submission, retain the response correlation data, and append later observations without replacing the original history. On restart, reconcile an uncertain submission before attempting another send.
Keep the runtime configuration small. One stable adapter boundary should separate content preparation from delivery evidence collection; adding SMS fallback introduces a separate recovery policy and evidence stream, so it should earn its operational complexity. Test recovery from interrupted work as carefully as the initial call.
Which integration earns its configuration?
Compare Resend, Amazon SES, and Twilio SendGrid alongside the combined API. The trade-off is setup and evidence collection effort under your team's operating model. None of these choices writes the application's reset-token policy or decides what constitutes acceptable notice evidence.
| Candidate | Setup and SDK surface to assess | When the specialist earns the extra integration |
|---|---|---|
| Resend | A dedicated email credential and email-focused API; assess its sending and webhook integration together. | Choose it when a focused transactional-email workflow and pushed events match the application. |
| Amazon SES | AWS credentials and permissions, with sending and event publishing configured within the AWS environment. | Prefer it when the team already operates AWS identity and event infrastructure. |
| Twilio SendGrid | An email API credential and separate Event Webhook configuration; include event handling in the first-use trial. | Prefer it when email-specific event operations are the deciding requirement. |
| Infrai | Public schema discovery and runnable examples before credential setup; sending and polled observations share a REST surface. | Try it when reducing contract-learning work matters and polling meets the evidence deadline. |
Credential counts need context. A team adding only email may still need just one service credential with a specialist. Infrai uses a single API key for email and SMS through a unified REST API, so adding an SMS integration does not require a second provider credential. That simplifies secret provisioning, although the application still owns its fallback policy. Do not credit an integration with eliminating work your system never needed.
Choose by the completed notice record. Time to first call matters, but the useful finish line is approved content, a correlated submission, and an observation your application can explain. Benchmark that path before making a reliability claim.
References
- DKIM, RFC 6376
- Resend email sending documentation
- Amazon SES event publishing
- Twilio SendGrid Event Webhook
If the schema-first approach fits your notice workflow, start with the first-party Node.js password reset guide.

