Creating a Future-Proof Responsive Email Without Media Queries

Final product image
What You’ll Be Creating

There are quite enough headaches to deal with when coding HTML email. So it hardly seems fair if we also need to keep on top of the new email clients and device sizes that pop up every week. CSS and media query support can vary from app to app making it impossible to avoid being consumed by fear every time you hear that there’s a new and exciting mail app that you’ve yet to test.

But what if you could build an email template that was responsive, even in environments with the poorest support for modern CSS? What if, every time you heard about some new email app that everyone’s trying, instead of shaking with fear, you could feel safe and secure in the knowledge that your emails probably look fine?

The method that I espouse below is all about creating a good experience for email clients which have no media query support whatsoever.

It’s called the fluid hybrid method, sometimes referred to as the spongy method of email development. The fluid part refers to the fact that we use lots of percentages. The hybrid part is because we also use max-width to restrict some of our elements on larger screens.

Six Major Problems We’re Aiming to Solve

1. Gmail’s app for Android and iOS is a pain

It’s more popular than the default mail app on Android, but Gmail doesn’t support media queries, which we traditionally rely on to resize and reformat our emails for small screens. This tutorial will show you how to make emails that are responsive, even in the Gmail app.

2. New email apps are being released all the time

It’s difficult to keep track of all the new mail apps that keep appearing. Some of them really care about email rendering and have great CSS and media query support, but some of them focus more on email workflows and don’t support media queries at all. This tutorial will show you how to make an email that is always responsive, no matter the level of CSS support.

3. The number of possible device screen sizes is almost infinite

Not only do we have large desktops and tiny smartphones, but we also have large smartphones and tiny laptops. Just because someone is accessing their Gmail via their laptop doesn’t mean their screen is big enough to view a 700px wide email, and people using an iPhone 6+ could handle a two-column layout, but instead are usually stuck with a single column. This tutorial shows you how to make a layout that will reformat to fit the space available, even in webmail.

4. Creating a responsive email by stacking <td>s on mobile doesn’t work everywhere

Certain email clients (on iOS and even some of the native mail apps on previous versions of Android) do not properly stack two table cells on the same row; they will only stack two individual tables. This tutorial uses a completely different method that is fully supported across all apps and devices. The usual solution to the problem is to use tables with the align="left" or align="right" attribute, but that presents another pitfall:

5. When using the aligned table method of responsive development, your tables are stuck aligned to the left or right in mobile apps which don’t support media queries

The method in this tutorial uses a different approach which ensures that your columns all stack in the centre on mobile, even in the Gmail app. (You can also easily set them to align to the left or right if you prefer.)

Tables aligned to the left or right remain in their positions in mobile apps that don’t support media queries. You can’t adjust them using mobile-specific CSS
This tutorial will show you how to have your columns stack in the center, even in apps that don’t support media queries

6. When you use the aligned table method of responsive development, you lose the ability to vertically align content in adjacent columns

This tutorial will also show you how to vertically align two columns on the same row to the top or the middle, as if they were all table cells on the same row that were using the valign attribute.

This tutorial will teach you the ’fluid hybrid’ method, which allows you to vertically align your columns to the top, middle or bottom

1. Getting Started

Start with a blank file and save it as index.html, then copy and paste this code:

Let’s quickly run through all of the elements in the code above:

!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" is the DOCTYPE I like best—I find it yields the fewest quirks.

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> gives us support for all Unicode characters in our document.

<meta http-equiv="X-UA-Compatible" content="IE=edge" /> and <meta name="viewport" content="width=device-width, initial-scale=1.0"> are used here so that Windows Phones will display our mobile version correctly.

We’ll include <title></title> although it’s best to leave it empty. A title tag is required for valid XHTML, but some native Android mail clients will display this title just before the preheader in the inbox preview, which usually isn’t ideal.

You’ll see that I’m using an external stylesheet for this tutorial, but the approach you take is up to you. To follow along, you should now create a new document called styles.css and save it in the same directory as your HTML file. We’ll be inlining our CSS at the end.

Next, between <!--[if (gte mso 9)|(IE)]> and <![endif]--> we have some conditional CSS for Outlook to force it to collapse borders on all tables and prevent unwanted gaps. This conditional expression targets all versions of Microsoft Outlook (mso) greater than or equal to version 9 (which is all of them since version 9 is the earliest: Outlook 2000) as well as versions of Outlook that use Internet Explorer to render (being Outlook 2000–2003).

Under the body, first we have a <center> tag, to center its contents and act as our bearer of a few useful global CSS properties (since the body tag often gets stripped in webmail clients). We also have <div class="webkit"> for earlier versions of WebKit-powered mail clients (basically only Apple Mail 6 and below, and Outlook 2011 in some cases). These earlier versions only support max-width on block-level elements and the easiest way to ensure our layout displays at the correct size is to wrap it in this div, which saves us having to set the widths in a media query as per my previous tutorial. (Thanks go to zerocents for this fix.)

2. Initial Styles

Next, create a blank CSS file called styles.css. Into your newly-created file, paste the following:

Here I am zeroing the margins and padding on the body, table and table cells and zeroing any borders that would appear on linked images. Our styles for the table and td tags are to take the place of the cellpadding and cellspacing HTML attributes. It’s entirely up to you if you prefer to use the HTML attributes instead; in the past I’ve always supported using an HTML attribute instead of a CSS property where possible, however as I have worked on more and more large-scale projects I have found that it can be more manageable to specify these in the CSS, especially if you are usually working in a platform that automatically handles CSS inlining for you.

I usually include a min-width of 100% on the <body> tag to avoid any situations where the content doesn’t take up the full width of the viewport on mobile, and it’s always a good idea to set your background colour, even if it’s pure white, to avoid background colour glitches in Outlook or Lotus Notes.

We also have our styles for .wrapper with a few properties to stop text resizing in a weird way on Windows Phones and iOS, as well as table-layout: fixed to ensure our centered content will actually be centered in Yahoo mail. We’re setting a max-width of 600px wide on our .webkit div to contain everything in Apple Mail 6 (and below) and Outlook 2011.

Finally we have a viewport fix which, in conjunction with our two meta tags in the head, will ensure everything looks right on Windows Phones.

3. Creating the Structural Outer Container

We’ll start with one of the key building blocks for this method: a conditional table for Outlook that is hidden to all other clients. We need these because we’re going to be using the max-width property which Outlook doesn’t support. Therefore we need to create special Outlook-only tables with explicit pixel widths to contain everything in Outlook.

Our conditional table for Outlook is used because Outlook doesn’t support the max-width property

So in our HTML file, let’s delete the [content goes here] placeholder and paste in the following code. I tend to keep my conditional code tags all left-aligned at the same indentation level for readability, but how you format them is up to you.

Note: there is no styling on my conditional table tags. I’m going to be using Campaign Monitor’s inliner tool,, which also inlines styles onto conditional tables. If you’re going to use a different inliner then it may not do this, so be sure to add cellpadding="0" cellspacing="0" border="0" to your conditional Outlook tables.

Inside our conditional table, you’ll see that we have a <table class="outer"> which is our key outer building block for every client except Outlook.

We want this outer table to be 100% wide on small screens but on larger screens we only want it to be a maximum of 600px wide. Therefore we’re going to set its width to 100% and give it a max-width of 600px.

Our table is set to be 100% wide until it reaches a maximum of 600px

Handy tip: For a quick and easy buffer on mobile, without having to fiddle around with padding or media queries, change the width of your table from 100% to 95%.

So let’s paste these styles into our styles.css file:

We also have Margin: 0 auto; set here to center our table in Yahoo in Chrome. Though this use of margin is for Yahoo’s sake, I always capitalise Margin so that won’t strip it out–a neat little hack thanks to Wiktor’s comment on this blog post.

Now we have our outer structure, it’s time to start adding some content.

4. Adding a Full-width Banner Image

First, download the tutorial files and move the /images directory so that it’s in the same folder as your index.html file.

Now let’s add a class of full-width-image to the td inside our .outer table and then we’ll replace our [content goes here] placeholder with an image tag, so that the entire table now looks like this:

You’ll notice I haven’t bothered putting any width or height attributes on the image. I’m going to handle this all in the CSS that we are going to add, which looks like this:

This brings us to an extremely important point regarding images when using this method.

Images must always appear at their physical pixel size

This method is all about using percentages to keep things nice and fluid. Therefore, we almost always want the width of our images to be set to 100% of their container. If we want to do this, we have to insert our images at the correct physical pixel size. This is because Outlook 2007, 2010 and 2013 will not scale images up or down from their physical dimensions unless you set an explicit pixel width on the image. If you were to place a 1200px wide image in a 600px wide cell and set its width to 100%, Outlook would display that image at 1200px wide. Therefore if you have a 600px wide cell (on desktop), you need to use a 600px wide image.

For images that are smaller than your minimum supported screen width, you could set an explicit pixel width on these (for example, 100px) and use high-resolution images, because in non-media-query apps their width is always going to be 100px, which fits neatly inside any mobile viewport. If you had a 350px wide column though, you could not set the image to be 350px wide, because if you were to view that image in the Gmail app on a 320px wide viewport, it would be too wide.

Often it’s useful to ensure all images have their width set to 100%, even if they are narrower than the smallest mobile viewport, because it gives you more flexibility when adding progressive enhancement with media queries.

My rule of thumb is that any image should always appear at its physical pixel size unless it’s an icon smaller than 100px wide.

So with all that in mind, we’ve saved out an image called header.jpg that is exactly 600px wide and placed it in our images directory. Grab it, or save your own, and now you can preview your HTML file and see how the image fluidly resizes based on the size of the viewport.

5. Adding a Single Column Layout

Add another row to the .outer table with this markup:

And add this styling to your CSS file:

You’ll notice that I’ve used the <p> tag and a set of classes for styling them. I like using paragraphs to style text, and you can actually manage them really easily because of the capital-M Margin hack that I mentioned earlier. I also use <p class="h1"> instead of <h1> because has some h1, h2 and h3 styles that always override your styling.

So in the CSS above we’ve set up 10px padding for our column, we’ve reset all the margins on <p>, set some basic styles for links and my .h1 and .h2 classes, then ensured the contents of our column are left-aligned with styled paragraphs.

Now onto the exciting stuff.. multiple columns!

6. Adding a Two-column Layout*

*which will be centered when stacked.

We are going to create a two-column layout on desktop that stacks to a single, centered column on mobile

First add this new row to the .outer table. It contains a cell with the class .two-column and, inside that, a conditional table for Outlook with two 50% wide columns:

These conditional columns are important, because without them Outlook will not let our two floating tables sit neatly side-by-side. As Outlook doesn’t support max-width either, these columns help restrict each column to the correct size.

Visualising what our two-column structure will look like

Now replace each of the [column to go here] placeholders with this:

The way we are going to get two columns to float side by side on desktop, but stack in the centre on mobile, is by using a combination of text-align: center and display: inline-block. All inline and inline-block elements obey the text-align property. Therefore, if we wrap our tables in a div that is set to inline-block, we can very easily set their alignment when they stack by setting the text-align property on their container. You can choose from left, center or right text alignment, and your inline-block divs will obey. You can indeed simply set the table itself to be display: inline-block, but only if you aren’t going to be nesting any more tables inside. Things can start behaving weirdly if you nest tables inside inline-block tables, so if you need to nest, always ensure the inline-block container is a div.

Let’s style our container cell .two-column with our chosen alignment. We’re also going to add font-size: 0 to get rid of any gaps between our columns inside this cell.

Now we’ll style our inline-block div which acts as our column:

We’re using a width of 100% up to a max-width of 300px so that this particular column will be 100% wide on viewports that are smaller than 300px wide.

You can set your vertical-align to whatever you like: top, center or bottom. Setting vertical-align to top means that each column acts as though it is a table cell using the HTML property valign="top", while setting it to middle is as though it has valign="middle". Note that you can have many rows of these divs within the same cell and the vertical alignment will always dictate the vertical alignment on a row-by-row basis. It’s pretty nifty! Also ensure that whatever you choose here matches the valign that you’ve set on your Outlook conditional table because Outlook doesn’t support vertical-align. If you’re having a mismatch with alignment in Outlook, forgetting to set the valign on the conditional tables is usually the culprit.

Next we’ll add a table with two rows to each column. This is so that when everything stacks on mobile, each image has its corresponding text directly underneath.

So let’s replace our two [content goes here] placeholders with the following:

Our image here is 280px wide. As discussed above, it has been saved out at exactly the right pixel dimensions to fit the cell into which we’re placing it. Each column is 300px wide with 10px of padding on either side, leaving 280px for our image.

Next we’ll style the .contents class by giving it a width of 100%:

And then let’s add our styling under the two-column layout to set our font size and text-alignment, ensure our images display at 100% wide, and to give our text underneath a little bit of padding:

Now you should have a two-column layout, which stacks vertically when you resize your browser and shrinks as appropriate when you make the viewport narrower than 300px.

7. Adding a Three-column Layout

Again we are going to create side-by-side columns that stack on mobile by using the combination of text-align: center and display: inline-block.

We are going to be using text-align: center so that our column stacks in the center, but you can also always use left or right text alignment. Here is an example of how center and left-aligned elements will stack:

Example of how three columns will stack, using text-align: center on container
Example of how three columns will stack, using text-align: left on container

So we’ll repeat the two-column process with an additional column. Add this new row to the .outer table. (Usually I prefer to use percentage widths for the cells in my conditional Outlook tables, but in this case it’s easier to set the width of each to 200.)

Now add the following CSS to give some additional padding to this row, as well as set up all the properties we used in the two-column layout to make our columns behave how we want them to. It will also set up our styles for the div columns that we are about to add, which will be 200px wide in this case.

Let’s now insert our columns by replacing the [column to go here] placeholders with one table each:

And that’s it! Now you should have a three-column layout, where the columns will stack on narrower viewports. 

Owing to the fact that this layout has an uneven number of columns, sometimes you can find yourself with two columns displaying on the top row, with only one column beneath. While I think you can really make this look great if you design for this scenario, it can sometimes look a little unbalanced. Often the best way to get around this is to either use left alignment, or use multiple rows of three columns so that when the content stacks on mid-sized resolutions there are still an even number of columns per row.

Adding a three-column layout with multiple rows

When you want to add more rows in your multi-column layouts, you can add as many inline-block elements to a single container cell as you like. This way, when the viewport becomes too narrow to fit all of the columns, they simply reflow to fit the space available.

While you don’t need to separate the rows of divs for most clients, you do need to add additional <tr>s to your conditional table for Outlook.

This is how our conditional table works in Outlook to keep our rows and columns separate

Let’s try this out by starting a new row in our .outer table with the class of .three-column. Here we have a new three-column row with a conditional table inside. You’ll see that there are three columns in our conditional table and then we end the conditional table’s row with </tr> and open a new <tr>, which contains another three 200px wide cells.

Next we’ll add a table like this to each conditional cell, replacing the [column to go here] placeholder:

Now if you resize your window, you’ll again see that the columns stack to fill the available space. Three columns will reduce to two-columns with three rows, until they collapse finally to a single column with six rows.

Adding even more columns

We won’t add any more multi-column layouts in this tutorial, but you are free to have as many columns in a layout as you wish. All you need to do is ensure that your content blocks all add up to the width of your container, and that your conditional table for Outlook has the correct number of cells and rows to contain them.

8. Adding a Two-column ‘Sidebar’ Layout

Next we’ll create a two column layout with a 500px wide column and then a narrower 100px wide sidebar for an icon.

Firstly we’ll add a row and cell with the class of .left-sidebar and inside that we’ll pop our conditional table for Outlook which has a single row and two uneven columns:

Then in each column, replacing the [column to go here] placeholder, we’ll add a table. This time we will call one .column .left and one .column .right because they have different widths.

Note: here I’m using multiple classes on a single element. Some inliner tools and/or ESPs may not support doing this, so check with your system or platform first. As mentioned above, I use to inline my CSS, which does support multiple classes.

In the first column, add the left-hand table which contains our icon:

As these images are so tiny and we always want them to appear at the same size, it’s safe to give them a pixel width.

Then in the second column, add the right-hand table with the text and link:

These tables are super-simple with nothing nested inside, so to save on markup I’m going to set the tables themselves to display: inline-block rather than wrapping them in a div. As discussed above, this is only practical when you aren’t going to be nesting any more elements inside. If you will be doing lots of nesting, wrap this table in a div, and put the .column .right class on that.

Next let’s style the container and set up the columns:

And finally let’s set up some text styling and a link colour:

Now you should have your left sidebar layout and when you resize your browser to make it smaller, the icon will jump above the text and sit in the centre.

9. Adding a Reversed ‘Sidebar’ Layout

Now we want to duplicate our sidebar layout, and this time we want the icon to be on the right-hand side to create some visual interest on desktop. But on mobile we want the content to stack in exactly the same order as our previous sidebar layout, so that the icon is on top of the text.

Firstly, we’re going to copy and paste the entire row with our .left-sidebar cell, and the only thing we are going to change is the class of the container cell from .left-sidebar to .right-sidebar:

Absolutely everything else is exactly the same.

What we’re going to do is use dir="rtl" (meaning direction is right-to-left) to our advantage. This property is for denoting alphabets that run right-to-left, such as Arabic. But in our case it’s simply going to tell each email client to render our elements in the opposite order.

Our elements will stack in the opposite order if dir="rtl" is set on their container

First, to the container (.right-sidebar), you need to add dir="rtl". This is telling it to render our floating tables inside from right to left. So our opening tag should now look like this:

Then, in the Outlook conditional code, we also need to add dir="rtl" to the <table> because we are telling the table to render the <td>s in the opposite order.

So our opening conditional comment should now look like this:

And finally, we need to add dir="ltr" to our .column-left and .column-right tables, because they have the content inside them, and since that content is in English, it needs to run left-to-right. If we don’t set this on these elements, they’ll inherit the right-to-left direction from their parent elements. 

Our .column-left should now look like this:

And our .column-right should now look like this:

So to recap, our entire row should now look like this:

And finally, let’s add our styling, which is all exactly the same as for our .left-sidebar, except for the link colour:

There we go! So now we have two sidebars on opposite sides, but when everything stacks on mobile both sidebars appear above the text.

10. Adding Progressive Enhancement with Media Queries

Now you have a complete email template that is responsive everywhere without a single media query in sight! But of course there are quite a few email clients that do indeed support media queries, so now we can go about progressively enhancing our already fabulous template with a few tweaks to make everything look beautiful in a client like iOS Mail.

Firstly, we’ll make all of our columns appear at 100% the width of the viewport for anything up to 400px. We’ll also limit our three-column images to 50% wide so that they don’t blow up too large. All we have to do is reset the max-width of these columns because, as you’ll recall, they all already have a width of 100% and it’s just the max-width that is restricting them.

So add this to your CSS file:

Then, between 401px and 600px wide, we’ll add the following to make the two- and three-column layouts appear as they would on desktop, but shrunk down to fit.

These are fairly arbitrary adjustments to demonstrate what’s possible—you can fiddle and play around with this as much as you like to achieve your desired outcome across a whole range of device sizes that support media queries.

11. Inlining Your Code

Finally, if you need to inline your code, take the contents of style.css and paste it into the<head> of your index.html document between the <style type="text/css"></style> tags. Then copy and paste the entire file into the box at and wait for the results. Once processed, copy the contents of the box out and you’re ready to go!

And There You Have it!

Well done! We now have a fully-functioning responsive HTML email using fewer than twenty lines of media queries.

A few final notes and tips

  • I have found with this method of email development that simplicity and uniformity is key. Things start to get out of hand when you have different padding on different columns. For this tutorial you’ll notice that I’ve kept padding uniform at 10px on the .inner class which applies to every single layout. This is important because when everything stacks on mobile you want the padding to be uniform.
Always have the same amount of padding on the left and right sides of your elements so that padding is uniform on mobile in clients with no media query support
  • Sometimes you may need to calculate outwards to establish what the outer width of your layout is going to be, based on what your best uniform padding value is, rather than deciding on the outer width and then working your way inwards.
  • It’s often a good idea to design in the browser with this method, since often it can be quite a challenge to retrofit certain designs to work with this approach.
  • When using this method it’s quite safe to start designing emails that are a lot wider than usual because you know the layout is going to rearrange itself to fit smaller viewports, even in webmail. The only sticking point is Outlook, which still requires those conditional tables so that everything will look right, and therefore Outlook users are always going to see the entire email at its widest. Even though you still need to bear this lowest common denominator in mind, there’s definitely some room to move beyond the usual 550-600px restriction that we usually place on email.
  • And finally, always ensure that you are inserting images at their physical pixel size. A good way to ensure that you’re always doing this is to code your layout first, then use the inspector on your browser tools to check how big the final space actually is. You can then ensure your image is created to those exact dimensions. Remember to check this again at the end just to make sure everything is right. If you don’t do this, Outlook will kindly show the error of your ways because it’s going to display every single image at its physical dimensions.

The icons

Thanks again go to Pierre Borodin for all the icons used in my tutorials.