Email templates in Outlook, built in HTML

Outlook saves templates, but it does not design them. Build the design once as a small HTML file with tables and inline styles, then save it into Outlook as a template.

"Email templates in Outlook" means a saved email you can reuse, in the Outlook mail app. Outlook stores the template, but the design comes from somewhere else.

The most reliable source is a small HTML file built with tables and inline styles, because classic Outlook for Windows reads mail with a Word-based HTML engine rather than a browser engine.

Here is the smallest version that holds together. Edit the text and the example reruns.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Outlook-safe email template</title>
</head>
<body style="margin:0; padding:0; background-color:#eef1f5;">
<!-- Outer table: full width background -->
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0" bgcolor="#eef1f5">
  <tr>
    <td align="center" style="padding:20px 10px;">
      <!-- Inner table: the 600px email. width attribute, not max-width -->
      <table role="presentation" width="600" cellpadding="0" cellspacing="0" border="0" bgcolor="#ffffff" style="width:100%; max-width:600px;">
        <tr>
          <td bgcolor="#1f4e79" style="padding:18px 24px; font-family:Arial, sans-serif; font-size:20px; font-weight:bold; color:#ffffff;">
            Acme Studio
          </td>
        </tr>
        <tr>
          <td style="padding:24px; font-family:Arial, sans-serif; font-size:15px; line-height:150%; color:#1d2330;">
            <p style="margin:0 0 12px 0;">Hi [First name],</p>
            <p style="margin:0 0 18px 0;">Your order <b>[Order number]</b> has shipped. It should arrive on [Date].</p>
            <!-- Button: a padded table cell around a link -->
            <table role="presentation" cellpadding="0" cellspacing="0" border="0">
              <tr>
                <td bgcolor="#1f7a3e" style="padding:12px 22px;">
                  <a href="https://example.com/track" style="font-family:Arial, sans-serif; font-size:15px; font-weight:bold; color:#ffffff; text-decoration:none;">Track the parcel</a>
                </td>
              </tr>
            </table>
          </td>
        </tr>
        <tr>
          <td style="padding:14px 24px; font-family:Arial, sans-serif; font-size:12px; line-height:150%; color:#6b7280; border-top:1px solid #e1e4ea;">
            Acme Studio, 1 Example Street. You get this mail because you ordered from us.
          </td>
        </tr>
      </table>
    </td>
  </tr>
</table>
</body>
</html>
A 600px email made of two tables, inline styles and a table-cell button. No stylesheet, no div layout.

Everything in it is plain HTML from before the CSS layout era: width attributes, bgcolor, padding on <td> cells, and a style attribute on every piece of text. That is on purpose.

Where Outlook keeps email templates

Outlook has three template features, and they keep different things. Pick the one that keeps a layout.

Mail templates and .oft files keep the whole email. My Templates keeps short text snippets.
Mail templates and .oft files keep the whole email. My Templates keeps short text snippets.
Feature Where What it keeps
Mail templates New Outlook, Outlook on the web The whole email: recipients, subject, body, formatting, images, tables, attachments
Outlook Template (.oft) Classic Outlook for Windows The email draft as a file
My Templates add-in New Outlook, web, classic Short text snippets, plain text with basic styling

Microsoft notes that Mail templates need a qualifying Microsoft 365 subscription. New Outlook and Outlook on the web can also download a template as an .oft file, and add .oft files from your computer with Add OFT.

Why the HTML has to be built with tables

Microsoft's reference for the Word engine, written for Outlook 2007, lists the CSS it skips. The list includes max-width, float, position and background-image. Elements such as script, form and button are unsupported too.

Left: what the Word engine skips. Right: what it keeps, which is enough to build a solid email.
Left: what the Word engine skips. Right: what it keeps, which is enough to build a solid email.

Compare the same card built two ways. Press the button to remove the properties the Word engine skips. This only imitates the effect in your browser, it is not Outlook.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Web layout vs table layout</title>
<style>
  body { margin: 0; padding: 14px; font-family: system-ui, sans-serif; background: #f4f5f7; color: #1d2330; }
  .bar { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-bottom: 12px; font-size: 14px; }
  button { font: inherit; padding: 8px 14px; border-radius: 8px; border: 1px solid #1f4e79; background: #1f4e79; color: #fff; cursor: pointer; }
  .cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 14px; }
  .label { font-size: 13px; font-weight: 700; margin: 0 0 6px; }
  .box { background: #fff; border: 1px dashed #c9ced8; padding: 10px; }
  #status { font-size: 13px; color: #9a3412; }
</style>
</head>
<body>
<div class="bar">
  <button id="toggle" type="button">Remove what the Word engine skips</button>
  <span id="status"></span>
</div>

<div class="cols">
  <div>
    <p class="label">A: built like a web page</p>
    <div class="box" id="web">
      <div style="max-width:320px; margin:0 auto; background-image:linear-gradient(135deg,#1f4e79,#3b82c4); border-radius:14px; padding:16px; color:#fff; font-family:Arial, sans-serif;">
        <div style="display:flex; gap:10px; align-items:center;">
          <div style="width:40px; height:40px; border-radius:50%; background:#fff; color:#1f4e79; font-weight:bold; text-align:center; line-height:40px;">A</div>
          <div style="font-size:17px; font-weight:bold;">Your invoice is ready</div>
        </div>
        <p style="margin:12px 0; line-height:1.5;">Amount due: 120.00</p>
        <a href="#" style="display:inline-block; background:#fff; color:#1f4e79; padding:10px 16px; border-radius:20px; text-decoration:none; font-weight:bold;">View invoice</a>
      </div>
    </div>
  </div>
  <div>
    <p class="label">B: built with tables</p>
    <div class="box" id="tbl">
      <table role="presentation" width="320" cellpadding="0" cellspacing="0" border="0" align="center" bgcolor="#1f4e79" style="width:100%; max-width:320px;">
        <tr>
          <td width="56" style="padding:16px 0 0 16px;">
            <table role="presentation" cellpadding="0" cellspacing="0" border="0"><tr>
              <td width="40" height="40" bgcolor="#ffffff" align="center" style="font-family:Arial, sans-serif; font-weight:bold; color:#1f4e79;">A</td>
            </tr></table>
          </td>
          <td style="padding:16px 16px 0 0; font-family:Arial, sans-serif; font-size:17px; font-weight:bold; color:#ffffff;">Your invoice is ready</td>
        </tr>
        <tr>
          <td colspan="2" style="padding:12px 16px; font-family:Arial, sans-serif; line-height:150%; color:#ffffff;">Amount due: 120.00</td>
        </tr>
        <tr>
          <td colspan="2" style="padding:0 16px 16px;">
            <table role="presentation" cellpadding="0" cellspacing="0" border="0"><tr>
              <td bgcolor="#ffffff" style="padding:10px 16px;"><a href="#" style="font-family:Arial, sans-serif; font-weight:bold; color:#1f4e79; text-decoration:none;">View invoice</a></td>
            </tr></table>
          </td>
        </tr>
      </table>
    </div>
  </div>
</div>

<script>
  // Properties listed as unsupported by Word's HTML engine, plus border-radius,
  // which is not on its supported list. This only imitates the effect.
  const skipped = ['max-width', 'background-image', 'border-radius', 'float', 'position'];
  const saved = new Map();
  let stripped = false;

  document.getElementById('toggle').addEventListener('click', (e) => {
    stripped = !stripped;
    document.querySelectorAll('#web [style], #tbl [style]').forEach((el) => {
      if (stripped) {
        saved.set(el, el.getAttribute('style'));
        skipped.forEach((p) => el.style.removeProperty(p));
      } else {
        el.setAttribute('style', saved.get(el));
      }
    });
    e.target.textContent = stripped ? 'Put the CSS back' : 'Remove what the Word engine skips';
    document.getElementById('status').textContent = stripped ? 'Removed: ' + skipped.join(', ') : '';
  });
</script>
</body>
</html>
A loses its background, so white text sits on white. B keeps its colour because the colour lives in bgcolor on the table.

Card A did nothing wrong as a web page. It just leaned on background-image for its colour and on border-radius for its shape. Card B has a plain bgcolor and a fixed width, so there is nothing for the engine to drop.

Rules that keep a template intact

Microsoft's email rendering guide for Dynamics 365 has an Outlook (Classic) section that adds a few practical rules.

  • Put spacing on table cells. The guide says the Word-based engine has limited support for margin and padding on other elements, and recommends padding on td.
  • Write line height as a percentage. It says numeric values such as line-height: 1.5 are not supported. Use 150%.
  • Keep the email 600 to 800 pixels wide. The same guide gives this range to avoid sideways scrolling.
  • Use solid colours, not background images. Give every coloured block a bgcolor.
  • Inline the CSS. Put styles in the style attribute of each element. Inline CSS explains how.

A good template also leaves room for the text that changes. Mark those parts with placeholders in square brackets, such as [First name], so they are easy to spot before you press send.

Fill in the placeholders before you save

When the same email goes out often with different details, a small page can fill the placeholders for you. Type in the fields and the preview and the HTML both update.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Fill in an email template</title>
<style>
  body { margin: 0; padding: 14px; font-family: system-ui, sans-serif; background: #f4f5f7; color: #1d2330; }
  form { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; margin-bottom: 12px; }
  label { font-size: 13px; font-weight: 600; display: grid; gap: 4px; }
  input { font: inherit; padding: 8px; border: 1px solid #c9ced8; border-radius: 6px; }
  .preview { background: #eef1f5; padding: 10px; border: 1px solid #dde1e8; }
  .row { display: flex; gap: 10px; align-items: center; margin: 12px 0 6px; flex-wrap: wrap; }
  button { font: inherit; padding: 8px 14px; border-radius: 8px; border: 0; background: #1f7a3e; color: #fff; cursor: pointer; }
  #msg { font-size: 13px; color: #0f5132; }
  textarea { width: 100%; box-sizing: border-box; height: 150px; font: 12px/1.4 ui-monospace, Consolas, monospace; }
</style>
</head>
<body>
<form id="fields">
  <label>First name <input name="name" value="Dana"></label>
  <label>Order number <input name="order" value="A-1042"></label>
  <label>Delivery date <input name="date" value="3 October"></label>
</form>

<div class="preview" id="preview"></div>

<div class="row">
  <button id="copy" type="button">Copy the HTML</button>
  <span id="msg"></span>
</div>
<textarea id="out" readonly aria-label="Email HTML"></textarea>

<!-- The template. [Brackets] mark the parts that change per email. -->
<template id="tpl">
<table role="presentation" width="600" cellpadding="0" cellspacing="0" border="0" bgcolor="#ffffff" style="width:100%; max-width:600px;">
  <tr><td bgcolor="#1f4e79" style="padding:16px 22px; font-family:Arial, sans-serif; font-size:19px; font-weight:bold; color:#ffffff;">Acme Studio</td></tr>
  <tr><td style="padding:22px; font-family:Arial, sans-serif; font-size:15px; line-height:150%; color:#1d2330;">
    <p style="margin:0 0 12px 0;">Hi [First name],</p>
    <p style="margin:0 0 16px 0;">Your order <b>[Order number]</b> has shipped. It should arrive on [Date].</p>
    <table role="presentation" cellpadding="0" cellspacing="0" border="0"><tr>
      <td bgcolor="#1f7a3e" style="padding:11px 20px;"><a href="https://example.com/track" style="font-family:Arial, sans-serif; font-weight:bold; color:#ffffff; text-decoration:none;">Track the parcel</a></td>
    </tr></table>
  </td></tr>
</table>
</template>

<script>
  const form = document.getElementById('fields');
  const tpl = document.getElementById('tpl').innerHTML.trim();

  // Turn typed text into safe HTML text (so "<" cannot become a tag)
  const esc = (s) => s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');

  function render() {
    const d = new FormData(form);
    const html = tpl
      .replaceAll('[First name]', esc(d.get('name')))
      .replaceAll('[Order number]', esc(d.get('order')))
      .replaceAll('[Date]', esc(d.get('date')));
    document.getElementById('preview').innerHTML = html;
    document.getElementById('out').value = html;
  }

  form.addEventListener('input', render);
  form.addEventListener('submit', (e) => e.preventDefault());

  document.getElementById('copy').addEventListener('click', async () => {
    const out = document.getElementById('out');
    const msg = document.getElementById('msg');
    try {
      await navigator.clipboard.writeText(out.value);
      msg.textContent = 'Copied.';
    } catch {
      out.select();  // clipboard blocked: select it so Ctrl+C / Cmd+C works
      msg.textContent = 'Selected. Press Ctrl+C or Cmd+C.';
    }
  });

  render();
</script>
</body>
</html>
The form stays inside the page. Copy the HTML, or use the preview as the source for an Outlook draft.

The page swaps each placeholder with replaceAll and escapes what you type, so a stray < cannot turn into a tag. The template itself lives in a <template> element, which the browser does not display.

How to save it as an Outlook template

The .html file stays the master copy. Outlook gets a saved draft made from it.
The .html file stays the master copy. Outlook gets a saved draft made from it.
  1. Build the email as tables. One outer table for the background, one inner table with width="600".
  2. Inline every style on the cells and text.
  3. Mark the changing parts with placeholders.
  4. Check it in a browser at desktop and phone width.
  5. Save it in Outlook. Get the email into a new message, then save it as a template.

Getting HTML into the body of a new message is the fiddly step, and the routes differ by Outlook version. How to send an HTML email in Outlook covers them.

To save it, use Mail template > Save email as template in new Outlook or on the web.

In classic Outlook, use File > Save As and choose Outlook Template. To reuse a classic template, go to New Items > More Items > Choose Form and pick User Templates in File System.

When it does not work

What you see Cause Fix
The email fills the whole window in classic Outlook max-width is skipped Add width="600" to the table
A coloured header turns white The colour came from background-image or a gradient Use bgcolor on the cell
Spacing differs from the browser Margin or padding on a div or p Pad the td instead
Line spacing differs from the browser A unitless line-height Write it as a percentage
A <button> shows no button <button> is not supported Use a padded table cell around a link
Saved template comes back as plain text It was saved in My Templates Use Mail templates or an .oft

For more layout fixes, see HTML not displaying correctly in Outlook. For a version that covers other mail apps, start from the HTML email template guide.

Before a template goes into Outlook, someone usually has to approve it. An .html attachment may arrive as code, and a screenshot cannot show the phone width or let anyone copy the source.

To share the working version, paste the page into a NOS document and choose Create share link. HTML to link walks through it.

The page renders as written and its scripts run, so reviewers can type into the placeholder form themselves. If you change the code later, the same link shows the new version.

Questions people ask

Can I import an .html file straight into Outlook as a template?

Outlook's template features save an email draft, not an HTML file. Put the finished email into a new message first, then save that message as a template. In new Outlook and Outlook on the web that is Mail template > Save email as template. In classic Outlook it is File > Save As > Outlook Template.

Why does my template look fine in the browser and broken in Outlook?

Classic Outlook for Windows uses a Word-based HTML engine. Microsoft's reference for that engine lists max-width, float, position and background-image as unsupported, so a layout built on them falls apart. Tables with width attributes and padding on cells hold up.

Can an Outlook email template run JavaScript or contain a form?

No. Microsoft's list for the Word engine names script, form, input and button as unsupported elements. Keep the email static and link to a page for anything interactive.

What is the difference between My Templates and Mail templates?

Microsoft describes the My Templates add-in as storing short text snippets with plain text and basic styling. Mail templates save a whole email, including formatting, images, tables and attachments, and need a qualifying Microsoft 365 subscription.

Where are classic Outlook templates stored?

By default in c:\users\username\appdata\roaming\microsoft\templates, as .oft files. New Outlook and Outlook on the web can add those files under Settings > Mail > Templates > Add OFT.

Keep reading