Skip to main content

Email Background Images and the VML Workaround for Outlook

Bulletproof email background images using VML v:rect and v:fill for Outlook 2007-2021 plus a CSS fallback for Gmail, Apple Mail, and iOS.

Background images are the single most fragile visual technique in HTML email. A hero banner that renders perfectly in Apple Mail collapses to a flat color block in Outlook 2016, because the Microsoft Word engine that powers Outlook 2007-2021 on Windows discards the CSS background-image and background shorthand entirely. The reliable fix is a dual-path technique: serve a standard CSS background to modern clients, and inject a parallel Vector Markup Language (VML) image inside Microsoft conditional comments so Outlook draws the same picture through its own renderer. This guide covers the complete bulletproof block, full-bleed versus contained backgrounds, color fallbacks, retina sizing, and the debugging steps for the failure modes you will actually hit in production. It builds on the broader patterns in Mastering Email HTML & CSS.

Why CSS Backgrounds Fail in Outlook

Outlook 2007, 2010, 2013, 2016, 2019, and 2021 on Windows all parse HTML through word.exe's layout engine rather than a browser engine. That engine has no concept of background-image, background-size, background-position, or the background shorthand on block-level elements. When it encounters them it does not warn or partially apply them — it simply drops the declaration, leaving the element with whatever solid background-color (or no color) it inherited.

This is different from the float and flexbox gaps documented in Outlook rendering fixes. Those properties degrade to default block flow; backgrounds vanish outright. There is no CSS-only escape hatch, because the engine never reads the relevant properties. The only supported raster-fill primitive in the Word engine is VML, a 1998-era Microsoft vector format that Office still understands. So the canonical approach is to keep the CSS background for the 90% of opens that happen in WebKit and Blink clients, and add a VML twin that only Outlook sees.

Two render paths for one background block One HTML block contains both a VML image read only by Outlook and a CSS background read by all other clients, producing the same visual result. One Block, Two Render Paths Background Block VML + CSS in one td Outlook 2007-2021 (Word) Reads only the [if mso] branch v:rect + v:fill draws image CSS background ignored Result: hero renders correctly Apple Mail / Gmail / iOS Skips the conditional comment CSS background-image draws VML markup invisible Result: hero renders correctly
The dual-path technique: Outlook follows the VML branch while every WebKit and Blink client follows the CSS branch, yielding the same hero across the board.

Core Implementation: A Complete Bulletproof Background

The structure below is the production reference. The outer <td> carries the CSS background for modern clients. Inside it, an <!--[if mso]> block opens a <v:rect> sized to match, fills it with <v:fill type="frame">, and opens a <v:textbox> so overlaid text flows on top. The non-Outlook content lives between the textbox open and close so it is shared by both paths.

<!-- VML namespaces MUST be declared on the <html> tag or Outlook strips all v: elements -->
<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">

<table role="presentation" width="600" cellpadding="0" cellspacing="0" border="0" align="center" style="width:600px;">
  <tr>
    <!-- Apple Mail, iOS Mail, Gmail webmail read this CSS background; Outlook ignores it -->
    <td background="https://cdn.example.com/hero.jpg"
        bgcolor="#450920"
        valign="top"
        style="background-image:url('https://cdn.example.com/hero.jpg');
               background-size:cover;
               background-position:center;
               background-color:#450920;  /* fallback color if image fails to load */
               height:300px;">

      <!--[if mso]>
      <!-- Outlook 2007-2021: Word engine ignores CSS background, so draw the image with VML -->
      <v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false"
              style="width:600px;height:300px;">
        <v:fill type="frame" src="https://cdn.example.com/hero.jpg" color="#450920" />
        <v:textbox inset="0,0,0,0">
      <![endif]-->

      <!-- Shared overlay content: read by BOTH Outlook (inside v:textbox) and other clients -->
      <div>
        <table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0">
          <tr>
            <td align="center" valign="middle" style="padding:80px 24px;">
              <!-- text-shadow improves legibility on busy images in WebKit; Outlook ignores it -->
              <h1 style="margin:0;color:#ffffff;font-family:Arial,sans-serif;font-size:30px;
                         line-height:1.2;text-shadow:0 1px 3px rgba(0,0,0,0.5);">
                Your Order Has Shipped
              </h1>
            </td>
          </tr>
        </table>
      </div>

      <!--[if mso]>
        </v:textbox>
      </v:rect>
      <![endif]-->

    </td>
  </tr>
</table>

Attribute notes that matter in practice:

  • type="frame" on <v:fill> scales the image once to the rect size — this is the right mode for a hero. type="tile" repeats it (pattern fills), and type="frame" is what prevents the doubled-image artifact described below.
  • color on <v:fill> is the Outlook-only fallback color. Pair it with bgcolor on the <td> so non-Outlook clients also show a solid color while the image loads or if it is blocked.
  • <v:textbox inset="0,0,0,0"> removes Outlook's default internal padding so your own padding controls layout.
  • The background HTML attribute on the <td> (not just the CSS property) is read by some older Gmail and Yahoo states and is harmless elsewhere — keep both.

Second Pattern: Full-Body Background vs. a Single Cell

A contained background wraps one cell — the hero above. A full-bleed background must cover the entire email width edge to edge, which Outlook cannot do with a fixed-pixel rect alone because the Word engine clips VML to its declared width. For a body-wide wash, set the rect to fill the viewport using mso-width-percent and a fixed maximum:

<!--[if mso]>
<!-- Outlook 2016-2021: mso-width-percent:1000 makes the rect span the full body width -->
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false"
        style="mso-width-percent:1000;height:480px;">
  <v:fill type="tile" src="https://cdn.example.com/bg-pattern.png" color="#fdf2f5" />
  <v:textbox inset="0,0,0,0">
<![endif]-->

The mechanics of full-bleed sizing — mso-width-percent, the centered <center> wrapper, and overlaying constrained content inside a wide background — are involved enough that they have their own walkthrough: Full-width background images in Outlook with VML. Use a single-cell contained background whenever the design allows it; reserve the full-bleed pattern for true edge-to-edge sections.

Retina and Sizing

Outlook's VML rect renders the image at the rect's CSS pixel dimensions, so supply a 2x source (e.g. a 1200x600 image displayed in a 600x300 rect) and let type="frame" downscale it. Do not declare the doubled dimensions on the rect itself or Outlook will render the hero at twice the intended height.

Provider and Client Constraint Table

Client CSS background-image CSS background shorthand VML v:fill Notes
Gmail (webmail) Supported on <td>/<div>; stripped on <body> Stripped on <body>; partial elsewhere N/A Move background off <body> onto a wrapper <td>
Gmail (Android/iOS app) Supported on <td> Partial N/A Same wrapper-cell rule applies
Outlook 2016/2019 (Win) Ignored Ignored Required Word engine; VML is the only path
Outlook 365 (Win) Ignored on most builds Ignored Required Some WebView2 builds vary; keep VML
Apple Mail (macOS) Full support Full support Ignored Reads CSS path cleanly
iOS Mail Full support Full support Ignored Reads CSS path; honors background-size:cover
Samsung Email Supported on <td> Partial N/A Avoid shorthand; use longhand properties

The pattern that survives every cell above: longhand CSS background properties on a wrapper <td> (never <body>), a bgcolor fallback, and a VML twin for Outlook.

Pipeline Integration Steps

  1. Author the background block with both the CSS <td> and the <!--[if mso]> VML twin in your template source (MJML's mj-hero or a hand-built partial).
  2. Declare namespaces — confirm xmlns:v and xmlns:o are on the <html> tag of the compiled output; MJML adds them automatically, hand-built templates must include them.
  3. Inline CSS with your inline CSS automation step configured to preserve conditional comments — Juice with preserveImportant and comment retention, or PostHTML's MSO plugin, so the VML block survives inlining.
  4. Host images on HTTPS with long cache headers; Outlook re-fetches VML sources on every open.
  5. Verify the conditional comments survive ESP transit — many senders strip HTML comments by default; disable that in your ESP settings.

Debugging

  • Image not showing in Outlook: The xmlns:v namespace is missing from <html>, or your ESP stripped the conditional comments. Check the raw source after ESP transit, not just your local build.
  • Image appears twice / doubled height: You used type="tile" on a hero (switch to type="frame"), or you sized the rect to the 2x retina dimensions. The rect must use the display size; the source can be larger.
  • Text unreadable over the image: Outlook ignores text-shadow. Add a semi-opaque overlay via a second VML fill color, or bake a darkening gradient into the image itself, and keep a high-contrast bgcolor.
  • Background shows in Outlook but not Gmail: You put the background on <body> — Gmail strips it there. Move it to a wrapper <td>.
  • Solid color only, no image, everywhere: The image URL is not publicly reachable over HTTPS, or it is being blocked as a tracking asset.

Validation & Deployment Checklist

  • xmlns:v and xmlns:o declared on the <html> tag of compiled output.
  • CSS background on a wrapper <td>, never on <body>.
  • bgcolor / background-color fallback present on both the <td> and the <v:fill> color attribute.
  • <v:fill type="frame"> used for heroes (not tile).
  • <v:textbox inset="0,0,0,0"> wraps overlaid content.
  • Conditional comments survive ESP transit (verified on a real send, not local).
  • Tested in Outlook 2016/2019/365 (Win), Apple Mail, iOS Mail, Gmail, Samsung Email.
  • 2x retina source supplied; rect sized to display dimensions.
  • Overlay text legible with image blocked and with image loaded.

The Dual-Path Model in Detail

Everything in this technique reduces to one idea: two renderers read two different branches of the same markup, and both must independently produce the right picture. Get comfortable with the split and the rest follows.

The CSS path is what WebKit (Apple Mail, iOS Mail) and Blink (Gmail webmail and app, Samsung Email) read. They parse the <td> with its background-image, background-size:cover, and background-position, ignore the <!--[if mso]> comment as an HTML comment, and draw the image with normal browser semantics. This path supports cover, contain, gradients layered over the image, and background-position keywords — full fidelity.

The VML path is what word.exe reads. Outlook 2007-2021 (and most Outlook 365 desktop builds) skip the CSS background entirely, then enter the <!--[if mso]> branch and draw a <v:rect> filled by <v:fill>. VML is a 1998 vector format with its own coordinate model; it has no background-size, only a fill type (frame, tile, gradient, solid). The overlay content sits inside <v:textbox> so it paints on top of the fill.

The two paths never see each other: the conditional comment hides VML from non-Outlook clients, and Outlook's failure to read CSS backgrounds hides the CSS path from it. The discipline is that every change you make has to be mirrored on both branches — change the image URL, change it in both background-image and v:fill src; change the height, change it on the <td> style and the v:rect style; change the fallback colour, change bgcolor/background-color and the v:fill color attribute. A change on one branch only is the most common source of "works in Apple Mail, broken in Outlook" regressions.

v:rect, v:fill, and v:textbox: the Three Elements

Three VML elements do all the work, and each has attributes that are easy to get subtly wrong.

<v:rect> is the rectangle that holds the fill. It needs fill="true" and stroke="false" (otherwise Outlook draws a 1px border around the hero) and a style carrying the display dimensions. Use width:600px;height:300px for a contained hero, or mso-width-percent:1000;height:300px for a full-bleed wash. Never put the 2x retina dimensions here — the rect size is the on-screen size.

<!--[if mso]>
<!-- Outlook 2007-2021: stroke=false removes the default 1px border; size = display size, not 2x -->
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false"
        style="width:600px;height:300px;">
<![endif]-->

<v:fill> describes how the rect is painted. type="frame" scales one image to fill the rect (correct for heroes); type="tile" repeats it (correct for seamless patterns); type="gradient" and type="solid" paint colour. The src is the image, and color is the Outlook-only fallback shown if the image is blocked. A type="frame" fill does not support background-position — it always centre-fits — so if your design depends on an off-centre focal point, bake the crop into the asset.

<!--[if mso]>
<!-- Outlook: frame = scale-to-fit (heroes); color is the fallback when the image is blocked -->
<v:fill type="frame" src="https://cdn.example.com/hero.jpg" color="#450920" />
<![endif]-->

<v:textbox> is the container for overlay content. inset="0,0,0,0" strips Outlook's default internal padding (left, top, right, bottom) so your own table padding governs spacing. Forgetting inset leaves a few pixels of unexpected margin around your overlay in Outlook only. The shared HTML content goes between the <v:textbox> open and its close, which is why those two tags live in separate conditional-comment blocks straddling the content.

CSS Background vs. VML: When to Use Which Path Leads

Both paths always ship together, but which one you optimize around depends on the design:

Design need Lead path Why
Photographic hero, centred focal point Either (both fit) frame fit matches background-size:cover closely
Off-centre focal point / art-directed crop CSS (background-position) VML frame cannot offset; bake crop into asset for Outlook
Seamless repeating pattern VML tile + CSS repeat Both repeat; supply a small seamless tile
Solid colour with subtle texture bgcolor + VML color Texture is enhancement; colour is the guarantee
Gradient overlay over photo CSS only (linear-gradient) VML gradient is crude; darken the asset itself for Outlook

Full-Bleed vs. Contained, Revisited

The distinction drives the rect width attribute. A contained background is bounded by a fixed-width column (the 600px hero), so the rect uses width:600px and the CSS <td> is inside a width:600px table. A full-bleed background must reach both edges of the viewport regardless of width, which Outlook cannot express with a fixed pixel rect; it uses mso-width-percent:1000 to span the body, wrapped in a <center> so it anchors edge to edge. The constrained content (text, buttons) then sits in an inner 600px table on top of the wide fill. Because the sizing math and the centred-content overlay are fiddly, the complete walkthrough lives in full-width background images in Outlook with VML — start from the contained pattern here and graduate to that one only when the design is truly edge-to-edge.

Background Colors as the Universal Fallback

The image is never guaranteed: it can be blocked (Outlook blocks remote images by default until the user enables them), fail to load, or be stripped as a tracking asset. A solid colour underneath is the only thing that always renders, so it is mandatory, not optional. Set it in three places so every path is covered:

<!-- bgcolor attribute: oldest Gmail/Yahoo states and image-blocked fallback everywhere -->
<td background="https://cdn.example.com/hero.jpg"
    bgcolor="#450920"
    style="background-color:#450920;        /* CSS path image-blocked fallback */
           background-image:url('https://cdn.example.com/hero.jpg');
           background-size:cover;background-position:center;height:300px;">
  <!--[if mso]>
  <!-- color attr: Outlook fallback when remote image is blocked (the default state) -->
  <v:rect fill="true" stroke="false" style="width:600px;height:300px;">
    <v:fill type="frame" src="https://cdn.example.com/hero.jpg" color="#450920" />
  <![endif]-->
</td>

Choose a colour sampled from the darkest meaningful region of the image so overlay text stays legible when the photo is absent. White text over a hero that falls back to a light tint becomes invisible the moment the image is blocked — exactly the state most Outlook recipients see on first open.

Retina and Sizing Deep-Dive

Two independent sizing rules are at play. The rect is sized in display pixels (width:600px;height:300px); this is the box Outlook paints. The source image should be 2x those dimensions (1200x600) so it stays crisp on high-DPI displays — type="frame" downscales it. The trap is putting the 2x numbers on the rect: Outlook then renders a 600px-wide hero at 1200px and pushes the rest of the email off-screen. The CSS path needs the same care: declare height:300px (display) on the <td> and let background-size:cover handle the 2x source. Also confirm o:PixelsPerInch is 96 in the head MSO block, or Outlook DPI scaling silently inflates the rect on high-DPI Windows machines.

Provider Edge Cases Beyond the Core Table

  • Outlook.com webmail (browser): Uses a browser engine, not Word — it reads the CSS path, not VML. The dual technique still works because it ignores the conditional comment.
  • Outlook for Mac: WebKit-based, reads CSS backgrounds fine; no VML needed but harmless.
  • Outlook 365 WebView2 builds: A subset of recent 365 desktop builds render via WebView2 (Chromium) and read CSS. Keep the VML twin anyway — the rendering engine varies by build and update channel, and you cannot detect it at send time.
  • Gmail on <body>: Backgrounds on <body> are stripped in all Gmail surfaces; always use a wrapper <td>, mirroring the wrapper-cell rule in responsive email layouts.
  • Samsung Email: Reads CSS backgrounds on <td> but is unreliable with the background shorthand — use longhand background-image/background-color only.

Extended Debugging

  • Hero is correct height in Apple Mail but doubled in Outlook: The rect style carries the 2x retina dimensions. Set the rect to the display size; keep the 2x only on the source asset.
  • Thin 1px border around the hero in Outlook only: stroke="false" is missing on <v:rect>. Add it.
  • Overlay text has extra padding in Outlook only: <v:textbox inset="0,0,0,0"> is missing or has non-zero insets.
  • Pattern fill shows seams in Outlook: The tile asset is not seamless, or type is frame instead of tile. Use a true seamless tile with type="tile".
  • Works locally, image missing after sending: The ESP stripped HTML comments in transit, removing the VML branch. Disable comment stripping in the ESP and re-verify on a real send.
  • VML draws but at the wrong position on full-bleed: Missing <center> wrapper or wrong mso-width-percent; follow the dedicated full-width guide.
  • Image flashes then disappears in Outlook: Outlook re-fetches VML src on each open; the URL must be permanently reachable over HTTPS with cache headers, not a signed/expiring URL.

Frequently Asked Questions

Do I really need VML, or can I just accept a flat colour in Outlook?
That is a legitimate product decision. If your Outlook share is small and a solid bgcolor behind white text reads acceptably, ship the CSS path plus a strong fallback colour and skip VML. The dual-path technique exists for designs where the background image carries meaning — a branded hero, a product shot, a textured section — and a flat block would look broken. Decide per template, not globally.

Does MJML generate the VML for me?
MJML's mj-hero and the background-url attribute on mj-section emit the VML twin and declare the xmlns:v/xmlns:o namespaces automatically. Hand-built templates must add both. If you hand-edit MJML output, preserve the conditional comments through your minifier or you will strip the generated VML.

Why does the image work in my browser preview but not after sending?
Two usual causes. First, the ESP stripped HTML comments in transit and removed the VML branch — verify on a real send, not a local file. Second, the image URL is not publicly reachable: browser previews load it from your local network, but the recipient's client fetches it cold over the internet and must be able to reach it over HTTPS.

Can I use a CSS gradient as the background instead of an image?
WebKit and Blink clients render linear-gradient/radial-gradient backgrounds well. Outlook does not read CSS gradients at all, and VML's type="gradient" is crude (two-stop, axis-limited). For a gradient that must appear in Outlook, render it to a small image and use the standard frame/tile fill, or accept the bgcolor fallback there.

How big should the source image be?
Supply 2x the display dimensions for retina sharpness — a 600x300 hero ships a 1200x600 source — and let both background-size:cover (CSS path) and type="frame" (VML path) downscale it. Keep the file optimized; Outlook re-fetches it on every open, so an oversized asset hurts perceived load.

Hand-off and Maintenance Notes

Because every change must touch both branches, treat the background block as a single component, not loose markup. Build it as a reusable partial (MJML component or a templating-engine include) with the image URL, height, and fallback colour as parameters, so a designer cannot update the CSS path and forget the VML src. In code review, the one thing to check on any background change is that the URL, height, and colour match across the <td> style, the bgcolor attribute, the v:rect style, and the v:fill src/color. The VML technique here is the same family of Word-engine workaround used for clickable CTAs in bulletproof email buttons, so a team that standardizes one usually standardizes the other in the same partial library — and both depend on the conditional-comment-preserving build configured in inline CSS automation.


← Back to Mastering Email HTML & CSS