We shipped a beautiful transactional email design once. Rounded corners, a clean two-column layout, a subtle gradient header. It looked perfect in Gmail, Apple Mail, and every email preview tool we tested. Then we got a support ticket from a user on Outlook 2019: 'Your email looks broken.' We opened it in Outlook and stared at the screen for a good fifteen seconds. The layout was completely destroyed. The gradient was gone. The button looked like a hyperlink from 1998.
Here's the uncomfortable truth: Outlook — specifically the Windows desktop versions (2013, 2016, 2019, 2021, and yes, some versions of the new Outlook for Windows) — still uses Microsoft Word's rendering engine to display HTML emails. Not a browser engine. Word. The same software you use to write reports. This is why email development is its own dark art, separate from everything you know about web development, and why every email developer has a special kind of thousand-yard stare.
Why Outlook Is a Special Kind of Pain
Most modern email clients (Gmail, Apple Mail, Yahoo, even Outlook.com the web version) use WebKit or similar browser engines to render HTML. They're not perfect, but they're at least in the same universe as what you'd expect. Desktop Outlook uses the Word rendering engine, which means it has its own completely separate set of supported CSS properties, and the list is... short.
- No CSS Grid support — period
- No Flexbox support — forget it
- No CSS background-image on divs — just gone
- border-radius is ignored — your buttons will be rectangles
- max-width and min-width are inconsistently supported
- padding on divs is unreliable — use table cells instead
- Margin on many elements is partially or completely ignored
- No web font support — system fonts only
If you're using React Email or MJML (which we recommend — more on that in a second), a lot of this is handled for you. But you still need to understand what's happening under the hood when things break, because they will break, and you'll need to debug it without losing your mind.
The Table-Based Layout Reality
Email HTML is basically what web development looked like in 2002. You have to use tables for layout. Not as a fallback. As your primary structure. This feels deeply wrong after years of semantic HTML and modern CSS, but it's just the reality. Tables are what Outlook understands, and they render consistently across the widest range of email clients.
<!-- DON'T do this for layout (broken in Outlook) -->
<div style="display: flex; gap: 24px;">
<div style="flex: 1;">Column 1</div>
<div style="flex: 1;">Column 2</div>
</div>
<!-- DO this instead -->
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%">
<tr>
<td width="50%" style="padding-right: 12px;">
Column 1
</td>
<td width="50%" style="padding-left: 12px;">
Column 2
</td>
</tr>
</table>The role="presentation" attribute is important — it tells screen readers to ignore the table structure, because this table exists for layout, not data. It's a small accessibility win in an otherwise ugly situation. Also note cellpadding="0" cellspacing="0" and border="0" — you almost always want those. Without them, email clients will add default spacing and borders that will make you question your career choices.
Making Buttons That Don't Look Terrible
Buttons are where most email designs fall apart in Outlook. You can't just apply border-radius to a div or a span. Outlook will render a flat rectangle. There are two main approaches. The first is the VML (Vector Markup Language) button, which uses Microsoft's proprietary XML format that only Outlook understands. Yes, really. The second is to accept the rectangle and style it as nicely as possible. We generally go with VML for important CTAs and move on with our lives.
<!-- Rounded button that works in Outlook using VML -->
<!--[if mso]>
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:w="urn:schemas-microsoft-com:office:word"
href="https://example.com"
style="height:44px; width:180px; v-text-anchor:middle;"
arcsize="25%"
strokecolor="#4F46E5"
fillcolor="#4F46E5">
<w:anchorlock/>
<center style="color:#ffffff; font-family:sans-serif; font-size:14px; font-weight:bold;">
Get Started
</center>
</v:roundrect>
<![endif]-->
<!--[if !mso]><!-->
<a href="https://example.com"
style="background-color:#4F46E5; border-radius:8px; color:#ffffff;
display:inline-block; font-family:sans-serif; font-size:14px;
font-weight:bold; line-height:44px; text-align:center;
text-decoration:none; width:180px; -webkit-text-size-adjust:none;">
Get Started
</a>
<!--<![endif]-->The <!--[if mso]> and <!--[if !mso]><!--> are conditional comments — an ancient HTML feature that Outlook still supports (and relies on). The first block renders only in Outlook, the second renders everywhere else. It's ugly, but it works. If you're using MJML, the mj-button component handles all of this for you automatically, which is one of the main reasons we use it.
Images and Background Images
Outlook blocks images by default until the user clicks 'Download Pictures'. This means your email needs to make sense without images. Always add descriptive alt text. Never use an image to display critical information like your company name, the main CTA text, or pricing. If the image is purely decorative, alt="" is fine — screen readers will skip it.
Background images in CSS (background-image: url(...)) are completely ignored by Outlook on div elements. If you need a hero section with a background image, you have to use VML again. Or — and this is our usual recommendation — just use a solid background color as a fallback and make the design work either way. Hero images in emails are often more trouble than they're worth.
<!-- Background image with VML fallback for Outlook -->
<!--[if gte mso 9]>
<v:rect xmlns:v="urn:schemas-microsoft-com:vml"
fill="true" stroke="false"
style="width:600px; height:200px;">
<v:fill type="frame" src="https://example.com/hero.jpg" color="#4F46E5" />
<v:textbox inset="0,0,0,0">
<![endif]-->
<div style="background-color:#4F46E5;
background-image:url('https://example.com/hero.jpg');
background-size:cover; background-position:center;
padding:40px 32px;">
<h1 style="color:#ffffff; font-family:sans-serif; font-size:28px; margin:0;">
Welcome aboard
</h1>
</div>
<!--[if gte mso 9]>
</v:textbox>
</v:rect>
<![endif]-->Typography Without Web Fonts
Outlook doesn't support web fonts loaded via @import or @font-face. Your beautifully chosen Inter or Geist font just becomes Arial or Times New Roman. The only reliable approach is a solid font stack that degrades gracefully.
/* Font stack that works everywhere */
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
Helvetica, Arial, sans-serif;
/* For a more 'branded' feel that still degrades well */
font-family: Georgia, 'Times New Roman', Times, serif;
/* What NOT to do */
font-family: 'Inter', sans-serif; /* Will fall back to sans-serif immediately in Outlook */Some email clients (Apple Mail, iOS Mail, newer Outlook.com) do support web fonts via @font-face in a style block. If fonts are important to your brand, you can include them and accept that ~40% of desktop Outlook users will see the fallback. Just make sure the fallback is intentional and not jarring. Set font sizes, line heights, and weights that look good in both.
Testing Is Non-Negotiable
You cannot trust your mental model of 'this should work'. You have to test. The main options are Litmus and Email on Acid — both render your email across dozens of clients and show you screenshots. They're not cheap, but they're cheaper than getting a hundred support tickets about broken emails. For quick testing during development, we usually spin up a local Outlook installation and just send to ourselves. Not glamorous, but free.
Never ship an email template to production without testing in at least Outlook 2016/2019, Gmail web, Apple Mail, and a mobile client. That covers roughly 85% of real-world usage and will catch most of the serious breakages.
Litmus has a free tier that gives you a handful of previews per month. For a small indie project, that might be enough. If you're building a SaaS and transactional emails are important to your UX — and they are — a paid Litmus plan is worth the money. It's caught bugs for us that we never would have found otherwise.
The MJML and React Email Situation
If you're starting from scratch in 2025, don't write raw email HTML by hand. Use MJML or React Email. Both abstract away most of the table-based nonsense and generate Outlook-compatible HTML for you.
React Email is great if you want to write emails in JSX and integrate tightly with your Next.js codebase. You get component reuse, TypeScript, and a nice preview dev server. The trade-off is that some components don't handle every Outlook edge case perfectly — you'll occasionally need to drop to raw HTML for specific things. MJML is more battle-tested for pure Outlook compatibility but requires you to learn its own markup language, which is less intuitive than JSX.
Our stack at peal.dev templates uses React Email with Resend for delivery. We've pre-built transactional email templates (welcome emails, password resets, team invites) that are already tested across Outlook versions, so you don't have to spend a weekend debugging why your button looks wrong in Outlook 2016. The goal was to make email the boring part of building a product, not the part that eats a whole sprint.
Quick Wins That Fix 90% of Outlook Problems
- Set width on table cells, not on inner divs — Outlook respects td width more reliably
- Use inline styles for everything critical — external stylesheets are ignored by many clients
- Set explicit line-height in pixels, not unitless numbers — Outlook handles them differently
- Add mso-line-height-rule:exactly when setting line-height to prevent Outlook from adding extra space
- Use display:block on images and set explicit width/height — prevents mysterious gaps
- Add style='border:0' to all images to remove default link borders in older Outlook
- Test with images disabled — your email should still communicate its main message
- Keep your email width at 600px max — it's the safe width that works everywhere
The single most useful thing you can do: open every finished email in Outlook with images disabled. If it's a confusing wall of alt text and broken layout, you have work to do.
Email development is genuinely annoying. It's one of those areas where years of web development experience don't transfer cleanly, and you have to re-learn a bunch of 2003-era techniques to get things working. But the fundamentals are finite. Learn the table layout model, understand conditional comments, get a test setup running, and most emails you'll ever need to build will be achievable without losing sleep over them. The tricks in this post have saved us from a lot of late-night debugging sessions. Hopefully they'll do the same for you.
