B2B Invoice Email
Send professional invoice emails with PDF invoices attached. Perfect for e-commerce, SaaS billing, and B2B transactions.
The Problem
Sending invoice emails with PDF attachments typically requires:
- Rendering the email body
- Generating a PDF invoice
- Attaching the PDF to the email
- Managing multiple templates (email + PDF)
- Keeping both templates in sync
The Solution
FormaMail lets you create email and PDF invoice templates, then send emails with dynamically generated PDF attachments in one API call.
Prerequisites
- FormaMail account with API key
- Email template created (or use our starter template)
- PDF attachment template created
Step-by-Step Guide
Create the Email Template
Create an email template with these suggested variables:
| Variable | Type | Description |
|---|---|---|
invoiceNumber | string | Invoice number (e.g., “INV-2024-001”) |
customerName | string | Customer’s name |
companyName | string | Customer’s company name |
dueDate | string | Payment due date |
total | number | Invoice total |
items | array | Line items |
Example email content:
Hi {{customerName}},
Your invoice {{invoiceNumber}} for {{companyName}} is attached.
Amount Due: ${{total}}
Due Date: {{dueDate}}
Please find the detailed invoice attached to this email.
Thank you for your business!Create the PDF Invoice Template
Create a PDF template with the variables it needs. Both templates can use similar data structures for consistency.
Your PDF template might include:
- Company logo and address
- Invoice number and date
- Customer billing info
- Line items table with columns: Description, Quantity, Unit Price, Total
- Subtotal, tax, and total
- Payment terms and bank details
Send the Invoice Email
const response = await fetch('https://api.formamail.com/api/emails/send', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.FORMAMAIL_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
templateId: "invoice-email",
to: [{
email: customer.email,
name: customer.name
}],
variables: {
invoiceNumber: "INV-2024-001",
customerName: "John Smith",
companyName: "Acme Corp",
dueDate: "December 15, 2024",
items: [
{
description: "Professional Services - November",
quantity: 40,
unitPrice: 150,
total: 6000
},
{
description: "Software License - Annual",
quantity: 1,
unitPrice: 1200,
total: 1200
}
],
subtotal: 7200,
taxRate: 0.1,
tax: 720,
total: 7920
},
attachments: [{
attachmentTemplateId: "invoice-pdf",
filename: "invoice-INV-2024-001.pdf"
}]
})
});Full Code Example
Node.js / Express
const express = require('express');
const app = express();
app.post('/api/send-invoice', async (req, res) => {
const { customer, invoice } = req.body;
try {
const response = await fetch('https://api.formamail.com/api/emails/send', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.FORMAMAIL_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
templateId: "invoice-email",
to: [{ email: customer.email, name: customer.name }],
variables: {
invoiceNumber: invoice.number,
customerName: customer.name,
companyName: customer.company,
dueDate: invoice.dueDate,
items: invoice.lineItems,
subtotal: invoice.subtotal,
taxRate: invoice.taxRate,
tax: invoice.tax,
total: invoice.total
},
attachments: [{
attachmentTemplateId: "invoice-pdf",
filename: `invoice-${invoice.number}.pdf`
}]
})
});
const result = await response.json();
if (response.ok) {
res.json({
success: true,
emailId: result.emailId,
message: 'Invoice sent successfully'
});
} else {
res.status(400).json({
success: false,
error: result.message
});
}
} catch (error) {
res.status(500).json({
success: false,
error: 'Failed to send invoice'
});
}
});Python / FastAPI
from fastapi import FastAPI, HTTPException
import httpx
import os
app = FastAPI()
@app.post("/api/send-invoice")
async def send_invoice(customer: dict, invoice: dict):
async with httpx.AsyncClient() as client:
response = await client.post(
'https://api.formamail.com/api/emails/send',
headers={
'Authorization': f"Bearer {os.environ['FORMAMAIL_API_KEY']}",
'Content-Type': 'application/json'
},
json={
'templateId': 'invoice-email',
'to': [{'email': customer['email'], 'name': customer['name']}],
'variables': {
'invoiceNumber': invoice['number'],
'customerName': customer['name'],
'companyName': customer['company'],
'dueDate': invoice['due_date'],
'items': invoice['line_items'],
'subtotal': invoice['subtotal'],
'taxRate': invoice['tax_rate'],
'tax': invoice['tax'],
'total': invoice['total']
},
'attachments': [{
'attachmentTemplateId': 'invoice-pdf',
'filename': f"invoice-{invoice['number']}.pdf"
}]
}
)
if response.status_code != 200:
raise HTTPException(status_code=400, detail='Failed to send invoice')
return {'success': True, 'emailId': response.json()['emailId']}Template Tips
Line Items Loop
Use Handlebars {{#each}} to render line items in both email and PDF:
{{#each items}}
<tr>
<td>{{description}}</td>
<td>{{quantity}}</td>
<td>${{unitPrice}}</td>
<td>${{total}}</td>
</tr>
{{/each}}Number Formatting
Format currency values with calculated variables:
variables: {
total: 7920,
totalFormatted: "$7,920.00" // Pre-format in your code
}Conditional Content
Show different payment terms based on customer type:
{{#if isPreferred}}
Payment due within 45 days.
{{else}}
Payment due within 30 days.
{{/if}}