Converting Markdown to HTML Email

May 28, 20266 min read

Writing email content in Markdown feels natural — it is fast, readable, and version-controllable. But email clients do not render Markdown, and they barely render modern HTML. Outlook uses Microsoft Word's rendering engine, Gmail strips <style> blocks, and mobile clients have their own quirks. Converting Markdown to email-ready HTML means embracing table layouts, inline styles, and a set of constraints that feel like coding for the early 2000s web.

Why Email HTML Is Different

Web browsers support Flexbox, CSS Grid, and external stylesheets. Email clients do not. The following table summarizes what you cannot rely on in email HTML:

FeatureGmailOutlookApple MailYahoo
<style> in <head>StripsSupportsSupportsStrips
<style> in <body>StripsStripsSupportsStrips
CSS GridNoNoPartialNo
FlexboxNoNoYesNo
border-radiusYesNoYesYes
External CSSNoNoYesNo

The practical consequence is that every visual property must be applied as an inline style attribute, and every layout must use <table> elements. This is not a suggestion — it is the only approach that works consistently across major email clients.

Converting Markdown Elements to Email HTML

Each Markdown construct maps to a specific HTML email pattern. Here is how the most common elements translate:

Headings become styled table cells:

<table width="100%" cellpadding="0" cellspacing="0" border="0">
  <tr>
    <td style="font-family:Arial,sans-serif; font-size:24px; font-weight:bold; color:#1a1a1a; padding-bottom:16px;">
      Monthly Update
    </td>
  </tr>
</table>

Paragraphs use explicit line-height and margin":

<p style="font-family:Arial,sans-serif; font-size:16px; line-height:24px; color:#333333; margin:0 0 16px 0;">
  Here is your monthly summary of project milestones and upcoming deadlines.
</p>

Lists must be explicitly styled because some clients reset list indentation:

<ul style="font-family:Arial,sans-serif; font-size:16px; color:#333333; padding-left:20px; margin:0 0 16px 0;">
  <li style="margin-bottom:8px;">Deployed authentication service v2.1</li>
  <li style="margin-bottom:8px;">Completed security audit for payment module</li>
  <li style="margin-bottom:8px;">Onboarded three new engineering contractors</li>
</ul>

Code blocks need monospace fonts and background colors inline:

<table width="100%" cellpadding="12" cellspacing="0" border="0" style="background-color:#f4f4f4; border-radius:4px;">
  <tr>
    <td style="font-family:'Courier New',monospace; font-size:14px; color:#333333;">
      npm run build --production
    </td>
  </tr>
</table>

Links should include both inline color styling and underline control, since some clients override link colors:

<a href="https://example.com" style="color:#0066cc; text-decoration:underline;">View full report</a>

Building a Conversion Pipeline

Manually converting Markdown to email HTML is tedious. A practical pipeline automates the heavy lifting:

  1. Parse Markdown to HTML using a library like marked, remark, or markdown-it
  2. Apply email-safe transformations — wrap blocks in tables, inline all styles
  3. Inline CSS using a tool like Juice or Premailer
  4. Test across email clients using Litmus or Email on Acid

Here is a Node.js script using marked and juice:

import { marked } from 'marked'
import juice from 'juice'
import fs from 'fs'

const markdown = fs.readFileSync('newsletter.md', 'utf-8')
const htmlBody = marked.parse(markdown)

const emailHtml = `
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"></head>
<body style="margin:0; padding:0; background-color:#f9f9f9;">
  <table width="100%" cellpadding="0" cellspacing="0" border="0">
    <tr>
      <td align="center" style="padding:32px 0;">
        <table width="600" cellpadding="0" cellspacing="0" border="0" style="background-color:#ffffff;">
          <tr><td style="padding:32px;">
            ${htmlBody}
          </td></tr>
        </table>
      </td>
    </tr>
  </table>
</body>
</html>`

const inlined = juice(emailHtml, { preserveMediaQueries: true })
fs.writeFileSync('newsletter.html', inlined)

The juice call is critical — it moves all CSS from <style> blocks into inline style attributes, which is the only reliable way to style emails across clients.

Common Pitfalls

  • Relative image paths will not work in emails. All images must use absolute URLs to hosted assets.
  • Web fonts are unsupported in most email clients. Use Arial, Georgia, Times New Roman, or Verdana as your font stack.
  • Background images do not work in Outlook. Use solid background colors instead.
  • Responsive design in email relies on @media queries in a <style> block, which Gmail strips. Use fluid-width tables with percentage widths as a fallback.

The gap between Markdown's simplicity and email HTML's complexity is significant, but a conversion pipeline closes it. Start by converting your Markdown to clean HTML with our tool at /tools/markdown-to-html, then apply email-specific transformations and inline styling before sending.