top of page

How to Implement Semantic Email Code

  • Writer: Diana Buda
    Diana Buda
  • Aug 17
  • 4 min read

Miniature figures paint near a green icon with code brackets on a white surface. Playful and creative scene.

When I first started coding emails, I used <tr> and <td> for everything, even paragraphs of text. It worked, but left my templates bloated with unnecessary tables and rows.


As I learned more about accessibility and email rendering, I realised that my approach wasn’t helping anyone. Beyond accessibility issues, this approach also slowed development time.


When handing over templates this bloated code was creating huge potentials for error. That’s when I started looking into two improvements:


  1. Reducing overall tables in my email templates (while still staying bulletproof for rendering).

  2. Introducing semantic HTML code wherever possible.


Semantic HTML means using tags that describe the type of content they contain. For example using <p> for paragraphs, <h1> for main headings, and <ul> for lists. In websites, it’s standard practice. In email, it’s trickier, but with the right approach, it’s worth the effort.


This guide will walk you through how I implement semantic code in my emails, based on my own experience and the ESPs I’ve worked with. There’s no one-size-fits-all here, but this is what works for me.



Why Use Semantic Code in Emails?

Highlighted "html" tag in yellow on printed HTML code, surrounded by tags like "head" and "http." Close-up, black text on white paper.

  1. Accessibility: Screen readers can navigate content more effectively when it’s marked up with proper headings, paragraphs, and lists.

  2. Cleaner Code: Easier to maintain and update without hunting through endless <td> cells.

  3. Consistent Rendering: Reduces the risk of weird spacing or alignment issues when you make updates.



Making Semantic Code Work in Email

Green envelope with white paper plane on a purple background. The envelope is centered, creating a vibrant, playful mood.

So what does semantic code actually look like in an email? Below I’ll walk you through the three building blocks I use most often—paragraphs, headings, and lists. Each needs a little extra care compared to coding for the web, but once you understand the patterns, it’s straightforward to implement and worth the effort for cleaner, more accessible emails.


How to code paragraphs

Using a plain <p> tag isn’t enough for email. Spacing often breaks, especially in Outlook. That’s why you need inline styles.

<p style="Margin:0; Margin-bottom:16px; font-family: Arial, sans-serif; font-size: 16px; line-height: 24px; color: #000000;">
	This is a paragraph inside a <p> tag. The inline styles help control spacing and appearance across different email clients.
</p>

Tips:

  • Reset Margin and padding to avoid inconsistent spacing.

  • Outlook 2007 and 2010 ignore padding on paragraphs. Use Margin instead (with a capital “M”).

  • Define font size, line height, font family, and colour globally in your email’s <head> block.

    • Make sure your paragraphs sit inside Outlook- and Gmail-friendly structures, such as ghost tables, <div>s, or an overall <table> wrapper.

    • To doubly ensure consistency, or to specify values just for specifc paragraphs you can also specify them inline as in the example above

  • Test across Outlook, Gmail, and Apple Mail to catch differences.


Note:

Note: For accessibility, it’s best practice to use em for font sizes. In my experience, not all ESPs render this consistently, so I often stick to pixels.


How to code headings

Headings make your structure clear and improve accessibility. Use <h1> through <h6> with inline styles.

<h1 style="Margin:0; font-family: Arial, sans-serif; font-size: 24px; line-height: 32px; font-weight: bold; color: #000000;">  
	Main Email Heading
</h1>
<h2 style="Margin:0; font-family: Arial, sans-serif; font-size: 20px; line-height: 28px; font-weight: bold; color: #000000;">
  Subheading Example
</h2>

Tips:

  • Stick to one <h1> per email for accessibility.

  • Use <h2> or <h3> for subheadings to break up sections.


How to code lists

Lists are great for breaking down information, but they need careful styling to look consistent across clients.


You can use <ul> or <ol> tags in your email, coded like below:

<ul style="Margin: 0 0 0 40px; padding: 0">
  <li style="Margin: 0 40px 20px 40px; font-size: 16px; line-height: 25px; color: #333333;" class="margin-copy">bullet item 1</li> 
  <li style="Margin: 0 40px 20px 40px; font-size: 16px; line-height: 25px; color: #333333;" class="margin-copy">bullet item 2</li>
</ul>

Tips:

  • As with paragraphs, you’ll need to reset Margin and padding manually.

  • Add padding-left or Margin for alignment.

  • Keep list styling inline for reliable rendering.


Bonus: Styling List Numbers or Bullets

You can change bullet or number colours with inline styling:

  • Code an <ul> or <ol> element as described above

  • Add the bullet colour as an inline style in the <li> element.

  • Add in your text within a <span> tag that has inline style defining the colour of the text or any other styles you need to specify

<ol style="Margin: 0 0 0 40px;padding: 0">
  <li style="Margin: 0 40px 20px 40px; font-size: 16px; line-height: 25px; color: #f7567c;" ><span style="color:#333333">numbered item 1</span></li>
  <li style="Margin: 0 40px 20px 40px; font-size: 16px; line-height: 25px; color: #f7567c;" class="margin-copy"><span style="color:#333333">numbered item 2<span></li>
</ol>

For custom bullets, tables are sometimes unavoidable:

<table width="100%"  cellpadding="0" cellspacing="0" style="width: 100%; mso-cellspacing: 0; mso-padding-alt: 0;" role="presentation">
  <tr>
    <td align="center" style="padding: 0 40px 0 60px; font-size: 16px; line-height: 25px; font-family: Arial, sans-serif; color: #333333;">
	<table width="100%"  cellpadding="0" cellspacing="0" style="width: 100%; mso-cellspacing: 0; mso-padding-alt: 0;" role="presentation">
        <tr>
          <td width="20" valign="top" style="font-family:Arial sans-serif;font-size:20px;color:#9381FF;" class="no-pad"><p style="Margin: 0 0 20px 0; font-size: 20px; line-height: 25px; color: #9381FF;">✓</p></td>
          <td  valign="top" style="font-family:Arial, sans-serif;font-size:14px;color:#333333;" class="no-pad"><p style="Margin: 0 0 20px 10px; font-size: 16px; line-height: 25px; color: #333333;" class="margin-copy">custom bullet point (tick)</p></td>
        </tr>        
      </table>
     </td>
  </tr>

  • Use a 100% width table to hold the custom list, keeping it stable across email clients.

  • Each bullet is made of a two-cell row:

    • Left cell: contains the bullet character (in this case a tick ✓), styled with its own colour, size, and spacing.

    • Right cell: contains the text, aligned neatly next to the tick, with its own font styling.

  • Inline styles control spacing, alignment, and colours, ensuring consistent rendering across Outlook, Gmail, and Apple Mail.

  • By using tables, you avoid the inconsistencies of <ul> or <ol> in emails, while still achieving a clean, styled list.

  • Easily customisable: swap ✓ for another symbol (e.g. ●, →, ✦) or even an image icon to fit your brand.


Final Thoughts

Dimly lit laptop on a table, screen almost closed. Keyboard casts a soft glow in a dark setting. Mysterious and quiet ambiance.

Semantic HTML won’t solve every email coding challenge, but it makes emails cleaner, more accessible, and easier to maintain.


Shifting from coding everything in <td> cells to using proper semantic tags made a big difference in my workflow.


Start small: switch one <td> paragraph to a <p>, add real headings, or clean up a list. Over time, your code will get leaner, your workflow faster, and your emails more robust.



Resources

bottom of page