TutorialsGenerate PDF Invoices

Generate PDF Invoices

Create professional PDF invoices from templates and attach them to emails automatically.


Overview

FormaMail allows you to generate PDF documents dynamically from templates and attach them to emails. This tutorial covers:

  • Creating an attachment template for PDF generation (via AI, gallery, or manually)
  • Designing a professional invoice layout
  • Sending emails with dynamically generated PDF attachments
  • Generating standalone PDFs via the API

This is perfect for invoices, receipts, reports, contracts, and any document you need to send as an attachment.


Prerequisites

Before starting, make sure you have:

  • An active FormaMail account
  • An API key with attachment permissions
  • (Optional) Company logo for branding

How PDF Generation Works

FormaMail uses attachment templates to generate PDFs:

  1. Create an Attachment Template - Design your PDF layout in the visual editor
  2. Send Email with Attachment - Reference the template and pass variables
  3. Automatic Generation - FormaMail renders the PDF with your data
  4. Delivery - The PDF is attached to your email
Email Template + Attachment Template + Variables β†’ Email with PDF Attachment

Same Designer Technology: FormaMail uses the same visual editor for creating email and PDF templates. Each template is created separately using the same drag-and-drop interface.


Choose Your Approach

FormaMail offers three ways to create PDF templates:

ApproachBest ForTime
AI GenerationQuick start, standard invoices/reports~1 minute
Template GalleryProfessional designs, common documents~2 minutes
Manual DesignFull customization, complex layouts~15-20 minutes

Option A: Generate with AI (Fastest)

Let AI create your invoice template in seconds:

Step 1: Start AI Generation

  1. Log in to your FormaMail Dashboard
  2. Go to Templates β†’ Create Template
  3. Select Attachment Template
  4. Click Generate with AI

Step 2: Describe Your Invoice

Enter a natural language description. Be specific:

Example prompts:

β€œProfessional invoice PDF with company logo, invoice number, date, bill-to section, line items table with description, quantity, unit price and amount, subtotal, tax, and total. Include payment terms and bank details at the bottom.”

β€œSimple receipt with company header, receipt number, date, list of items purchased, total amount, and thank you message”

β€œDetailed quote/estimate PDF with company branding, customer information, itemized services with pricing, terms and conditions, and signature line”

Step 3: Review and Customize

  1. AI generates a complete PDF template with:
    • Professional A4/Letter layout
    • Properly formatted tables
    • Pre-configured variables (e.g., {{invoiceNumber}}, {{items}}, {{total}})
  2. Review the template in the designer
  3. Make any adjustments:
    • Add your company logo
    • Update colors to match your brand
    • Modify text content and sections

Step 4: Publish

  1. Click Preview to test with sample data
  2. Click Save and Publish
  3. Copy the Template ID for use in your code

Use professionally designed invoice templates:

  1. Log in to your FormaMail Dashboard
  2. Go to Templates β†’ Template Gallery
  3. Filter by Attachment templates

Step 2: Find an Invoice Template

Browse categories:

  • Invoices: Professional invoices, simple invoices, detailed invoices
  • Receipts: Purchase receipts, payment confirmations
  • Reports: Monthly reports, statements, summaries
  • Contracts: Agreements, proposals, quotes

Step 3: Import and Customize

  1. Click on a template to preview
  2. Click Import to add it to your templates
  3. Customize the template:
    • Replace placeholder logo
    • Update company details
    • Adjust colors and fonts
    • Modify sections as needed

Step 4: Publish

  1. Click Preview to test
  2. Click Save and Publish
  3. Copy the Template ID

Option C: Build Manually (Full Control)

For complete customization, build your invoice template from scratch.

Tutorial: Create a Professional Invoice PDF

Step 1: Create an Attachment Template

  1. Log in to your FormaMail Dashboard
  2. Navigate to Templates β†’ Create Template
  3. Select Attachment Template
  4. Choose PDF as the output format

Set the template details:

  • Name: Invoice Template
  • Slug: invoice-template
  • Description: Professional invoice for customers

Step 2: Configure Page Settings

Before designing, set up the PDF page:

  1. Click Page Settings in the toolbar
  2. Configure:
    • Page Size: A4 (or Letter for US)
    • Orientation: Portrait
    • Margins: 40px all sides
    • Header Height: 0 (we’ll add our own header)
    • Footer Height: 60px

Step 3: Design the Invoice Header

Create a professional header with your company branding:

  1. Drag a Columns component (2 columns) onto the canvas

  2. Left Column - Company Info:

    • Add Image component for your logo
      • Width: 150px
    • Add Text for company name:
      • Content: {{companyName}}
      • Font Size: 20px
      • Font Weight: Bold
    • Add Text for address:
      • Content: {{companyAddress}}
      • Font Size: 12px
      • Color: #666666
  3. Right Column - Invoice Details (right-aligned):

    • Add Heading:
      • Content: INVOICE
      • Level: H1
      • Font Size: 32px
      • Color: #1a1a2e
    • Add Text for invoice number:
      • Content: Invoice #: {{invoiceNumber}}
      • Font Size: 14px
    • Add Text for dates:
      • Content: Date: {{invoiceDate}}
      • Content: Due Date: {{dueDate}}

Step 4: Add Bill To Section

Below the header:

  1. Add a Divider component

    • Margin: 24px 0
  2. Add a Columns component (2 columns)

  3. Left Column - Bill To:

    • Add Heading: Bill To
      • Level: H4
      • Margin Bottom: 8px
    • Add Text:
      {{customer.name}}
      {{customer.address}}
      {{customer.city}}, {{customer.state}} {{customer.zip}}
      {{customer.email}}
  4. Right Column - Payment Info (optional):

    • Add Heading: Payment Details
    • Add Text: {{paymentMethod}}

Step 5: Create the Line Items Table

This is the core of the invoice:

  1. Add a Container with:

    • Background: #f8f9fa
    • Border Radius: 8px
    • Margin Top: 24px
    • Padding: 0
  2. Add a Table component inside with:

    • Header Row: Description | Quantity | Unit Price | Amount
    • Header background: #1a1a2e
    • Header text color: #ffffff
  3. For the table body, use a Loop component:

    • Data Source: {{items}}
  4. Inside the loop, add table cells:

    • Description: {{item.description}}
    • Quantity: {{item.quantity}}
    • Unit Price: {{item.unitPrice}}
    • Amount: {{item.amount}}

Table Styling: Use alternating row colors for readability. Set even rows to #ffffff and odd rows to #f8f9fa.

Step 6: Add Totals Section

Below the items table:

  1. Add a Container for totals:

    • Width: 300px
    • Float: Right
    • Margin Top: 24px
  2. Add rows for each total line using Columns (2 columns):

    Subtotal Row:

    • Left: Subtotal:
    • Right: {{subtotal}} (right-aligned)

    Tax Row:

    • Left: Tax ({{taxRate}}%):
    • Right: {{taxAmount}}

    Discount Row (conditional):

    • Wrap in Conditional with condition {{hasDiscount}}
    • Left: Discount:
    • Right: -{{discountAmount}}

    Divider

    Total Row:

    • Left: Total Due: (bold, larger)
    • Right: {{total}} (bold, larger, primary color)

Step 7: Add Payment Terms

Below the totals:

  1. Add a Container:

    • Margin Top: 40px
    • Padding: 16px
    • Background: #f0f9ff (light blue)
    • Border Radius: 8px
  2. Add Heading: Payment Terms

    • Level: H4
  3. Add Text:

    {{paymentTerms}}
    
    Please make payment to:
    Bank: {{bankName}}
    Account: {{accountNumber}}
    Reference: {{invoiceNumber}}

Step 8: Add Notes Section (Optional)

  1. Add a Conditional component:

    • Condition: {{notes}}
  2. Inside, add:

    • Heading: Notes
    • Text: {{notes}}
  1. Add a Container at the bottom:

    • Background: #1a1a2e
    • Padding: 16px
    • Text Color: #ffffff
    • Text Align: Center
  2. Add Text:

    • Content: Thank you for your business!
    • Font Size: 14px
  3. Add Text:

    • Content: {{companyName}} | {{companyPhone}} | {{companyEmail}}
    • Font Size: 12px
    • Color: #aaaaaa

Step 10: Review and Publish

  1. Click Variables tab to review all variables:
VariableTypeDescription
invoiceNumberStringInvoice identifier
invoiceDateStringInvoice date
dueDateStringPayment due date
companyNameStringYour company name
companyAddressStringCompany address
companyPhoneStringCompany phone
companyEmailStringCompany email
customerObjectCustomer details
itemsArrayLine items
subtotalStringSubtotal amount
taxRateNumberTax percentage
taxAmountStringTax amount
hasDiscountBooleanHas discount?
discountAmountStringDiscount amount
totalStringTotal due
paymentTermsStringPayment terms
notesStringAdditional notes
  1. Click Preview to test with sample data
  2. Click Save and Publish
  3. Copy the Template ID

Sending Emails with PDF Attachments

Now use your invoice template to send emails with PDF attachments:

Basic Example

const axios = require('axios');
 
const API_KEY = process.env.FORMAMAIL_API_KEY;
const API_URL = 'https://api.formamail.com/api';
 
async function sendInvoiceEmail() {
  const response = await axios.post(
    `${API_URL}/emails/send`,
    {
      // Email template
      templateId: 'invoice-email-template',
      to: [
        {
          email: 'customer@example.com',
          name: 'John Doe'
        }
      ],
      // Email variables
      variables: {
        customerName: 'John',
        invoiceNumber: 'INV-2024-001'
      },
      // PDF attachment
      attachments: [
        {
          filename: 'invoice-{{invoiceNumber}}.pdf',
          attachmentTemplateId: 'invoice-template',
          outputFormats: ['pdf'],
          variables: {
            invoiceNumber: 'INV-2024-001',
            invoiceDate: 'December 7, 2025',
            dueDate: 'December 21, 2025',
            companyName: 'Acme Corp',
            companyAddress: '123 Business St, Suite 100',
            companyPhone: '+1 (555) 123-4567',
            companyEmail: 'billing@acme.com',
            customer: {
              name: 'John Doe',
              address: '456 Customer Lane',
              city: 'New York',
              state: 'NY',
              zip: '10001',
              email: 'john@example.com'
            },
            items: [
              {
                description: 'Professional Services - November',
                quantity: 40,
                unitPrice: '$150.00',
                amount: '$6,000.00'
              },
              {
                description: 'Software License - Annual',
                quantity: 1,
                unitPrice: '$1,200.00',
                amount: '$1,200.00'
              },
              {
                description: 'Support Package - Premium',
                quantity: 1,
                unitPrice: '$500.00',
                amount: '$500.00'
              }
            ],
            subtotal: '$7,700.00',
            taxRate: 8.5,
            taxAmount: '$654.50',
            hasDiscount: true,
            discountAmount: '$200.00',
            total: '$8,154.50',
            paymentTerms: 'Net 14 - Payment due within 14 days of invoice date.',
            bankName: 'First National Bank',
            accountNumber: '****4567',
            notes: 'Thank you for being a valued customer!'
          }
        }
      ]
    },
    {
      headers: {
        'Authorization': `Bearer ${API_KEY}`,
        'Content-Type': 'application/json'
      }
    }
  );
 
  console.log('Invoice email sent!');
  console.log('Email ID:', response.data.id);
  return response.data;
}
 
sendInvoiceEmail();

Dynamic Filename

The filename supports variables:

attachments: [
  {
    filename: 'invoice-{{invoiceNumber}}-{{customerName}}.pdf',
    // Generates: invoice-INV-2024-001-John.pdf
    attachmentTemplateId: 'invoice-template',
    outputFormats: ['pdf'],
    variables: { /* ... */ }
  }
]

Multiple Output Formats

Generate both PDF and Excel from the same template:

attachments: [
  {
    filename: 'invoice-{{invoiceNumber}}',
    attachmentTemplateId: 'invoice-template',
    outputFormats: ['pdf', 'xlsx'],  // Both formats
    variables: { /* ... */ }
  }
]

This creates two attachments: invoice-INV-001.pdf and invoice-INV-001.xlsx.


Standalone PDF Generation

Generate PDFs without sending an email:

async function generatePDF() {
  const response = await axios.post(
    `${API_URL}/attachments/generate`,
    {
      templateId: 'invoice-template',
      outputFormat: 'pdf',
      variables: {
        invoiceNumber: 'INV-2024-001',
        // ... all other variables
      }
    },
    {
      headers: {
        'Authorization': `Bearer ${API_KEY}`,
        'Content-Type': 'application/json'
      }
    }
  );
 
  console.log('PDF generated!');
  console.log('Download URL:', response.data.url);
  console.log('Expires:', response.data.expiresAt);
 
  return response.data;
}

Response:

{
  "id": "att_abc123",
  "url": "https://cdn.formamail.com/attachments/att_abc123.pdf",
  "filename": "invoice-INV-2024-001.pdf",
  "size": 125432,
  "contentType": "application/pdf",
  "expiresAt": "2024-12-08T12:00:00.000Z"
}

Real-World Example: Order Invoice System

Here’s a complete example integrating with your order system:

const axios = require('axios');
 
class InvoiceService {
  constructor(apiKey) {
    this.client = axios.create({
      baseURL: 'https://api.formamail.com/api',
      headers: {
        'Authorization': `Bearer ${apiKey}`,
        'Content-Type': 'application/json'
      }
    });
  }
 
  async sendInvoice(order, customer) {
    // Calculate totals
    const subtotal = order.items.reduce(
      (sum, item) => sum + (item.quantity * item.price), 0
    );
    const taxAmount = subtotal * (order.taxRate / 100);
    const total = subtotal + taxAmount - (order.discount || 0);
 
    // Format items for template
    const formattedItems = order.items.map(item => ({
      description: item.name,
      quantity: item.quantity,
      unitPrice: this.formatCurrency(item.price),
      amount: this.formatCurrency(item.quantity * item.price)
    }));
 
    // Send email with PDF invoice
    const response = await this.client.post('/emails/send', {
      templateId: 'invoice-notification',
      to: [{ email: customer.email, name: customer.name }],
      variables: {
        customerName: customer.name.split(' ')[0],
        invoiceNumber: order.invoiceNumber,
        viewUrl: `https://yoursite.com/invoices/${order.invoiceNumber}`
      },
      attachments: [{
        filename: `invoice-${order.invoiceNumber}.pdf`,
        attachmentTemplateId: 'invoice-template',
        outputFormats: ['pdf'],
        variables: {
          invoiceNumber: order.invoiceNumber,
          invoiceDate: this.formatDate(order.createdAt),
          dueDate: this.formatDate(order.dueDate),
          companyName: 'Your Company',
          companyAddress: '123 Business St, City, ST 12345',
          companyPhone: '+1 (555) 123-4567',
          companyEmail: 'billing@yourcompany.com',
          customer: {
            name: customer.name,
            address: customer.address.line1,
            city: customer.address.city,
            state: customer.address.state,
            zip: customer.address.zip,
            email: customer.email
          },
          items: formattedItems,
          subtotal: this.formatCurrency(subtotal),
          taxRate: order.taxRate,
          taxAmount: this.formatCurrency(taxAmount),
          hasDiscount: order.discount > 0,
          discountAmount: this.formatCurrency(order.discount || 0),
          total: this.formatCurrency(total),
          paymentTerms: 'Payment due within 30 days.',
          bankName: 'Your Bank',
          accountNumber: '****1234'
        }
      }],
      tags: ['invoice', 'billing'],
      metadata: {
        orderId: order.id,
        customerId: customer.id
      }
    });
 
    return response.data;
  }
 
  formatCurrency(amount) {
    return new Intl.NumberFormat('en-US', {
      style: 'currency',
      currency: 'USD'
    }).format(amount);
  }
 
  formatDate(date) {
    return new Date(date).toLocaleDateString('en-US', {
      year: 'numeric',
      month: 'long',
      day: 'numeric'
    });
  }
}
 
// Usage
const invoiceService = new InvoiceService(process.env.FORMAMAIL_API_KEY);
 
const order = {
  id: 'order-123',
  invoiceNumber: 'INV-2024-001',
  createdAt: new Date(),
  dueDate: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),
  taxRate: 8.5,
  discount: 50,
  items: [
    { name: 'Product A', quantity: 2, price: 99.99 },
    { name: 'Product B', quantity: 1, price: 149.99 }
  ]
};
 
const customer = {
  id: 'cust-456',
  name: 'John Doe',
  email: 'john@example.com',
  address: {
    line1: '456 Customer Lane',
    city: 'New York',
    state: 'NY',
    zip: '10001'
  }
};
 
invoiceService.sendInvoice(order, customer)
  .then(result => console.log('Invoice sent:', result.id))
  .catch(err => console.error('Error:', err));

PDF Design Best Practices

Layout

  1. Use standard page sizes - A4 for international, Letter for US
  2. Set appropriate margins - 40-60px for printing
  3. Keep it single page - When possible, fit content on one page
  4. Use visual hierarchy - Clear headings, grouped sections

Typography

  1. Professional fonts - Arial, Helvetica, Georgia work best
  2. Readable sizes - 10-12pt for body, 14-18pt for headings
  3. Consistent alignment - Right-align numbers for easy scanning
  4. Adequate spacing - White space improves readability

Branding

  1. Include your logo - Top-left is traditional for invoices
  2. Use brand colors - Sparingly for headers and accents
  3. Consistent styling - Match your email templates
  4. Professional footer - Contact info and company details

Data Tables

  1. Clear headers - Bold, contrasting background
  2. Alternating rows - Improves readability
  3. Right-align numbers - Currency, quantities
  4. Adequate column width - Don’t crowd data

Troubleshooting

PDF Not Generating

Solutions:

  1. βœ… Verify attachment template exists and is published
  2. βœ… Check all required variables are provided
  3. βœ… Ensure outputFormats includes pdf
  4. βœ… Check API key has attachment permissions

Layout Issues in PDF

Solutions:

  1. βœ… Preview the template in PDF mode before sending
  2. βœ… Use fixed widths for columns in tables
  3. βœ… Avoid very long unbroken text
  4. βœ… Test with maximum expected data length

Missing Data in PDF

Solutions:

  1. βœ… Check variable names match exactly (case-sensitive)
  2. βœ… Verify nested object structure matches template
  3. βœ… Ensure array data is properly formatted
  4. βœ… Check the Variables tab in template editor

PDF Too Large

Solutions:

  1. βœ… Compress images before uploading
  2. βœ… Use web-optimized images
  3. βœ… Reduce image dimensions if possible
  4. βœ… Limit number of pages/items

Next Steps

Now that you can generate PDF invoices: