Password-reset mail is high-trust transactional email. It arrives when the From address is a registered, sending-active identity on your production domain, authenticated with aligned SPF, DKIM, and DMARC, and sent through a real API—not php mail() on a hosting IP. Keep the template short, keep marketing off that From, log the send so support can look it up, and do not retry hard bounces.
Why “email sent” is not the same as “reset received”
The user is locked out. Support searches a shared Gmail label and finds nothing. The app logged “queued” after a local mail() call or an unauthenticated SMTP hop. That is not delivery. Transactional email is accepted by a provider that will later emit events. If support cannot look up the message id, you do not have a reset path—you have a hope path. See Support should see the transactional email log.
Fix the sending identity first
Use one stable From on the production domain, for example [email protected] or [email protected]. Do not share that From with newsletters. Mixing marketing and resets is a common reason reset mail lands in spam; keep streams separate as described in separate marketing and transactional subdomains.
Prefer an address people can reply to. “I didn’t request this” and “the link is dead” are support tickets, not noise. The case against noreply@ is already made in Stop sending from noreply@. Set Reply-To if the visible From must stay a system identity; know what From, Reply-To, and Return-Path each do.
ArawaMail sending constraints
On ArawaMail, Enable Sending requires receiving to be active first. When you activate sending, Cloudflare receives DKIM CNAMEs plus a custom MAIL FROM with MX and SPF. HTTP API from must be registered, allowed by the API key, and sending-active. Those checks are the same for mailbox users and API sends. Details: Enable Sending.
Send Email is the Resend-compatible POST /emails endpoint. Documented fields include from, to, subject, html or text, cc, bcc, reply_to, headers, and attachments. Reserved headers are ignored. There is no inbox-placement field you can set. Plan caps apply (Free is 3,000 sends per month with no overage); do not treat resets as unlimited.
Authenticate even below bulk thresholds
Gmail, Yahoo, and Microsoft still expect SPF, DKIM, and DMARC on authenticated mail. Resets are not exempt because volume is low. Alignment is the rule—not a raw SPF pass on a mismatched domain. Use SPF, DKIM, and DMARC explained and DMARC alignment. Bulk-sender volume rules are covered separately in Gmail and Yahoo bulk-sender requirements; do not wait for 5,000/day before you align reset mail.
Hosting-IP php mail() and a shared workspace mailbox used as a sending API are the two failure modes that produce “forgot password email not arriving” tickets with no provider event to inspect.
Write a reset template machines and humans can parse
Users often see a summary first. Make the subject and first line explicit:
- Subject: Reset your password for
- First line: Use this link to choose a new password. It expires in {N} minutes.
Keep HTML lean. You do not need a tracking pixel on a reset. Use HTTPS. Put the raw URL in the text part. Avoid marketing modules, unsubscribe experiments, and large image headers on this template. Dark-mode survival is useful; conversion design is not the job of a reset.
Observe the send before you blame the user’s spam folder
After a documented API send, outgoing webhooks carry delivery events. Retrieve Email exposes last_event. That is provider state, not proof of inbox placement. Wire those events so support can answer “was it accepted, delayed, or bounced?” without paging engineering. Implementation patterns: transactional email webhooks.
Support checklist before “check spam”:
- Does a message id exist for that user and timestamp?
- What is last_event?
- Was the From sending-active and aligned?
- Is the recipient a hard bounce or suppression?
- Did the user request multiple resets in one minute (duplicate sends, not a placement bug)?
Retry policy that does not amplify hard bounces
Do not resend the same token to a hard-bounced address on every “resend code” click. Issue a new token when the old one expires; do not create five live links. Token lifetime should be short enough to limit replay and long enough that a delayed message is still usable—minutes, not days.
Mashed “resend” clicks are a duplicate-send problem. Treat them with idempotency keys when that guide is live; they are not evidence that Gmail “lost” the first copy.
OTP and verification-code latency is a different article (one-time codes, not reset links). Keep reset copy and OTP copy on separate templates so a slow code path does not get “fixed” by rewriting the reset From.
How we analyzed this
This guidance maps user-visible failures (reset never arrived, landed in spam, app said sent) to documented ArawaMail sending prerequisites, the Send Email / Retrieve Email API surface, outgoing webhooks, and public bulk-sender authentication expectations. We did not invent bounce payload fields, inbox-placement guarantees, or reset-specific unlimited sending.
FAQ
Why did the app say the reset email was sent when it was not received?
The application usually logs a local accept. Delivery starts only after an authenticated provider accepts the message. Check the API message id and last_event before blaming the user’s spam folder.
Should password resets come from no-reply@?
No. Use a monitored security or accounts address, or set Reply-To to one. Users need a path when the link fails.
How long should the reset link live?
Minutes to a few hours is typical. Expire it. On resend, invalidate or supersede the previous token so only one link works.
Are password reset emails exempt from DMARC?
No. Align SPF and DKIM with the From domain even at low volume.