When to use this
Login verification, signup confirmation, sensitive-action approval, anywhere you email a short-lived code a user is actively waiting for. That "actively waiting" part defines everything about the design: the reader has your app open in another tab and wants exactly one thing from this email. Every element that isn't the code is friction.
Design rules an OTP email should follow
Keep it almost boring. The code should be the largest thing on the page, spaced out for readability and easy to copy on mobile. State the expiry honestly so a delayed reader knows to request a fresh one. Include the "if you didn't request this" line, it reduces confused replies and spam reports from mistyped addresses. And resist the marketing team's urge to add a banner: promotional content inside transactional mail is how account-critical email starts earning complaints and losing its protected reputation.
The template
Copy-ready, table-based so it renders everywhere, inline styles only. Swap the {{placeholders}} for your values or your template engine's variables.
<!DOCTYPE html>
<html lang="en">
<body style="margin:0;padding:0;background:#f4f5f7;font-family:Arial,Helvetica,sans-serif;">
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background:#f4f5f7;padding:24px 0;">
<tr><td align="center">
<table role="presentation" width="420" cellpadding="0" cellspacing="0"
style="background:#ffffff;border-radius:8px;padding:32px;">
<tr><td style="font-size:18px;font-weight:bold;color:#111;padding-bottom:8px;">
{{company_name}}
</td></tr>
<tr><td style="font-size:14px;color:#444;line-height:1.5;padding-bottom:20px;">
Use this code to finish signing in. It expires in {{expiry_minutes}} minutes.
</td></tr>
<tr><td align="center" style="padding-bottom:20px;">
<div style="font-size:32px;letter-spacing:8px;font-weight:bold;color:#111;
background:#f4f5f7;border-radius:6px;padding:14px 24px;display:inline-block;">
{{otp_code}}
</div>
</td></tr>
<tr><td style="font-size:12px;color:#888;line-height:1.5;">
If you didn't request this code, you can ignore this email.
Someone may have typed your address by mistake.
</td></tr>
</table>
<table role="presentation" width="420" cellpadding="0" cellspacing="0">
<tr><td style="font-size:11px;color:#999;padding:16px 8px;text-align:center;">
Sent by {{company_name}} · {{company_address}}
</td></tr>
</table>
</td></tr>
</table>
</body>
</html>Deliverability: the half that actually fails
No OTP email fails because the button was the wrong shade. They fail by arriving late or landing in spam, and both are sending problems, not design problems. The rules that matter: send OTPs on a transactional stream separated from marketing, so a campaign complaint spike can never drag your login codes into the junk folder. Keep SPF, DKIM, and DMARC aligned, unauthenticated OTPs are prime spam-folder material. And watch latency: an OTP that arrives after the user gave up is a support ticket, which is why per-domain reputation pacing that keeps transactional mail flowing matters more here than anywhere.
If your OTPs are already going to spam, don't redesign the email, run the free deliverability check and the three-cause diagnosis first. It's nearly always auth, reputation, or list, in that order of likelihood for transactional mail.
Related
- Password Reset template and Email Verification template: the link-based siblings
- Welcome template: the email that follows a verified signup
- Transactional Email Service: the sending layer for OTPs
- Transactional Email: the category, defined
- Email for EdTech: OTPs at education scale
- SPF, DKIM, DMARC: the auth your OTPs ride on