Skip to main content

Automated Invoice Mailing

This guide shows how to automatically send printed invoices via the Intelliprint hybrid mail API whenever invoices are created or become overdue. It is ideal for:
  • Accounting and billing platforms
  • Subscription and SaaS systems
  • Finance teams replacing manual invoice printing

Overview

High-level flow: You can implement automated invoice mailing using:
  • HTML-based letters (for simple layouts)
  • PDF-based letters (for existing invoice PDFs)
  • Backgrounds and templates for consistent branding

Step 1: Decide HTML vs PDF

Option A – HTML invoices Option B – PDF invoices In both cases, you pass customer address data and invoice details to Intelliprint.

Step 2: Map Invoice Events to Postal Actions

Decide when to send printed invoices. Common patterns:
  • Initial invoice generation
    • Every time an invoice is created for customers with postal preferences.
  • Overdue reminders
    • Send a letter if an invoice has not been paid X days after due date.
  • Final notice
    • Send a tracked or recorded letter before escalation.
You can control this using your own business logic in your billing system or integration service.

Step 3: Implement the API Call

Example: HTML-based invoice letter (Node.js)

import Intelliprint from "intelliprint";

const ip = Intelliprint(process.env.INTELLIPRINT_API_KEY);

export async function sendInvoiceByPost(invoice, customer) {
  const html = `
    <h1>Invoice ${invoice.number}</h1>
    <p>Dear ${customer.name},</p>
    <p>Thank you for your business. Your invoice is now due on <strong>${invoice.due_date}</strong>.</p>
    <p>Amount due: <strong>£${invoice.amount_gbp.toFixed(2)}</strong></p>
    <p>You can also pay online using your usual method.</p>
    <p>Kind regards,<br>${invoice.company_name}</p>
  `;

  const printJob = await ip.prints.create({
    testmode: true, // start in test mode
    content: html,
    recipients: [
      {
        address: {
          name: customer.name,
          line: customer.postal_address.line,
          postcode: customer.postal_address.postcode,
          country: customer.postal_address.country || "GB"
        }
      }
    ],
    metadata: {
      invoice_id: invoice.id,
      customer_id: customer.id,
      channel: "invoice_post"
    },
    confirmed: true
  });

  await db.invoices.update(invoice.id, {
    postal_print_job_id: printJob.id
  });
}
Switch testmode to false once you have tested the flow.

Example: PDF-based invoice letter (Node.js)

import Intelliprint from "intelliprint";
import fs from "fs";

const ip = Intelliprint(process.env.INTELLIPRINT_API_KEY);

export async function sendInvoicePdfByPost(invoice, customer) {
  const pdfPath = `/tmp/invoices/${invoice.id}.pdf`; // generated earlier in your system

  const printJob = await ip.prints.create({
    testmode: true,
    file: fs.createReadStream(pdfPath),
    printing: {
      double_sided: "yes"
    },
    recipients: [
      {
        address: {
          name: customer.name,
          line: customer.postal_address.line,
          postcode: customer.postal_address.postcode,
          country: customer.postal_address.country || "GB"
        }
      }
    ],
    metadata: {
      invoice_id: invoice.id,
      customer_id: customer.id,
      channel: "invoice_post"
    },
    confirmed: true
  });

  await db.invoices.update(invoice.id, {
    postal_print_job_id: printJob.id
  });
}

Step 4: Track Statuses and Build an Audit Trail

For finance and compliance, you should store:
  • Intelliprint print_job_id
  • Letter statuses and key timestamps
  • Any returned or failed mail indicators
Use Track, Retrieve & Cancel to:
  • Retrieve print jobs and letters by ID
  • Check status (e.g. waiting_to_print, printing, sent, returned)
  • Cancel jobs that have not yet been printed
Augment this with Webhooks to push status updates back into your billing system automatically.

Step 5: Control Costs & Service Levels

Invoices can be time-sensitive and high volume. Use:
  • Postage choices and scheduling
    See Postage & Scheduling to choose between first class, second class, tracked services and dispatch dates.
  • Double-sided printing
    Enable double-sided printing for multi-page invoices to reduce sheet count and costs. See Double-Sided Printing in the HTML quickstart.
  • Test mode for cost estimation
    Use testmode: true with your real data to calculate actual per-invoice and per-campaign costs without sending live mail. See Understand Costs.

Example: Daily Invoice Batch

You can also run a daily job to send any outstanding invoices:
async function runDailyInvoiceBatch() {
  const invoicesToSend = await db.invoices.findAll({
    where: {
      delivery_method: "post",
      posted_via_intelliprint: false,
      status: "open"
    }
  });

  for (const invoice of invoicesToSend) {
    const customer = await db.customers.findById(invoice.customer_id);
    await sendInvoicePdfByPost(invoice, customer);
  }

  console.log(`Queued ${invoicesToSend.length} invoices for postal mailing`);
}

Next Steps