Most developers send email without thinking about it as a security surface. These are the things that matter and the questions worth asking before a transactional email flow goes to production.
SPF, DKIM and DMARC
Three DNS records that together prove your sending domain is legitimate and that messages have not been tampered with in transit.
- SPF — lists which mail servers are authorised to send for your domain. A missing SPF record means any server can send mail appearing to be from you.
- DKIM — a cryptographic signature on each message. The receiving server verifies it using a public key in your DNS. If the signature fails, the message was altered in transit.
- DMARC — a policy that tells receiving servers what to do when SPF or DKIM fails (none / quarantine / reject). Without DMARC, failures result in unpredictable delivery behaviour.
All three should be in place before you send to real users. Most transactional mail providers (Resend, Postmark, SendGrid) provide setup instructions specific to their sending infrastructure.
Sanitise inbound HTML
If your application stores or renders email HTML — inbox features, contact forms, imported content — treat that HTML as untrusted input from a stranger. Strip scripts, event handlers, javascript: URLs, iframes, object tags, and remote images before storage. Render the result in a sandboxed frame. See email HTML security for the full threat list.
Check links before rendering
Phishing emails are built around convincing links. If your application renders email body HTML to end users, consider whether you need to warn users before they follow an external link, or rewrite links through a safe-redirect endpoint that checks against a reputation list.
Rate limit all email-triggering endpoints
Password reset, signup confirmation, and any endpoint that triggers an outbound email is an amplification vector if unauthenticated and unthrottled. A loop of rapid requests can flood a third party's inbox (a targeted attack) or exhaust your transactional email quota. Apply per-IP rate limiting and per-recipient rate limiting separately.
Test with disposable addresses
For manual end-to-end checks of signup and transactional flows, a temporary inbox is the fastest tool: generate an address, trigger the flow, read the result. The inbox is genuinely external (not a shared team alias) and the blocked remote images let you verify that your HTML fallbacks and alt text are correct. For automated testing, run a self-hosted mail catcher (MailHog, Mailpit) that gives you API access without sending real mail.