Compress Large PDFs for Email Attachments with Node.js
You've built a great invoicing system. It generates beautiful PDF invoices with company logos and product images. There's just one problem: the files are 8MB each, and Gmail rejects attachments over 25MB.
Even when emails go through, large attachments frustrate users on slow connections. They also eat up inbox storage and often get blocked by corporate email filters.
The fix is simple: compress PDFs before sending. A good compression can reduce file sizes by 50-90% without visible quality loss, especially for image-heavy documents.
Quick Example
const axios = require('axios');
const API_TOKEN = 'YOUR_API_TOKEN';
const API_URL = 'https://apdf.io/api/pdf/file/compress';
async function compressPDF(pdfUrl) {
const response = await axios.post(API_URL, {
file: pdfUrl
}, {
headers: {
'Authorization': `Bearer ${API_TOKEN}`,
'Content-Type': 'application/json',
'Accept': 'application/json'
}
});
return response.data;
}
// Usage
compressPDF('https://example.com/large-invoice.pdf')
.then(result => {
console.log(`Original: ${result.size_original} bytes`);
console.log(`Compressed: ${result.size_compressed} bytes`);
console.log(`Download: ${result.file}`);
});
The API returns the compressed file URL along with the original and new sizes so you can see the savings.
Real-World Scenario: Email Invoice System
You're building an e-commerce backend that sends order confirmations with PDF invoices attached. Before sending, you need to compress the PDF to ensure deliverability.
const axios = require('axios');
const nodemailer = require('nodemailer');
const API_TOKEN = 'YOUR_API_TOKEN';
const COMPRESS_URL = 'https://apdf.io/api/pdf/file/compress';
const MAX_ATTACHMENT_SIZE = 10 * 1024 * 1024; // 10MB limit
async function compressPDF(pdfUrl) {
const response = await axios.post(COMPRESS_URL, {
file: pdfUrl
}, {
headers: {
'Authorization': `Bearer ${API_TOKEN}`,
'Content-Type': 'application/json',
'Accept': 'application/json'
}
});
return response.data;
}
async function downloadPDF(url) {
const response = await axios.get(url, { responseType: 'arraybuffer' });
return Buffer.from(response.data);
}
async function sendInvoiceEmail(customerEmail, invoicePdfUrl, orderNumber) {
console.log(`Processing invoice for order ${orderNumber}...`);
// Step 1: Compress the PDF
const compressed = await compressPDF(invoicePdfUrl);
const savings = Math.round((1 - compressed.size_compressed / compressed.size_original) * 100);
console.log(`Compressed: ${savings}% smaller`);
// Step 2: Check if it's small enough for email
if (compressed.size_compressed > MAX_ATTACHMENT_SIZE) {
throw new Error('PDF still too large after compression');
}
// Step 3: Download the compressed PDF
const pdfBuffer = await downloadPDF(compressed.file);
// Step 4: Send email with attachment
const transporter = nodemailer.createTransport({
host: 'smtp.example.com',
port: 587,
auth: {
user: 'invoices@example.com',
pass: 'your-password'
}
});
await transporter.sendMail({
from: 'invoices@example.com',
to: customerEmail,
subject: `Your Invoice for Order #${orderNumber}`,
text: `Thank you for your order! Please find your invoice attached.`,
attachments: [{
filename: `invoice-${orderNumber}.pdf`,
content: pdfBuffer
}]
});
console.log(`Invoice sent to ${customerEmail}`);
}
// Example usage
sendInvoiceEmail(
'customer@example.com',
'https://your-storage.com/invoices/order-12345.pdf',
'12345'
).catch(console.error);
Batch Compression for Storage Optimization
If you're storing many PDFs, compressing them before upload saves significant storage costs. Here's a script to process multiple files:
const axios = require('axios');
const API_TOKEN = 'YOUR_API_TOKEN';
const API_URL = 'https://apdf.io/api/pdf/file/compress';
async function compressBatch(pdfUrls) {
const results = [];
for (const url of pdfUrls) {
try {
console.log(`Compressing: ${url}`);
const response = await axios.post(API_URL, {
file: url
}, {
headers: {
'Authorization': `Bearer ${API_TOKEN}`,
'Content-Type': 'application/json',
'Accept': 'application/json'
}
});
const data = response.data;
const savings = Math.round((1 - data.size_compressed / data.size_original) * 100);
results.push({
original: url,
compressed: data.file,
originalSize: data.size_original,
compressedSize: data.size_compressed,
savings: `${savings}%`
});
console.log(` -> Reduced by ${savings}%`);
// Rate limiting pause
await new Promise(resolve => setTimeout(resolve, 500));
} catch (error) {
console.error(` -> Failed: ${error.message}`);
results.push({ original: url, error: error.message });
}
}
return results;
}
// Process files
const files = [
'https://your-storage.com/reports/q1-2025.pdf',
'https://your-storage.com/reports/q2-2025.pdf',
'https://your-storage.com/reports/q3-2025.pdf'
];
compressBatch(files).then(results => {
console.log('\\nSummary:');
console.table(results);
});
When Compression Works Best
PDF compression is most effective for:
- Image-heavy documents: Invoices with logos, brochures, photo albums (50-90% reduction)
- Scanned documents: Often contain unoptimized images (40-70% reduction)
- Reports with charts: Embedded images can be optimized (30-60% reduction)
Text-only PDFs are usually already small and won't compress much further.
Next Steps
Now that you can compress PDFs, consider these related features:
- Check file info first: Use the Metadata Read endpoint to check file size before deciding whether to compress.
- Merge then compress: If you're combining multiple PDFs with the Merge endpoint, compress the result for optimal file size.