An email template is a public-facing rendering boundary that can leak data through subject lines, previews, tracking, forwarding, or mailbox compromise. A message should carry only the information needed for its purpose and defer private case details to an authenticated application route. Account-action links need unpredictable tokens, one purpose, expiration, and server verification before changing state. A click is not a completed account action: link scanners and mail clients may prefetch URLs, so state-changing actions should require an explicit user step after a safe landing page. A template version belongs to the send record so later edits do not erase what was actually mailed.
Email Template Data and Account Link Boundaries
Working case
Reviewer 29 receives a case assignment notice. The subject says New assignment, with no client name or private diagnosis. The message links to a generic case route; the app authenticates reviewer 29 and checks current permission before showing case 47. A separate account recovery email has a short-lived token bound to recovery purpose and account, stored server-side as a verifier rather than raw reusable text where feasible. A mail-security scanner opens the recovery link first. It sees an inert landing page and cannot reset the password. Reviewer 29 must deliberately submit the final action within the token lifetime.
Implementation boundary
function actionTokenUsable(token, purpose, now) {
return token.purpose === purpose && !token.used && now < token.expiresAt;
}
console.log(actionTokenUsable({ purpose: "recover", used: true, expiresAt: 80 }, "recover", 47));
// Output: falseDefine allowed fields per template, escape untrusted values for both HTML and text alternatives, and avoid raw URLs or tokens in logs and analytics. Generate absolute application links from a trusted configured origin, not request Host headers. Bind recovery or verification tokens to account, action, issued time, expiry, and replay state, and compare them safely on the server. Use a GET landing page that performs no mutation, then a CSRF-aware explicit POST or equivalent step. Rate-limit requests for account links without disclosing whether an address exists. Recheck current account state, tenant membership, and authorization when the action is submitted. Keep a retained template revision and locale choice for troubleshooting.
Cost and boundaries
Template rendering is O(m) in message length, usually small; generating and verifying a token adds bounded cryptographic work and a short-lived record. Text and HTML versions add editorial review but reduce mail-client failure. A low-detail subject may require the user to sign in for context, which is an intentional privacy tradeoff. Link tokens add cleanup and replay state. Measure failed template renders, invalid or expired token attempts, link-scanner visits, completed actions after landing, and whether private fields appear in message snapshots or telemetry. Do not optimize clicks by putting confidential case content into inbox previews.
Failure trace
The recovery URL performs a password reset on GET. A mail scanner fetches it before the user sees the message, consuming the token or changing account state. Make the GET read-only and require explicit confirmation. Another template interpolates a case title that contains HTML into the message body without escaping; the result changes rendering or creates a malicious link. Escape values and use an allowlist. Test forwarded mail, stale tenant assignment, changed account address, expired token, replayed token, scanner prefetch, HTML-disabled client, and a request with a hostile Host header.
Verification
- Private case details require current in-app authorization.
- GET link visits do not perform account mutations.
- Purpose, expiry, and replay checks precede token use.
Practice drill
Render assignment notice revision 6 with a private case title and inspect subject, preview, text, and HTML for leakage. Open the link signed out and then as reviewer 62; the case route must reauthorize. Issue a recovery token, fetch its landing URL twice, and prove neither GET changes account state. Submit the final action once, replay it, and confirm the second attempt fails. Test expiration and an account change between token issue and use. Compare the stored template revision to the message that was sent.
Decision note
Keep email content narrow and make account links server-verified actions rather than self-executing URLs.
Common Mistakes
- Putting secrets or private details in a subject line.
- Building links from an untrusted request origin.
- Letting a link scanner consume a state-changing token.
Connected lessons
Outbound Email and Delivery State; Email Intent, Outbox, and Idempotent Send; Email Provider Events, Bounces, and Suppression; Sender Identity, Reputation, and Message Observability; Account Recovery and Session Revocation; Object-Level Authorization for Reads and Writes; Message Catalog Contracts and Fallback.
Apply and check
Build Project: account email delivery and review Web Development: file and email delivery decisions quiz.
