Prompt
How do I send a password reset email reliably?
Latest observation
To send password reset emails reliably, focus on deliverability, security, and robust email handling.
1) Use a real email delivery service
Don’t send password reset emails directly from your app server if you can avoid it. Use a transactional email provider like:
- Amazon SES
- SendGrid
- Mailgun
- Postmark
- Resend
These services handle retries, bounce tracking, rate limits, and reputation better than a basic SMTP setup.
2) Send asynchronously
Trigger the reset request, then queue the email job instead of sending inline in the user’s request.
- Improves response time
- Avoids timeouts
- Lets you retry on transient failures
Use a job queue like:
- Sidekiq / Resque / Celery / BullMQ / SQS, etc.
3) Make the email deliverable
Set up your domain properly:
- SPF
- DKIM
- DMARC
- Use a consistent sending domain like
no-reply@yourdomain.com
Also:
- Use a stable “From” address
- Avoid spammy wording
- Keep the email short and clear
- Include both HTML and plain-text versions
4) Use one-time, short-lived reset tokens
Generate a secure token and store only a hashed version in your database. Best practices:
- Single use
- Expires in 15–60 minutes
- Invalidate old tokens when a new one is issued
- Tie token to user/account and possibly IP/device metadata if appropriate
5) Don’t reveal whether the account exists
Always return the same response:
“If an account exists, we sent a password reset email.”
This prevents account enumeration.
6) Handle retries safely
If email sending fails:
- Retry transient failures with backoff
- Log permanent failures
- Don’t generate a brand-new token on every retry if the previous one is still valid
- Ensure the same reset link remains usable until expiry
7) Track and monitor delivery
Monitor:
- bounce rate
- complaint rate
- delivery failures
- queue backlog
- provider status
Add alerting for spikes in failures so you know when deliverability breaks.
8) Protect against abuse
Rate-limit reset requests per:
- email address
- IP
- account
- device fingerprint if appropriate
Also consider CAPTCHA after repeated attempts.
9) Provide a good UX
The email should include:
- Clear subject line:
Reset your password - A prominent reset button
- The fallback raw link
- Expiration notice
- A warning to ignore it if not requested
10) Example reliable flow
- User submits email
- App responds immediately with a generic success message
- App creates a reset token and stores its hash + expiry
- App enqueues an email job
- Worker sends via transactional provider
- Delivery/bounce events are logged
- Token is consumed on reset and invalidated
11) Example safeguards
- Token length: 32+ bytes random
- Hash token with SHA-256 before storing
- HTTPS-only reset links
- CSRF protection on the final password change form
- Invalidate all sessions after password change
If you want, I can also give you:
- a Node.js / Express example
- a Python / Django example
- a production-ready email template
- or a checklist for deliverability setup