A password-reset email should contain a short-lived link, never the account’s password. If the mailbox is exposed later, that choice limits what the message can reveal. Email security starts in the application: code determines what goes into a message, who receives it, where its links lead, and what sensitive details end up in delivery logs.
Protect access to mail and sending services
Start with the accounts developers use to read and send mail. Enable phishing-resistant multifactor authentication where available, review recovery methods, and remove access promptly when someone leaves the team. A compromised developer mailbox can expose customer conversations, reset links, and internal service details. Treat shared support inboxes as privileged systems: give named users access instead of distributing one password.
Applications need the same care. Keep SMTP credentials and API keys in a managed secret store, not in source files, container images, or copied configuration examples. Give each application and environment a separate credential with only the sending permissions it needs. That way, you can rotate one credential without disrupting unrelated services. If a key is exposed, revoke it and inspect sending activity. Deleting it from the latest commit is not enough; earlier commits and build logs may still hold the value.

Make your domain harder to impersonate
Three DNS-based mechanisms help receiving systems assess mail that claims to come from your domain. SPF lists the servers permitted to send for a domain. DKIM adds a cryptographic signature that receivers can check against a public key in DNS. DMARC provides reports on authentication results and tells receivers how to handle messages that fail aligned SPF or DKIM checks.
Don’t just copy three DNS records from a provider dashboard. First, inventory every legitimate sender, including transactional mail services and support platforms. Configure DKIM for the domain each service uses, then check that its authenticated domain aligns with the visible From domain. SPF can fail after forwarding; DKIM may survive if the message is unchanged. DMARC can pass when either aligned mechanism passes.
Begin with a DMARC monitoring policy and examine reports for legitimate senders you missed. Once those sources authenticate correctly, move toward a stricter policy. A DMARC pass—or a familiar From address—still does not mean the message is safe. Attackers can register lookalike domains, and a compromised authorized sender can send fully authenticated mail.
Design account emails to reveal less
Email can be stored, forwarded, shown in lock-screen previews, and retained by multiple providers. Keep sensitive details out of both subjects and message bodies. For a security alert, “Your account settings changed” reveals less than a message containing the new phone number or recovery address. Tell users to sign in through the application to see the details instead.
Use reset and verification links carefully
- Generate an unpredictable, single-use token with a short expiry; store a hash of the token where practical.
- Bind each token to its intended purpose and account. A verification token must not work as a password-reset token.
- Build links from a configured, trusted application origin, not an unvalidated request Host header.
- Keep complete reset URLs out of logs. Restrict access to any system that must temporarily handle them.
After a valid reset, invalidate the used token and handle any other outstanding reset tokens according to your product’s policy. Consider revoking existing sessions, especially if the reset follows a suspected compromise. Send a separate change notification, but never include the new password. When someone requests a reset for an unknown email address, show a neutral on-screen response so the form does not reveal which accounts exist.
Build a safer sending pipeline
Use an established mail library or provider integration rather than assembling SMTP messages by hand. Keep transport encryption enabled, verify server certificates, and never silently fall back to an unencrypted connection. TLS protects mail on supported connections in transit; it does not make ordinary email end-to-end confidential.
Check recipient addresses for sensible format and length, then apply the separate business rules: should this account receive the message, and has the address been confirmed for that use? Escape untrusted values in HTML templates and provide a plain-text version when appropriate. User-supplied names, comments, and ticket titles must not become raw HTML or uncontrolled headers. Limit which callers can trigger sends, and rate-limit verification and password-reset flows to reduce inbox flooding and operational abuse.
Be precise about delivery states. A provider accepting a message does not prove it reached an inbox or was read. Retry temporary failures within set limits, avoid endlessly resending one-time links, and handle bounces and complaints according to the message type. Marketing preferences should not accidentally suppress essential account-security notices, but those notices must not carry promotional content.

Test what users and operators actually see
Use test accounts and a sandbox or controlled test domain instead of sending trial messages to customers. Inspect rendered HTML and plain text on narrow screens, with images disabled, and with long names or unusual characters. Check that links point to the intended domain and that quoted user input appears as text, not markup.
Exercise token expiry and reuse, delivery failures, and concurrent reset requests. Logs and dashboards should capture useful operational details—message type, provider response, and a correlation identifier—without recording full message bodies or live tokens. Set retention and access limits for those records; email addresses and delivery metadata are personal data too.
For a focused first check, request a password reset for a test account. Open the delivered message and inspect its subject, destination URL, and visible personal data. Use the link once, then try it again. The second attempt should fail without exposing the token or account details in the error response.
