Skip to main content

Full-Width Background Images in Outlook with VML

Make edge-to-edge background images span the full body width in Outlook 2007-2021 using v:rect, mso-width-percent, v:fill type=frame, and v:textbox.

A background image that needs to bleed edge to edge across the full email width fails in Outlook 2007 through 2021 on Windows, where the Word engine ignores CSS backgrounds and clips a fixed-pixel VML rect to its declared width — leaving a 600px image stranded in a wider window. The fix is a <v:rect> driven by mso-width-percent rather than a fixed width, filled with <v:fill type="frame">, with overlaid content placed inside a <v:textbox>. This deep-dive is scoped to Windows Outlook and assumes you already have the dual-path foundation from Email background images and the VML workaround.

Dual render paths for a full-width background The same markup uses a VML rect in Outlook and a CSS background elsewhere, both yielding an edge-to-edge image. One email markup dual-path background block Outlook 2007 to 2021 v:rect + v:fill type=frame Apple Mail / iOS / Gmail CSS background-image Edge-to-edge background renders
One markup block, two engines: VML drives Outlook while a CSS background covers every other client, both reaching the full width.

Root Cause: The Word Engine Clips Fixed-Width Rects

The Microsoft Word rendering engine behind Outlook 2007-2021 treats a <v:rect> with style="width:600px" as a literal 600px object anchored at the content origin. It does not stretch to the available window width and it does not understand CSS background-image on the surrounding <td>. So a hero authored for the contained case renders as a 600px island when the design calls for a wash that reaches both window edges. The engine does honor one VML-specific sizing property: mso-width-percent, which expresses width as tenths of a percent of the parent. Setting it to 1000 means 100%, which is what makes a rect span the full body.

Exact Fix: A Percent-Width Rect with a Frame Fill

<!-- Outlook 2007-2021: this <center> establishes the full-width context the rect measures against -->
<!--[if mso]>
<center>
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false"
        style="mso-width-percent:1000;  /* 1000 = 100% of body width; full-bleed, not 600px */
               height:480px;">
  <v:fill type="frame"                  /* frame = scale image once to the rect (no tiling/doubling) */
          src="https://cdn.example.com/full-bleed-hero.jpg"
          color="#450920" />            /* Outlook-only fallback color behind the image */
  <v:textbox inset="0,0,0,0"            /* zero inset so your own padding controls the layout */
             style="mso-fit-shape-to-text:false;">
<![endif]-->

  <!-- Shared content: a CONSTRAINED 600px table centered over the full-bleed background -->
  <table role="presentation" width="600" cellpadding="0" cellspacing="0" border="0" align="center"
         style="width:600px;max-width:600px;margin:0 auto;">
    <tr>
      <!-- CSS background here serves Apple Mail, iOS Mail, Gmail; Outlook ignores it -->
      <td valign="middle" align="center"
          background="https://cdn.example.com/full-bleed-hero.jpg"
          bgcolor="#450920"
          style="background-image:url('https://cdn.example.com/full-bleed-hero.jpg');
                 background-size:cover;background-position:center;
                 background-color:#450920;height:480px;padding:48px 24px;">
        <h1 style="margin:0;color:#ffffff;font-family:Arial,sans-serif;
                   font-size:32px;line-height:1.2;">Welcome to the Platform</h1>
      </td>
    </tr>
  </table>

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

Every Outlook-specific attribute, called out:

  • mso-width-percent:1000 — the load-bearing property. Tenths of a percent of the parent width; 1000 = full bleed. A fixed width:600px here is exactly what produces the stranded-island bug.
  • type="frame" on <v:fill> — scales the source image once to the rect. Using tile here repeats the image across the full width, and omitting type defaults to a behavior that often doubles the image.
  • color="#450920" — the fallback shown in Outlook if the source fails to load; mirror it with bgcolor on the inner <td> for the other clients.
  • <v:textbox inset="0,0,0,0"> — strips Outlook's default textbox padding so the centered 600px table positions predictably.
  • mso-fit-shape-to-text:false — prevents Outlook from shrinking the rect to the height of its text content, which would collapse a tall hero.
  • The <center> wrapper inside the MSO conditional — gives the percent-width rect a full-width measuring context; without it some builds anchor the rect left.

The pattern is: a full-bleed VML rect for Outlook, with a constrained 600px content table centered on top, so the background reaches the edges while the text stays in a readable column. The same 600px table carries the CSS background for non-Outlook clients.

Variant: Outlook 365 (WebView2/Edge) vs. Outlook 2016

Outlook 2016 and 2019 are unambiguously Word-engine and need the VML path. Outlook 365 is split: many Windows builds still use the Word engine, but newer builds render through WebView2 (the Edge/Chromium control), which reads the CSS background directly and ignores VML. Because both branches coexist in the dual-path block — the WebView2 build follows the CSS <td>, the Word build follows the VML — you do not need to detect the build. Keep both paths and the rect's color/bgcolor fallbacks aligned so the two engines produce the same result. Do not try to feed WebView2 builds a wider VML rect; let them take the CSS branch.

Mso-width-percent in Detail

mso-width-percent is the property that turns a stranded 600px rect into a full-bleed wash, and its units are the part people get wrong: it is expressed in tenths of a percent of the parent width, not whole percent. So 1000 means 100%, 500 means 50%, and 1100 means 110% (useful when you want the image to slightly overscan the body to avoid a hairline gap at the edges):

Fixed versus percentage VML width A fixed-width rect leaves an unpainted band when the reading pane is wider, while mso-width-percent stretches the fill edge to edge. Why the Band Appears on Wide Panes width: 600px painted bare bare The rect stops at 600px; the reading pane keeps its own background either side. mso-width-percent: 1000 painted edge to edge The value is tenths of a percent, so 1000 means 100% of the containing width. Keep the inner content table at 600px — only the painted rect goes full bleed.
Full-bleed backgrounds and fixed-width content are separate concerns: stretch the rect, pin the table.
Value Effective width Use
1000 100% of parent Standard full-bleed hero
1100 110% of parent Overscan to kill edge hairlines
500 50% of parent Half-width split background
(omitted, fixed width:600px) 600px island The bug you are fixing

Two rules make it behave. First, the rect needs a full-width measuring context, which is why the <center> wrapper sits inside the [if mso] conditional — without a parent that spans the window, mso-width-percent has nothing to take a percentage of and some builds anchor the rect at 600px. Second, mso-width-percent controls width only; you still set height in pixels on the rect, and mso-fit-shape-to-text:false so the Word engine does not shrink that height to its text content. Never combine mso-width-percent with a fixed style="width:600px" on the same rect — the fixed pixel width wins in some builds and you get the island bug back intermittently, which is the hardest version to diagnose.

Overlaid Content via v:textbox

The <v:textbox> is what lets text and buttons sit on top of the VML background in Outlook rather than below it. Everything between <v:textbox> and </v:textbox> is rendered inside the rect, over the frame fill. The inset attribute is the textbox's internal padding, given as left,top,right,bottom:

Nesting order for overlaid content The VML rect wraps a textbox, which wraps a normal content table, so the same markup renders once whether or not the client parses VML. Content Sits Inside the Rect, Not Beside It v:rect — the painted background, full bleed v:textbox — inset 0, no border, no fill the ordinary content table headline, copy and button — authored exactly once Clients without VML skip the outer two layers and render the content table alone.
Because the content nests inside the rect, there is no duplicated copy to keep in sync between the two paths.
<!--[if mso]>
<center>
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false"
        style="mso-width-percent:1000;height:480px;">
  <v:fill type="frame" src="https://cdn.example.com/full-bleed-hero.jpg" color="#450920"/>
  <v:textbox inset="0,0,0,0" style="mso-fit-shape-to-text:false;">  <!-- 0 inset: your table controls padding -->
<![endif]-->

  <!-- Shared overlay content: a 600px table centered over the background in BOTH engines -->
  <table role="presentation" width="600" cellpadding="0" cellspacing="0" border="0" align="center"
         style="width:600px;max-width:600px;margin:0 auto;">
    <tr>
      <td valign="middle" align="center"
          background="https://cdn.example.com/full-bleed-hero.jpg" bgcolor="#450920"
          style="background:url('https://cdn.example.com/full-bleed-hero.jpg') center/cover #450920;
                 height:480px;padding:48px 24px;">          <!-- Apple Mail/iOS/Gmail: CSS background + overlay padding -->
        <h1 style="margin:0;color:#fff;font-family:Arial,sans-serif;font-size:32px;line-height:1.2;">
          Welcome to the Platform</h1>
        <!-- a button placed here sits over the image in every engine -->
      </td>
    </tr>
  </table>

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

Practical v:textbox notes:

  • inset="0,0,0,0" strips Outlook's default textbox padding so your inner <td> padding is the single source of spacing — otherwise Outlook adds its own and the overlay sits inconsistently versus the CSS clients.
  • Keep all overlay content inside the textbox. A heading or button placed after </v:textbox> but before </v:rect> renders below the image in Outlook, not over it.
  • v-text-anchor:middle on the rect style vertically centers the textbox content when the overlay is shorter than the rect height; pair it with valign="middle" on the inner <td> for the other clients.
  • Buttons over the background must still take the VML roundrect path from the bulletproof buttons guide; the textbox does not change how a button is built, only where it sits.

Outlook-Version Variants

Outlook 2007/2010. The earliest Word-engine versions are the most literal about mso-width-percent; they require the <center> measuring context and will not full-bleed without it. They also ignore type="frame" subtleties less gracefully — confirm the image scales rather than tiles.

Outlook 2013/2016/2019. The mainstream Word-engine targets. The pattern above works as written; these are the builds to validate first.

Outlook 365 (Word build). Behaves like 2016/2019 — takes the VML branch, honors mso-width-percent.

Outlook 365 (WebView2/Edge build). Renders through Chromium, reads the CSS background-image on the <td> directly, and ignores VML entirely. It takes the [if !mso] path automatically. Do not try to widen the VML rect for it; let it follow the CSS background. As with buttons, the dual-path block means you never detect the build — keep the VML color fallback and the CSS bgcolor/background-color aligned so both engines land on the same hero, and verify against one Word-engine Outlook and one WebView2 Outlook 365.

Pipeline Integration: Keeping VML Through the Inliner

CSS inliners walk the DOM and can mangle or drop the mso-* properties and the conditional comments that protect them. When you run inline CSS automation, configure it to leave conditional comments intact: with Juice, keep comment-preservation on and avoid removeStyleTags stripping the VML-adjacent block; with PostHTML, run the MSO plugin before the inliner so the conditional is treated as opaque. After inlining, grep the compiled output for mso-width-percent and v:rect to confirm both survived, and send a real test rather than trusting the local preview — some ESPs strip HTML comments in transit, which silently removes the entire Outlook branch.

Treat the VML background as a build invariant, the same way you would the VML roundrect button:

  1. Author from a partial so the src, color, height, and mso-width-percent are set once and shared between the VML and CSS branches.
  2. Inline with comment preservation via inline CSS automation — keep conditional comments opaque and avoid an inliner pass that rewrites mso-* properties.
  3. Assert in CI with a grep that fails the build if mso-width-percent, v:rect, or v:fill type="frame" is missing, or if a fixed width:600px has crept onto the rect.
  4. Send a real test, since some ESPs strip HTML comments in transit and silently delete the entire Outlook branch, leaving a flat bgcolor where the hero should be.

Validation Checklist

Frequently Asked Questions

Why is mso-width-percent in tenths of a percent?

It is a Microsoft Office measurement convention rather than a CSS one, so 1000 means 100%. The practical consequence is that a value that looks like a pixel width — 600 — is silently interpreted as 60% and produces a rect narrower than the content it should sit behind, which is a confusing failure because nothing is invalid.

Does the rect need to be inside the table cell?

It needs to wrap the content it paints behind, which in practice means opening inside the cell and closing after the content. Placing it as a sibling produces a painted band with the content rendered below it rather than on top, because VML shapes do not participate in normal flow the way a positioned element would.

What happens in Outlook when images are blocked?

The rect renders with its color fallback and no artwork, which is why the fallback colour is not optional. Since Outlook blocks external images by default, this is the state most Outlook recipients see on first open — the design has to be legible in it, not merely survive it.

Can I use a gradient instead of an image?

VML supports type="gradient" with two colours, and it renders in the Word engine where a CSS gradient does not. It is a genuine option for a hero band that does not need photography, and it removes the image-blocking problem entirely since there is nothing to block.

Why does the background repeat instead of scaling?

Because the fill defaults to tiling. type="frame" scales the image to the shape; without it a 1200-pixel asset inside a 600-pixel rect renders cropped and repeated, which is the same mistake that makes a retina asset look broken rather than sharp.


← Back to Email Background Images and the VML Workaround