SaaS email template

Password reset email template — secure, clear, no marketing noise

The password reset email is a trust-critical moment. Clear CTA, visible expiry, consistent branding. Fire it from user.password_reset_requested and manage the template outside your codebase.

Common mistakes with password reset emails

No expiry time shown in the email

If the reset link expires in 1 hour, say so in the email. Users who open the email later are less confused and less likely to contact support.

Generic sender name erodes trust

A password reset email from "noreply@company.com" with no visible app name looks like phishing. Use a consistent sender identity with your app name.

Hardcoded reset URL in the template

The reset token must be unique per request. Include the full reset URL in the event payload — not hardcoded in the template.

Template differs from the rest of the product emails

A password reset email that looks different from other product emails breaks trust and looks suspicious.

Fire the reset event — else.events handles the secure email

Reset URL from the payload — not hardcoded

Generate the reset token in your backend. Include the full reset URL in the event payload. The template renders it as a CTA button.

Expiry shown in the email

Include the expiry timestamp in the payload. The template renders "This link expires in 1 hour" or "Expires at 15:30 UTC" — clear and useful.

Consistent branding with your other product emails

Password reset emails use the same MJML template base and brand variables as your other emails. No phishing-like inconsistency.

Managed outside your codebase

The template lives in else.events. Update copy — "Did not request this? Contact us" — without a deployment.

// user.password_reset_requested event payload

Example event payload for the password reset email

{
  "type": "user.password_reset_requested",
  "user": { "email": "user@example.com", "name": "Alex" },
  "data": {
    "reset_url": "https://app.example.com/reset?token=abc123",
    "expires_at": "2026-05-25T16:00:00Z",
    "app_name": "ExampleApp"
  }
}

The reset URL with the unique token is generated in your backend and included in the payload. else.events renders it directly into the template — no token logic in the email system.

Template variables for the password reset email

  • {{ user.name }} Recipient name for the greeting
  • {{ user.email }} The email address for the account being reset
  • {{ data.reset_url }} Personalised, time-limited password reset link
  • {{ data.expires_at }} Reset link expiry time — shown in the email body
  • {{ data.app_name }} App name for the email subject and sender context

Frequently asked questions

What subject lines work for password reset emails?
"Reset your [App] password", "Password reset request for your [App] account", "Your [App] password reset link". Keep it factual — no marketing tone.
Should I show the reset link as a button or plain text?
Button for the primary CTA, plain text fallback below it. Some email clients block images or render buttons differently. A plain-text URL ensures the user can always access the link.
What if the user did not request a password reset?
Include a "Did not request this?" line with a contact or security page link. This is standard practice and reduces support requests from confused users.
How long should a reset link be valid?
Industry standard is 1–24 hours. Show the expiry clearly in the email. Your backend controls the token lifetime — else.events just renders the expiry time from the event payload.

Password reset emails that users trust — and that work

Secure token from your backend, clear expiry in the email, consistent branding. Managed outside your codebase.

  • Reset URL from event payload — not hardcoded
  • Expiry shown in the email
  • Consistent branding with your product emails