Automated PDF Invoice Generator in Python [With Code]

Automated PDF Invoice Generator and Email Dispatcher Python

Generating customer receipts, contracts, and monthly invoices manually consumes hours of administrative time and introduces calculation mistakes. In automated billing systems, your application needs to receive transaction records, generate a formatted PDF with company branding, calculate taxes and totals, and dispatch the PDF directly to the customer's email via SMTP.

In this tutorial, you will build an end-to-end billing automation pipeline using ReportLab (for deterministic PDF canvas layout) and Python's built-in smtplib and email modules (for authenticated SSL/TLS email delivery).


Python PDF Generation Libraries Compared

Library Approach Dependencies Pros Cons
ReportLab Programmatic Canvas & Flowables Pure Python / C-extension Pixel-perfect layouts, fast generation Steeper coordinate learning curve
WeasyPrint HTML + CSS to PDF Cairo, Pango, GDK-PixBuf Design invoices with standard CSS Heavy external C-libraries to install
pdfkit wkhtmltopdf wrapper wkhtmltopdf binary Quick setup from HTML strings Deprecated upstream engine

Installation

pip install reportlab

Building the Invoice PDF Generator with ReportLab Flowables

import os
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib import colors

def generate_invoice_pdf(filename: str, invoice_number: str, customer_info: dict, items: list) -> str:
    doc = SimpleDocTemplate(filename, pagesize=letter, rightMargin=36, leftMargin=36, topMargin=36, bottomMargin=36)
    story = []
    styles = getSampleStyleSheet()
    
    # 1. Header Branding
    title_style = ParagraphStyle(
        'InvoiceTitle',
        parent=styles['Heading1'],
        fontSize=22,
        textColor=colors.HexColor("#1a365d"),
        spaceAfter=12
    )
    story.append(Paragraph("iLab Academy - Tax Invoice", title_style))
    story.append(Paragraph(f"Invoice #: {invoice_number}
Customer: {customer_info['name']}
Email: {customer_info['email']}", styles['Normal'])) story.append(Spacer(1, 20)) # 2. Line Items Table Data table_data = [["Item Description", "Qty", "Unit Price", "Total Price"]] subtotal = 0.0 for item in items: line_total = item['qty'] * item['price'] subtotal += line_total table_data.append([item['name'], str(item['qty']), f"${item['price']:.2f}", f"${line_total:.2f}"]) tax = subtotal * 0.10 total = subtotal + tax table_data.append(["", "", "Subtotal:", f"${subtotal:.2f}"]) table_data.append(["", "", "Tax (10%):", f"${tax:.2f}"]) table_data.append(["", "", "Grand Total:", f"${total:.2f}"]) # 3. Table Styling invoice_table = Table(table_data, colWidths=[280, 50, 90, 100]) invoice_table.setStyle(TableStyle([ ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor("#f1f5f9")), ('TEXTCOLOR', (0, 0), (-1, 0), colors.HexColor("#0f172a")), ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'), ('BOTTOMPADDING', (0, 0), (-1, 0), 8), ('GRID', (0, 0), (-1, -4), 0.5, colors.HexColor("#cbd5e1")), ('FONTNAME', (2, -3), (-1, -1), 'Helvetica-Bold'), ('ALIGN', (1, 0), (-1, -1), 'RIGHT'), ])) story.append(invoice_table) story.append(Spacer(1, 30)) story.append(Paragraph("Payment is due within 14 business days. Thank you for your business!", styles['Normal'])) doc.build(story) print(f"Generated PDF invoice: {filename}") return filename if __name__ == "__main__": sample_customer = {"name": "Dev Studio Ltd", "email": "billing@devstudio.com"} sample_items = [ {"name": "Python Backend Architecture Consultation", "qty": 10, "price": 120.00}, {"name": "API Security Audit & Penetration Test", "qty": 1, "price": 850.00} ] generate_invoice_pdf("invoice_1001.pdf", "INV-2026-1001", sample_customer, sample_items)

Automating Email Dispatch with smtplib and MIME Attachments

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication

def send_invoice_email(recipient_email: str, invoice_path: str, smtp_user: str, smtp_pass: str):
    msg = MIMEMultipart()
    msg['From'] = smtp_user
    msg['To'] = recipient_email
    msg['Subject'] = "Your Invoice from iLab Academy"
    
    body = "Hello,\n\nPlease find your latest invoice attached to this email.\n\nBest regards,\niLab Academy Billing Team"
    msg.attach(MIMEText(body, 'plain'))
    
    with open(invoice_path, "rb") as f:
        attachment = MIMEApplication(f.read(), _subtype="pdf")
        attachment.add_header('Content-Disposition', 'attachment', filename=os.path.basename(invoice_path))
        msg.attach(attachment)
        
    with smtplib.SMTP_SSL("smtp.gmail.com", 465) as server:
        server.login(smtp_user, smtp_pass)
        server.send_message(msg)
        print(f"Invoice successfully sent to {recipient_email}!")

Frequently Asked Questions

Q: How do I handle multi-page tables in ReportLab?
A: When using SimpleDocTemplate and Table Flowables, ReportLab automatically splits long item rows across multiple pages and recalculates coordinates directly.

Post a Comment

0 Comments