Tips > Building Workflows

Generate Dynamic HTML Email Templates

Instead of fighting with the limited formatting options in n8n's email nodes, build your HTML in a Code node.

Instead of fighting with the limited formatting options in n8n's email nodes, build your HTML in a Code node. This gives you full control over styling, conditional sections, and dynamic table generation.

Real-world example: A daily sales report email that includes a summary header, a table of top deals, and conditional warning banners when targets are missed.

// Mode: Run Once for All Items
const deals = $input.all().map(i => i.json);
const totalRevenue = deals.reduce((s, d) => s + d.amount, 0);
const target = 50000;
const hitTarget = totalRevenue >= target;

const tableRows = deals
  .sort((a, b) => b.amount - a.amount)
  .slice(0, 10)
  .map(d => `
    <tr>
      <td style="padding:8px;border-bottom:1px solid #ddd;">${d.dealName}</td>
      <td style="padding:8px;border-bottom:1px solid #ddd;">${d.rep}</td>
      <td style="padding:8px;border-bottom:1px solid #ddd;text-align:right;">
        $${d.amount.toLocaleString()}
      </td>
      <td style="padding:8px;border-bottom:1px solid #ddd;">${d.stage}</td>
    </tr>
  `).join('');

const warningBanner = hitTarget ? '' : `
  <div style="background:#c0392b;color:#fff;padding:12px;margin:16px 0;
              border-radius:4px;text-align:center;">
    Revenue is $${(target - totalRevenue).toLocaleString()} below daily target.
    Review pipeline immediately.

`;

const html = `
<div style="font-family:Arial,sans-serif;max-width:680px;margin:0 auto;">
  <h2 style="color:#2c3e50;">Daily Sales Report</h2>
  <p>Report generated: ${new Date().toISOString().slice(0, 10)}</p>
  ${warningBanner}
  <div style="background:#ecf0f1;padding:16px;border-radius:4px;margin:16px 0;">
    <strong>Total Revenue:</strong> $${totalRevenue.toLocaleString()} /
    $${target.toLocaleString()} target
    (${((totalRevenue / target) * 100).toFixed(1)}%)

  <h3>Top 10 Deals</h3>
  <table style="width:100%;border-collapse:collapse;">
    <thead>
      <tr style="background:#34495e;color:#fff;">
        <th style="padding:8px;text-align:left;">Deal</th>
        <th style="padding:8px;text-align:left;">Rep</th>
        <th style="padding:8px;text-align:right;">Amount</th>
        <th style="padding:8px;text-align:left;">Stage</th>
      </tr>
    </thead>
    <tbody>${tableRows}</tbody>
  </table>

`;

return [{ json: { html, subject: `Sales Report - $${totalRevenue.toLocaleString()} ${hitTarget ? '(Target Met)' : '(Below Target)'}` } }];
```text
Feed the `html` output into the Send Email node's HTML body field and the `subject` into the subject line.

**Related:** [Use Edit Fields in "Map Each" Mode for Simple Renames](../data-transformation/01-use-edit-fields-in-map-each-mode-for-simple-renames.md) | [Configure Payload Size and Binary Data Mode for Large Files](../performance-and-large-files/01-configure-payload-size-and-binary-data-mode-for-large-files.md)

Showcase builds

19 complete workflows from my own projects, each with its n8n workflow JSON to import. Showcase entries link the file at the end of the article.

See the showcase builds

Keep reading

191 entries grouped by topic, from first workflow to queue mode. Free, no signup.

Browse the encyclopedia

Need it built?

I design, build and run n8n systems for clients. Every engagement starts with a $1,500 diagnostic audit, credited toward the build.

Book a 20-minute call