Skip to content

Outlook & MSO

Outlook is the reason HTML email feels like it’s stuck in 2005. From 2007 onward, Outlook for Windows renders email using Microsoft Word’s HTML engine, not a real browser. That engine ignores most modern CSS, breaks float and flexbox, and has its own non-standard properties for the things it does support.

This page catalogs the workarounds.

Outlook is not one product. There are at least four distinct renderers under the same name, and each has its own quirks:

ClientRendererQuirks
Outlook 2007-2019 (Windows desktop)Word HTML engineMost restrictive. No CSS3, no media queries, no flex/grid, breaks images and backgrounds without VML hacks.
Outlook 365 (Windows desktop, M365 subscription)Word HTML engineSame as 2019 — Microsoft has not modernized it.
Outlook.com / Outlook for Web (OWA)Webkit-basedBehaves like a modern browser. Supports most CSS, media queries work.
New Outlook for Windows (2024+, the React rewrite)Webkit-basedModern. Effectively Outlook.com in a desktop wrapper.
Outlook for MacWebkit-basedModern. Apple-side of the Outlook family.
Outlook mobile (iOS/Android)Webkit-basedModern.

When this playbook says “Outlook” without qualification, it means the Windows desktop client running the Word renderer — that’s the one that drives every painful decision.

Outlook’s Word renderer reads HTML comments that match the pattern <!--[if mso]>...<![endif]-->. Every other client treats them as plain comments and ignores them. This is the foundation of every Outlook workaround.

<!--[if mso]>
<p>Only Outlook sees this.</p>
<![endif]-->

mso 9 is Outlook 2000. mso 12 is Outlook 2007. Most VML and styling hacks target gte mso 9 (Outlook 2000 or later), which covers every version of the Word renderer:

<!--[if gte mso 9]>
<p>Outlook 2000 and later see this.</p>
<![endif]-->

[if !mso] runs everywhere except Outlook desktop:

<!--[if !mso]><!-->
<p>Every client except Outlook desktop sees this.</p>
<!--<![endif]-->

The <!--> and <!-- opening/closing pattern is intentional — it makes the block readable as a comment by browsers (which would otherwise read the inner HTML as fully-comment-wrapped).

VML (Vector Markup Language) is Microsoft’s pre-SVG vector spec. Outlook’s Word renderer is the only place it still ships. Two patterns appear constantly:

<v:rect> for background images and colored regions

Section titled “<v:rect> for background images and colored regions”
<!--[if gte mso 9]>
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false"
style="mso-width-percent:1000; height:200px;">
<v:fill type="tile" src="image.jpg" color="#FALLBACK" />
<v:textbox inset="0,0,0,0">
<![endif]-->
<!-- Real content for everyone else -->
<!--[if gte mso 9]>
</v:textbox>
</v:rect>
<![endif]-->

See Background Images for the full breakdown.

<!--[if mso]>
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" href="{{cta_url}}"
style="v-text-anchor:middle; width:200px; height:40px;"
arcsize="10%" stroke="f" fillcolor="#222222">
<w:anchorlock/>
<center>
<![endif]-->
<a href="{{cta_url}}" style="...">Button Text</a>
<!--[if mso]>
</center>
</v:roundrect>
<![endif]-->

See Buttons and Bulletproof Buttons for variations.

MSO ghost-tables — give Outlook a fixed width without breaking modern clients

Section titled “MSO ghost-tables — give Outlook a fixed width without breaking modern clients”

Outlook desktop ignores max-width:Npx. If your container is <table style="max-width:600px;width:100%;">, modern clients shrink it correctly on narrow viewports — but Outlook just renders it at the full available width because it never read the CSS. The result: hero images stretch, columns blow out, text spans the whole reading pane.

The fix is a ghost-table: an MSO-only <table width="600"> that exists ONLY for Outlook. Modern clients see plain comments and ignore it.

mso-ghost-table.html
<!-- OUTER wrapper (modern + Outlook) -->
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%"
style="width:100%;background-color:#F5F5F5;">
<tr>
<td align="center" style="padding:20px 10px;">
<!--[if mso | IE]>
<table role="presentation" align="center" width="600" cellpadding="0" cellspacing="0" border="0">
<tr>
<td>
<![endif]-->
<!-- Fluid container that modern clients shrink on mobile -->
<table role="presentation" cellpadding="0" cellspacing="0" border="0"
style="max-width:600px;width:100%;margin:0 auto;background-color:#FFFFFF;">
<tr>
<td>Email content goes here</td>
</tr>
</table>
<!--[if mso | IE]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</table>

What each client renders:

  • Outlook desktop (Word renderer) sees the <!--[if mso | IE]> block as instructions: opens an outer 600px-wide table, drops your fluid table inside, closes the outer. Net effect: fixed 600px wrapper.
  • Every modern client ignores the conditional comment. Sees only the inner max-width:600px;width:100% table. Shrinks fluidly on mobile.

This pattern combined with the 3-table-level wrapper is the canonical hybrid-responsive shell. Use it on every email.

Outlook adds proprietary properties prefixed with mso-. These work nowhere else and don’t break anywhere else — they’re safe to inline:

PropertyUse
mso-line-height-rule:exactlyForces line-height to be pixel-perfect on spacer rows. Without it, Outlook adds extra leading.
mso-hide:allHides an element in Outlook only. Useful for showing fallback images.
mso-padding-altOutlook-only padding. The “alt” version works on cells where regular padding doesn’t.
mso-margin-top-alt, mso-margin-bottom-altOutlook-only margins. Same workaround pattern.
mso-border-altBorders on table cells that Outlook would otherwise drop.
mso-width-percentWidth as a fraction of parent. 1000 = 100%, 500 = 50%. Used inside <v:rect>.
mso-fit-shape-to-textMakes a VML shape size to content. Used when background height is dynamic.

Things Outlook breaks even with workarounds

Section titled “Things Outlook breaks even with workarounds”
  • border-radius on table cells and <td> backgrounds — silently ignored. Use VML <v:roundrect> for rounded buttons.
  • CSS gradients (linear-gradient, radial-gradient) — fall back to solid bgcolor. VML supports gradients via <v:fill type="gradient"> but it’s brittle; usually not worth it.
  • float, flex, grid — Outlook’s Word renderer doesn’t speak modern layout. Use nested tables instead.
  • @font-face, @import, <link> font loads — fonts via these methods get stripped. Use OS-safe stacks (see Text).
  • position:absolute / position:fixed — silently ignored.
  • transform, transition, animation — all silently ignored.
  • background-image in CSS — see Background Images for the VML workaround.
  • max-width on images — ignored. Use the width="" HTML attribute.
  • Three-letter hex colors (#fff) — sometimes silently ignored. Always use six-digit hex.

For multi-version targeting (rare, but useful when Outlook 365 differs from 2019):

<!--[if mso 16]> Outlook 2019/365 only <![endif]-->
<!--[if mso 15]> Outlook 2013 <![endif]-->
<!--[if mso 14]> Outlook 2010 <![endif]-->
<!--[if mso 12]> Outlook 2007 <![endif]-->
<!--[if gte mso 12]> Outlook 2007 and later <![endif]-->
<!--[if lte mso 11]> Outlook 2003 and earlier <![endif]-->

In practice, gte mso 9 covers everything you need to worry about.

Outlook quirks are unpredictable. Always send a test to a real Outlook 2019 or 365 desktop client before shipping a campaign. Litmus, Email on Acid, and Mailtrap all render Outlook accurately if you don’t have a Windows machine handy.