Absolute positioning in HTML e-mails for Outlook 2007

I couldn’t possibly explain my frustration from Microsoft switching Outlook’s rendering engine to Word so I better not even try. Instead, I’m going to tell you how to make Outlook/Word position elements absolutely.

The idea originally came from doublethink (written in Czech) who made a text field in Word, saved it as HTML and then dug through the mess to extract the essence. I just went a step further and did the same for images as well.

Start by adding this to tag HTML:

  1. <html xmlns:v="urn:schemas-microsoft-com:vml">

Images

We’re lucky Word knows how to insert pictures and “wrap” the text behind/above the picture.

  1. <!–[if gte vml 1]>
  2. <v:shape id="headerShapeImg" type="#_x0000_t75"
  3.  style="position: absolute; height: 106px; width: 769px; z-index: -1;">
  4. <v:imagedata src="/pix/header.png" alt="this is my header"/>
  5. </v:shape>
  6. <![endif]–>
  7.  
  8. <![if !vml]>
  9. <img v:shapes="headerShapeImg" src="/pix/header.png" id="headerImg" alt="this is my header">
  10. <![endif]>

Place the whole thing directly into BODY, both parts where the image is supposed to be. Please note that the IMG tag will be used only for engines other than Word and MSIE.

ID “headerImg” is there to provide reference for further formatting – although don’t expect it to work in Word/Outlook. The only universal method is to use inline CSS via STYLE. Also like it or not, you’ll have to duplicate your formatting definition – define it both for V:SHAPE and for IMG (or DIV, see below).

Others

Other stuff must be wrapped in a div like this:

  1. <!–[if gte vml 1]>
  2. <v:shape id="tableShape" type="#_x0000_t202" filled="f" stroked="f"
  3. style="position: absolute; margin-left: 280px; margin-top: 76px; z-index: 1; width: 470px;"></v:shape>
  4. <![endif]–>
  5.  
  6. <div v:shape="tableShape"><table><tr><td>…</td></tr></table></div>

I’m sure you have already guessed the meaning of attributes filled (background color) and stroked (frame border). Remember, this is Word so we’re talking about a “text frame”.

That’s also a reason why you have to use margin-left and margin-top instead of top and left, or even margin: top right bottom left. And don’t forget to add width to every absolutely positioned element – in numbers, “auto” doesn’t count.

Duplicate formatting

Sweet, huh? Here’s what I used to make my life easier. We’re PHP programmers, remember?

  1. <?php
  2. $tableStyle = <<<HEREDOC
  3. position: absolute;
  4. margin-left: 280px;
  5. margin-top: 76px;
  6. z-index: 1;
  7. width: 470px;
  8. HEREDOC;
  9. ?>
  10. <v:shape id="tableShape"
  11.  style="<?php echo $tableStyle; ?>"></v:shape>
  12. <div v:shape="tableShape"
  13.  style="<?php echo $tableStyle; ?>"><table><tr><td>…

The output will still contain duplicated formatting but at least, you have a single place for changes.

How to debug

The first method that comes to your mind is probably to run your mailing script and then wait for the e-mail to arrive to your Outlook. Since we’re in fact debugging for Word I preferred to open it directly in Word. I wrote my script to display the HTML “e-mail” as a web page instead of sending it and then I opened the url in Word via CTRL+O. You are allowed to paste a url and Word downloads it.

For command line lovers (like me):

  1. "C:\Program Files\Microsoft Office\Office12\WINWORD.EXE" http://server.com/path/page.php

You’ll have to be careful about local cache so append fictitious parameters in order to force reload:

  1. http://server.com/path/page.php&amp;whatever=changing_value

During early stages debug locally with dummy data, of course. No need for the HTML page to be generated by a script using real data. Note though, that when you open a file in Word you cannot write to it using another editor. And when you save from Word you get back all the marvellous garble that you have worked so hard to erase. Enjoy!

Some formatting must be applied to a child element

Did I mention that text-align: right works only when it’s NOT in the DIV we position but in its child? The same is true for font-family, font-weight and font-size:

  1. <div v:shape="myShape">
  2. <div style="text-align: right; font-family: sans-serif;">
  3. hello world
  4. </div>
  5. </div>

will work while if you join the two DIVs together, it will not.

5 Responses to “Absolute positioning in HTML e-mails for Outlook 2007”

  1. Adrenalin says:

    Oh my inexistant God! You really saved my day.

    You know, after banging your head against Outlook 2007 for several hours, trying to Google my way to find out about the lack of backgrounds and then finally ending up in here, tired and frustrated, ready to resign… ;)

    I thank you from the bottom of my heart for these advices.

  2. ciccio says:

    Interesting…
    “<div v:shape=”…

    Please, stop publishing that crap on the web.

  3. I despise this MS-only stuff as much as you do but by closing my eyes I won’t make it go away. So if a client specifically requests he wants his e-mail thing to show well in Outlook 2007 I just take a deep breath and do it. That’s just life I guess.

  4. ciccio says:

    Sorry for being unpolite.
    And I had really appreciated the way you answered to my comment.
    But I arrived here searching for “<div v:shape=” because I have to deal with a customer which has about 20000 xml docs containg html parts.
    The docs are contained in a database of a product that has to be migrated.
    I wrote a software that, among the others, extract the xml from the db blobs, transform some xml nodes and extract some html parts to build a html document, as a part of the migration project.
    While I’m writing it, I was doing some tests against a number of documents as xml parsing and transformation is time and resource consuming, and all went ok.
    Now that the sw is 99.9% done, I’ve tested it against a broader set of documents and it’s failing because of that v:shape attribute.
    Now I have to choose among:
    – add the xmlns to all the documents, whether they have the attr or not (little effort, not elegant)
    – navigate all the nodes and check all the attributes, sanitizing them or adding the xmlns if necessary (middle effort, time and resource consuming)
    – implement my own transformer (high effort)
    – ?
    AFAIK, all the solutions require time and you know time==money/life.
    That’s way I’m unhappy.

  5. Greg Bulmash says:

    Dude, thanks. This worked great. One bit to note for people needing to do this for multiple table cells… use different names AND different z-indexes for each cell’s shapes. I needed to fill 2 cells and did the backgrounds both at -1 with the foregrounds both at 1, the background wouldn’t show on the second cell. When I changed the background to 2 and the foreground to 3 on the second cell, both displayed nicely.

Leave a Reply