HTML Email to PDF: Archive Email Campaigns — TongoRender Blog
Back to Blog
guidesemailpdfarchival

HTML Email to PDF: Archive Email Campaigns

Learn how to convert HTML email campaigns into PDF archives. Understand the challenges of email-specific CSS and how to handle them for perfect PDF output.

TongoRender TeamMarch 8, 20268 min

Email marketing teams send hundreds of campaigns per year. Regulations like GDPR and CAN-SPAM, combined with internal compliance requirements, often mandate archiving every email that goes out. While email service providers store campaign data, having a PDF archive gives you a portable, searchable, and legally admissible record that does not depend on a third-party vendor.

Why Archive Emails as PDF?

  • Regulatory compliance — Financial and healthcare industries require durable records of all customer communications.
  • Legal protection — In disputes, a timestamped PDF is stronger evidence than a screenshot.
  • Vendor independence — If you switch email platforms, your archive remains intact.
  • Internal review — Product and legal teams can review past campaigns without accessing the email platform.
  • Client reporting — Agencies can deliver campaign portfolios as polished PDF documents.

The Challenge: Email HTML Is Not Web HTML

HTML emails use a subset of HTML and CSS that dates back to the early 2000s. Email clients have wildly inconsistent rendering engines, so email developers rely on:

  • Table-based layouts instead of Flexbox or Grid
  • Inline styles instead of external stylesheets
  • Deprecated attributes like bgcolor, align, and cellpadding
  • Conditional comments for Outlook (<!--[if mso]>)
  • VML (Vector Markup Language) for Outlook backgrounds

When converting email HTML to PDF, you need to handle these quirks without breaking the layout.

Preprocessing Email HTML

Before sending email HTML to a PDF API, clean it up:

const { JSDOM } = require('jsdom');

function preprocessEmailHTML(emailHtml) {
  const dom = new JSDOM(emailHtml);
  const document = dom.window.document;

  // Remove Outlook conditional comments
  const html = emailHtml
    .replace(/<!--\[if[^\]]*\]>.*?<!\[endif\]-->/gs, '')
    .replace(/<!--\[if[^\]]*\]>.*?<!\[endif\]-->/gs, '');

  // Remove tracking pixels (1x1 images)
  document.querySelectorAll('img').forEach(img => {
    if (img.width <= 1 || img.height <= 1) {
      img.remove();
    }
  });

  // Ensure images use absolute URLs
  document.querySelectorAll('img').forEach(img => {
    if (img.src && !img.src.startsWith('http')) {
      img.src = `https://cdn.example.com${img.src}`;
    }
  });

  // Add print-friendly styles
  const style = document.createElement('style');
  style.textContent = `
    @media print {
      body { width: 100% !important; margin: 0 !important; }
      table { width: 100% !important; }
      img { max-width: 100% !important; height: auto !important; }
    }
  `;
  document.head.appendChild(style);

  return dom.serialize();
}

Converting to PDF

With the preprocessed HTML, generate the PDF:

async function archiveEmail(campaignId, emailHtml, subject) {
  const cleanHtml = preprocessEmailHTML(emailHtml);

  const response = await fetch('https://api.tongorender.io/v1/pdf', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': process.env.TONGORENDER_API_KEY,
    },
    body: JSON.stringify({
      html: cleanHtml,
      format: 'A4',
      margin: { top: '15mm', bottom: '15mm', left: '10mm', right: '10mm' },
      displayHeaderFooter: true,
      headerTemplate: `<div style="font-size:9px;color:#999;width:100%;text-align:center">${subject} — Campaign #${campaignId}</div>`,
      footerTemplate: '<div style="font-size:9px;color:#999;width:100%;text-align:center">Archived on ' + new Date().toISOString().split('T')[0] + ' — Page <span class="pageNumber"></span></div>',
    }),
  });

  if (!response.ok) throw new Error(`Archive failed: ${response.statusText}`);
  return Buffer.from(await response.arrayBuffer());
}

Batch Archiving with Mailchimp

If you use Mailchimp (or a similar provider), you can pull campaign HTML via their API and archive every campaign automatically:

const mailchimp = require('@mailchimp/mailchimp_marketing');

mailchimp.setConfig({ apiKey: process.env.MAILCHIMP_API_KEY, server: 'us1' });

async function archiveAllCampaigns() {
  const campaigns = await mailchimp.campaigns.list({ count: 100, status: 'sent' });

  for (const campaign of campaigns.campaigns) {
    const content = await mailchimp.campaigns.getContent(campaign.id);
    const pdf = await archiveEmail(campaign.id, content.html, campaign.settings.subject_line);

    fs.writeFileSync(`archives/${campaign.id}.pdf`, pdf);
    console.log(`Archived: ${campaign.settings.subject_line}`);
  }
}

Tips for Perfect Email-to-PDF Conversion

  • Set a fixed width — Emails are typically 600px wide. Set the viewport or a wrapper to match.
  • Handle web fonts — Many email clients strip web fonts, but PDFs can render them. Keep the font links.
  • Remove interactive elements — Buttons with JavaScript handlers or form elements will not work in PDF.
  • Test dark mode variants — If your email has dark mode CSS, decide which version to archive.

TongoRender handles table-based email layouts, inline styles, and legacy HTML attributes without issue. The Chromium rendering engine treats email HTML just like any web page.

Archive your emails with TongoRender — 100 free renders per month, no credit card required.

Share this articleShare on Twitter