Screens on modern smartphones, tablets, and even more so laptops and computers, are wide. But if we look at emails, they're all sent at a very modest width — 600 pixels. What's stopping us from making them stretch the full width of the screen? Two reasons.

First, history. Emails as we know them appeared in the mid-1990s, when the maximum screen width was quite small — 1024 pixels. A width of 600 pixels suited them perfectly, so nobody rushed to adapt it for wider screens.

Second, math. 600 pixels divides nicely by 1, 2, 3, and 4. That matters if we're going to split the email into columns — then each one gets an equal number of pixels. Which brings us to column-based coding.

Column-based email coding

What does coding an email actually involve? As we already mentioned, emails are coded using tables [this guarantees the email won't fall apart across different clients]. So, essentially, coding a campaign is a set of tables nested inside other tables. Let's confirm this:

We peeked into this email's code and changed all the zero border values to 1. Now the email looks like this:

In the example, you can see a two-column layout is used, but you can just as easily split an email into three or four columns. There are two ways to arrange multiple columns in email coding: with stacking and without.

Two columns without stacking

To build a two-column grid, we need an outer table. Accordingly, with two cells [columns]:

<table width=»100%» border=»0″ cellspacing=»0″ cellpadding=»0″>

<tr>

<td align=»left» valign=»top»>

</td>

<td align=»left» valign=»top»>

</td>

</tr>

</table>

Now let's add equal padding to both cells:

<table width=»100%» border=»0″ cellspacing=»0″ cellpadding=»0″>

<tr>

<td align=»left» valign=»top»>

<div style=»height: 30px; line-height:30px; font-size:28px;»>&nbsp;</div>

</td>

<td align=»left» valign=»top»>

<div style=»height: 30px; line-height:30px; font-size:28px;»>&nbsp;</div>

</td>

</tr>

</table>

And if we change the border value from 0 to 1, we get this:



If a cell size isn't specified in <td>, cells split their share of the content proportionally. As an example, let's take the same table, but add links instead of padding:

<table width=»100%» border=»1″ cellspacing=»0″ cellpadding=»0″>

<tr>

<td align=»left» valign=»top»>

<div style=»line-height:16px;»>

<a href=»#» target=»_blank» style=»font-family: Tahoma, Arial, Helvetica, sans-serif; font-size: 14px; color: #000000;text-decoration:none;»>

Web version

</a>

</div>

</td>

<td align=»right» valign=»top»>

<div style=»line-height:16px;»>

<a href=»#» target=»_blank» style=»font-family: Tahoma, Arial, Helvetica, sans-serif; font-size: 14px; color: #000000;text-decoration:none;»>

Unsubscribe

</a>

</div>

</td>

</tr>

</table>

We aligned the second cell's text to the right [align=»right»] and got this result:

Web version

Unsubscribe

And if it's responsive, as the screen narrows, these two cells will move evenly toward each other:

Web version

Unsubscribe

Three columns without stacking

Now let's look at another example — this time with three columns. It's mostly the same:

<table width=»100%» border=»1″ cellspacing=»0″ cellpadding=»0″>

<tr>

<td align=»center» valign=»top»>

<div style=»line-height:16px;»>

<a href=»#» target=»_blank» style=»font-family: Tahoma, Arial, Helvetica, sans-serif; font-size: 14px; color: #000000;text-decoration:none;»>

Unsubscribe

</a>

</div>

</td>

<td align=»center» valign=»top»>

<div style=»line-height:16px;»>

<a href=»#» target=»_blank» style=»font-family: Tahoma, Arial, Helvetica, sans-serif; font-size: 14px; color: #000000;text-decoration:none;»>

Web version

</a>

</div>

</td>

<td align=»center» valign=»top»>

<div style=»line-height:16px;»>

<a href=»#» target=»_blank» style=»font-family: Tahoma, Arial, Helvetica, sans-serif; font-size: 14px; color: #000000;text-decoration:none;»>

2026 Company

</a>

</div>

</td>

</tr>

</table>

This code will render like this:

Unsubscribe

Web version

2026 Company

Note: no cell sizes are set here, so they split proportionally [in the "2026 Company" line there are 3 more characters than in the others]. To change the sizes, you need to set the <td> tag's width as a percentage [or a pixel size, but with responsive layouts, an exact value can break the layout since blocks will "hit" that fixed size]:

<table width=»100%» border=»1″ cellspacing=»0″ cellpadding=»0″>

<tr><td align=»center» valign=»top» width=»20%»>

<div style=»line-height:16px;»>

<a href=»#» target=»_blank» style=»font-family: Tahoma, Arial, Helvetica, sans-serif; font-size: 14px; color: #000000;text-decoration:none;»>

Unsubscribe

</a>

</div>

</td><td align=»center» valign=»top» width=»20%»>

<div style=»line-height:16px;»>

<a href=»#» target=»_blank» style=»font-family: Tahoma, Arial, Helvetica, sans-serif; font-size: 14px; color: #000000;text-decoration:none;»>

Web version

</a>

</div>

</td><td align=»center» valign=»top» width=»60%»>

<div style=»line-height:16px;»>

<a href=»#» target=»_blank» style=»font-family: Tahoma, Arial, Helvetica, sans-serif; font-size: 14px; color: #000000;text-decoration:none;»>

2026 Company

</a>

</div>

</td></tr>

</table>

Thanks to this, our table now looks like this:

Unsubscribe

Web version

2026 Company

This way you can also build tables with four, five, or six columns of content. In cases like these, it's important to make sure the cells don't overlap each other as the screen narrows.

Now you know how to code blocks in an email that won't stack. This format is used, for example, with lists:

Here's what the same table looks like if you set the border value to 1:

And as the screen narrows on mobile, the blocks stay in place without stacking at all, as long as the left cell's size is set rigidly in pixels:

This method is also often used for footers with social icons. Like these:

Here we see six icons, which means our table will have six cells:

<table width=»100%» border=»1″ cellspacing=»0″ cellpadding=»0″>

<tr><td align=»left» valign=»top»>

<a href=»#» target=»_blank» style=»color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 16px;»>

<img src=»ig.png» width=»40″ height=»40″ alt=»Instagram» border=»0″ style=»display: block;»/>

</a>

</td><td align=»left» valign=»top»>

<a href=»#» target=»_blank» style=»color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 16px;»>

<img src=»fb.png» width=»40″ height=»40″ alt=»Facebook» border=»0″ style=»display: block;»/>

</a>

</td><td align=»left» valign=»top»>

<a href=»#» target=»_blank» style=»color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 16px;»>

<img src=»vk.png» width=»40″ height=»40″ alt=»VKontakte» border=»0″ style=»display: block;»/>

</a>

</td><td align=»left» valign=»top»>

<a href=»#» target=»_blank» style=»color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 16px;»>

<img src=»yt.png» width=»40″ height=»40″ alt=»YouTube» border=»0″ style=»display: block;»/>

</a>

</td><td align=»left» valign=»top»>

<a href=»#» target=»_blank» style=»color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 16px;»>

<img src=»ok.png» width=»200″ height=»100″ alt=»Odnoklassniki» border=»0″ style=»display: block;»/>

</a>

</td><td align=»left» valign=»top»>

<a href=»#» target=»_blank» style=»color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 16px;»>

<img src=»tt.png» width=»200″ height=»100″ alt=»TikTok» border=»0″ style=»display: block;»/>

</a>

</td></tr>

</table>

Remember how in this case the cells split proportionally? Right now our table looks like this:

But let's take a look at the same layout in Figma:

The total distance from the first icon to the last is 365px [that's the total table width], the images themselves are 40x40, and the gap between them is 31px. That means each cell will be 71px [40+31]. We add this value to the width attribute on every cell except the last one:

<table width=»365″ border=»0″ cellspacing=»0″ cellpadding=»0″>

<tr><td align=»left» valign=»top» width=»71″>

<a href=»#» target=»_blank» style=»color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 16px;»>

<img src=»ig.png» width=»40″ height=»40″ alt=»Instagram» border=»0″ style=»display: block;»/>

</a>

</td><td align=»left» valign=»top» width=»71″>

<a href=»#» target=»_blank» style=»color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 16px;»>

<img src=»fb.png» width=»40″ height=»40″ alt=»Facebook» border=»0″ style=»display: block;»/>

</a>

</td><td align=»left» valign=»top» width=»71″>

<a href=»#» target=»_blank» style=»color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 16px;»>

<img src=»vk.png» width=»40″ height=»40″ alt=»VKontakte» border=»0″ style=»display: block;»/>

</a>

</td><td align=»left» valign=»top» width=»71″>

<a href=»#» target=»_blank» style=»color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 16px;»>

<img src=»yt.png» width=»40″ height=»40″ alt=»YouTube» border=»0″ style=»display: block;»/>

</a>

</td><td align=»left» valign=»top» width=»71″>

<a href=»#» target=»_blank» style=»color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 16px;»>

<img src=»ok.png» width=»40″ height=»40″ alt=»Odnoklassniki» border=»0″ style=»display: block;»/>

</a>

</td><td align=»left» valign=»top»>

<a href=»#» target=»_blank» style=»color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 16px;»>

<img src=»tt.png» width=»40″ height=»40″ alt=»TikTok» border=»0″ style=»display: block;»/>

</a>

</td></tr>

</table>

Now our table looks the way it should:

There's also another way — you can position the images using percentages instead. Then the code looks like this:

<table width=»100%» border=»0″ cellspacing=»0″ cellpadding=»0″ style=»max-width: 396px;»>

<tr><td align=»center» valign=»top» width=»16%»>

<a href=»#» target=»_blank» style=»color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 16px;»>

<img src=»ig.png» width=»40″ height=»40″ alt=»Instagram» border=»0″ style=»display: block;»/>

</a>

</td><td align=»center» valign=»top» width=»17%»>

<a href=»#» target=»_blank» style=»color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 16px;»>

<img src=»fb.png» width=»40″ height=»40″ alt=»Facebook» border=»0″ style=»display: block;»/>

</a>

</td><td align=»center» valign=»top» width=»17%»>

<a href=»#» target=»_blank» style=»color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 16px;»>

<img src=»vk.png» width=»40″ height=»40″ alt=»VKontakte» border=»0″ style=»display: block;»/>

</a>

</td><td align=»center» valign=»top» width=»17%»>

<a href=»#» target=»_blank» style=»color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 16px;»>

<img src=»yt.png» width=»40″ height=»40″ alt=»YouTube» border=»0″ style=»display: block;»/>

</a>

</td><td align=»center» valign=»top» width=»17%»>

<a href=»#» target=»_blank» style=»color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 16px;»>

<img src=»ok.png» width=»40″ height=»40″ alt=»Odnoklassniki» border=»0″ style=»display: block;»/>

</a>

</td><td align=»center» valign=»top» width=»16%»>

<a href=»#» target=»_blank» style=»color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 16px;»>

<img src=»tt.png» width=»40″ height=»40″ alt=»TikTok» border=»0″ style=»display: block;»/>

</a>

</td></tr>

</table>

What changed? We added the gap between icons [31px] to the table's total width [365px], so the max-width value became 396. There are 6 icons in total, and as a percentage each cell takes up about 16–17% of the table [100%/6 ≈ 16.7, but fractional sizes don't work in emails. You can specify either 16% or 17% here — the compiler will sort everything out on its own]. Next, we center-align the content of the cells [align=»center»], and voilà! We get the same result:

Well, almost the same. There's one important difference: when we set an exact pixel distance, the table's total width should be no more than 320px [the smallest phone screen size], otherwise the cells will "hit a wall" and the layout will break. That's why we favor the second option, using percentages.

Stacking blocks

Sometimes the email layout has already been approved by the client, but during coding you have to remove certain elements. Why does this happen? Because at the design stage, nobody thought about how a given element would adapt for the mobile version.

In that situation, the only option is to code the complex block as an image. But we usually code emails with actual markup: if a whole campaign consists of images, email providers might flag it as spam. On top of that, images on mobile devices shrink proportionally to the screen width, which can strain readers' eyes. Here's how that looks:

With responsive coding, on the other hand, the email's elements on a mobile screen simply stack on top of each other:

Let's break down how this works.

Two stacking blocks

Essentially, two stacking blocks are two <div> blocks with the display property set to inline-block. As a reminder: this makes the element render as an inline block.

Inline blocks take up the full width assigned to their container. So if the email's width is 600px, two identical containers would each be 300px. Here's a code example:

<table width=»100%» border=»0″ cellspacing=»0″ cellpadding=»0″>

<tr><td align=»center» valign=»top» style=»font-size: 0px;»><!—

Item —><div style=»display: inline-block;vertical-align:top;width:300px;»>

<table width=»100%» border=»0″ cellspacing=»0″ cellpadding=»0″ style=»border-collapse:collapse;»>

<tr><td align=»center» valign=»middle» style=»font-size: 14px;»>

<table width=»100%» border=»0″ cellspacing=»0″ cellpadding=»0″ >

<tr><td align=»center» valign=»top»>

content

</td></tr>

</table>

</td></tr>

</table></div><!— Item END—><!—[if (gte mso 9)|(IE)]>

</td>

<td valign=»top» style=»width: 300px;»>

<![endif]—><!—

Item —><div style=»display: inline-block;vertical-align:top;width:300px;»>

<table width=»100%» border=»0″ cellspacing=»0″ cellpadding=»0″ style=»border-collapse:collapse;»>

<tr><td align=»center» valign=»middle» style=»font-size: 14px;»>

<table width=»100%» border=»0″ cellspacing=»0″ cellpadding=»0″ >

<tr><td align=»center» valign=»top»>

content

</td></tr>

</table>

</td></tr>

</table></div><!— Item END—>

</td></tr>

</table>

Now let's break down what's going on here. Two <div> tags with inline properties create two cells — they stay on one row as long as their combined width equals 600px.

To be sure no stray characters slip into our markup, we add style=»font-size: 0px;» to the outer table. This "safety net" zeroes out the size of any extraneous elements. This ensures the parent container's total width doesn't accidentally pick up extra characters with their own dimensions.

Next, we set the style attribute for the first block with the display, vertical-align, and width properties. The first value [inline-block] means the block will behave like both a block-level and inline element. The second value [top] aligns the block's content to the top of the page. And the block's width [width:300px] is self-explanatory :)

Inside is a table with the collapse value on the border-collapse property, which overrides the cellspacing attribute's value. After that comes a standard table, but now we effectively turn off our "safety net" and set the cell's size [style=»font-size: 14px;»]. The first block's code is closed off with a conditional comment for Outlook. In fact, it doesn't need stacking at all, since it's a desktop client. But without the comment, it wouldn't see the closing </td> tag in the first container.

The second block is almost identical, just with a conditional comment for Outlook.

As a result, our table looks like this:

And if the screen narrows even one pixel below 600px, the blocks stack:

If we need to set different widths for the cells, here's how we do it:

<table width=»100%» border=»0″ cellspacing=»0″ cellpadding=»0″>

<tr><td align=»center» valign=»top» style=»font-size: 0px;»><!—

Item —><div style=»display: inline-block;vertical-align:top;max-width:400px;width=100%»>

<table width=»100%» border=»0″ cellspacing=»0″ cellpadding=»0″ style=»border-collapse:collapse;»>

<tr><td align=»center» valign=»middle» style=»font-size: 14px;»>

<table width=»100%» border=»0″ cellspacing=»0″ cellpadding=»0″ >

<tr><td align=»center» valign=»top»>

content

</td></tr>

</table>

</td></tr>

</table></div><!— Item END—><!—[if (gte mso 9)|(IE)]>

</td>

<td valign=»top» style=»width: 200px;»>

<![endif]—><!—

Item —><div style=»display: inline-block;vertical-align:top; width:200px»>

<table width=»100%» border=»0″ cellspacing=»0″ cellpadding=»0″ style=»border-collapse:collapse;»>

<tr><td align=»center» valign=»middle» style=»font-size: 14px;»>

<table width=»100%» border=»0″ cellspacing=»0″ cellpadding=»0″ >

<tr><td align=»center» valign=»top»>

content

</td></tr>

</table>

</td></tr>

</table></div><!— Item END—>

</td></tr>

</table>

Here width became max-width because the size grew past 300px: if we set the width rigidly, the screen would "hit a wall" at 400px. Now our table looks like this:

And when it stacks, like this:

The same goes for banners. A banner's content is often split into two sides: say, text on the left, an image on the right:

How would a banner like that adapt for a mobile device? It can look different ways: for example, the right column could "move" under the other one:

But it could also go the other way — text first, then the image below it. Which brings us to reverse block stacking.

Reverse block stacking

This kind of coding works roughly the same way, but with one caveat: the dir attribute. It sets the direction — left to right or right to left. It has two values:

  • ltr [literally Left To Right] — text displays as usual [left to right];
  • rtl [Right To Left] — text is inverted and displays right to left.

The code would look like this:

<table border=»0″ cellspacing=»0″ cellpadding=»0″ width=»100%»>

<tr><td dir=»rtl» align=»center» style=»font-size: 0px;»><!—[if (gte mso 9)|(IE)]>

<table border=»0″ cellspacing=»0″ cellpadding=»0″ width=»100%»>

<tr><td width=»300″ style=»width: 300px;» dir=»rtl»>

<![endif]—><!—

Item —><div style=»display: inline-block; vertical-align: top; width: 300px;»>

<table width=»100%» cellpadding=»0″ cellspacing=»0″ border=»0″ dir=»ltr»>

<tr><td align=»center» style=»font-size: 14px;»>

Block 2

</td></tr>

</table>

</div><!— Item END—><!—[if (gte mso 9)|(IE)]>

</td><td width=»300″ style=»width: 300px;»>

<![endif]—><!—

Item —><div style=»display: inline-block; vertical-align: top; width: 300px;»>

<table width=»100%» border=»0″ cellspacing=»0″ cellpadding=»0″ dir=»ltr»>

<tr><td align=»center» style=»font-size: 14px;»>

Block 1

</td></tr>

</table>

</div><!—[if (gte mso 9)|(IE)]>

</td></tr>

</table>

<![endif]—></td>

</tr>

</table>

On a large screen, this code renders like this:

And on mobile, like this:

Essentially, it's the same two <div> tags, but they'll be read in reverse order. Plus, there's now a conditional comment for Outlook so it picks up the specified direction.

Now you know why it's better to use a modular grid when building an email layout — this structure works great for adapting an email to mobile devices. We'll cover that in the next lesson.


📱 You no longer need to test responsiveness by hand. Letteros has built-in testing across 9 email clients.