Automated Personalized PDF Generation and Email Delivery with n8n and PDF.co
This tutorial explains how to generate personalized PDF documents from Google Sheets data and email them automatically using n8n and PDF.co.
The completed workflow will:
- Watch a Google Sheet for new campaign records.
- Generate a personalized PDF from a reusable HTML template.
- Add a company logo to the PDF.
- Download the finished PDF into n8n.
- Email it to the recipient as an attachment.
The workflow follows this structure:
Google Sheets Trigger → PDF.co: Generate PDF from HTML Template → PDF.co: Add Logo → HTTP Request: Download PDF → Send Email
Prerequisites
Before starting, prepare the following:
- An active n8n instance
- A PDF.co account and API key
- A Google account connected to n8n
- A Google Sheet containing the personalization data
- A PDF.co HTML template
- A publicly accessible company-logo URL or a logo uploaded to PDF.co
- An SMTP or Gmail credential configured in n8n
Security reminder: Store API keys, email passwords, OAuth connections, and SMTP credentials in n8n’s credential manager. Never paste credentials directly into workflow fields that may be included in exported JSON files.
IN THIS TUTORIAL
Step 1: Install the PDF.co Node
Install the PDF.co node before building the workflow.
In n8n 1.94.0 or later:
- Open a workflow.
- Open the node-selection panel.
- Search for PDF.co.
- Select the PDF.co node.
- Choose Install Node.
Alternatively:
- Go to Settings → Community Nodes.
- Search for:
n8n-nodes-pdfco - Install the package.
- Reload the n8n editor.
For additional installation information, see the PDF.co n8n setup guide.
Step 2: Prepare the Google Sheet
Create a Google Sheet containing the information required by your HTML template and email message.
A sample sheet could contain these columns:
customer_name
customer_email
campaign_title
campaign_subtitle
brand_color
hero_image
headline
body_text
cta_link
cta_text
footer_text
year
company_nameAdd one test row with sample values.
For example:
customer_name: Jordan Smith
customer_email: jordan@example.com
campaign_title: Summer Product Launch
campaign_subtitle: New tools for growing teams
brand_color: #2563EB
hero_image: https://example.com/images/product-launch.jpg
headline: Work faster with our newest features
body_text: Discover the latest improvements to our platform.
cta_link: https://example.com/get-started
cta_text: Get Started
footer_text: You are receiving this document as an Acme customer.
year: 2026
company_name: Acme CorporationThe column names should match the data properties expected by the PDF.co HTML template.
Step 3: Create the HTML Template
Sign in to PDF.co and open the HTML to PDF Templates section:
https://app.pdf.co/templates/html
Create a new template or adapt an existing one.
PDF.co supports Mustache and Handlebars placeholders. For example:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{campaign_title}}</title>
<style>
body {
margin: 0;
padding: 40px;
font-family: Arial, sans-serif;
color: #222;
}
.logo-space {
height: 80px;
}
.hero {
width: 100%;
max-height: 300px;
object-fit: cover;
}
.headline {
color: {{brand_color}};
font-size: 28px;
margin-top: 24px;
}
.button {
display: inline-block;
margin-top: 20px;
padding: 12px 20px;
color: white;
background-color: {{brand_color}};
text-decoration: none;
border-radius: 4px;
}
.footer {
margin-top: 40px;
padding-top: 16px;
border-top: 1px solid #ddd;
color: #666;
font-size: 12px;
}
</style>
</head>
<body>
<div class="logo-space"></div>
<h1>{{campaign_title}}</h1>
<p>{{campaign_subtitle}}</p>
<img class="hero" src="{{hero_image}}" alt="Campaign image">
<h2 class="headline">{{headline}}</h2>
<p>Hello {{customer_name}},</p>
<p>{{body_text}}</p>
<a class="button" href="{{cta_link}}">
{{cta_text}}
</a>
<div class="footer">
<p>{{footer_text}}</p>
<p>© {{year}} {{company_name}}</p>
</div>
</body>
</html>The empty logo-space section reserves space for the company logo that will be added in a later PDF.co step.
Save the template and copy its template ID.
The template ID belongs to your PDF.co account. Do not copy an ID from another tutorial or user’s account.
Step 4: Add the Google Sheets Trigger
Create a new workflow in n8n.
Add a Google Sheets Trigger node and configure it:
- Event: Row Added
- Document: Select your campaign spreadsheet.
- Sheet: Select the sheet containing the campaign data.
- Polling Interval: Select the desired interval.
Connect your Google account through n8n’s credential manager.
Test the node and select the sample row. Confirm that the output contains all the required fields, including customer_name and customer_email.
Step 5: Connect PDF.co to n8n
Add a PDF.co API node after the Google Sheets Trigger.
Create a PDF.co credential using either the available API-key or OAuth2 authentication option.
If using an API key:
- Copy the key from your PDF.co dashboard.
- Create a PDF.co credential in n8n.
- Store the key in the credential.
- Select that credential in the PDF.co node.
Do not place the API key in a normal workflow field or HTTP header.
Step 6: Generate the Personalized PDF
Name the first PDF.co node:
Generate Personalized PDFConfigure it as follows:
- Action: URL/HTML to PDF
- Convert Type: HTML Template to PDF
- Template ID: Enter your saved HTML template ID.
- Template Data: Use an n8n expression that creates a JSON string from the Google Sheets values.
Use:
={{ JSON.stringify({
campaign_title: $json.campaign_title,
campaign_subtitle: $json.campaign_subtitle,
brand_color: $json.brand_color,
hero_image: $json.hero_image,
headline: $json.headline,
body_text: $json.body_text,
cta_link: $json.cta_link,
cta_text: $json.cta_text,
footer_text: $json.footer_text,
year: $json.year,
company_name: $json.company_name,
customer_name: $json.customer_name
}) }}Set the output filename to something unique:
={{ $json.campaign_title + "-" + $json.customer_name + ".pdf" }}If needed, replace characters that are unsuitable for filenames before using values from the spreadsheet.
Configure additional HTML-to-PDF options as required:
- Orientation: Portrait
- Paper Size: Letter or A4
- Print Background: Enabled
- Margins: Appropriate for your template
- Async: Use the default or recommended setting for the document size
Run the node.
A successful result should contain a temporary URL for the generated PDF:
{
"url": "https://pdf-temp-files.s3.amazonaws.com/..."
}Open the URL and verify that the Google Sheets values replaced the HTML placeholders.
Step 7: Prepare the Logo
The logo must be accessible to PDF.co.
You can use either:
- A publicly accessible HTTPS image URL; or
- A
filetoken://URL for an image uploaded to PDF.co storage
Do not use a file token copied from another PDF.co account. File tokens are account-specific.
For a reusable company logo, upload the image to your own PDF.co account and copy its resulting file-token URL.
The logo should use a web-compatible image format such as PNG or JPG. A transparent PNG is often best for company branding.
Step 8: Add the Logo to the PDF
Add another PDF.co API node after Generate Personalized PDF.
Name it:
Add Company LogoChoose the action:
Add Text/Images to PDFConfigure the source PDF URL:
={{ $json.url }}Add an image and configure it with values similar to:
{
"imageUrl": "https://example.com/images/company-logo.png",
"x": 20,
"y": 20,
"width": 180,
"height": 50
}Replace the example URL with your own public logo URL or PDF.co file token.
The appropriate coordinates depend on the HTML template and page size. Use PDF.co’s PDF Edit/Add Helper to determine the correct X and Y coordinates.
PDF page coordinates begin from the upper-left area of the page in the helper. Test the logo’s position and dimensions until it fits the reserved area without covering the campaign content.
Run the node.
A successful result should contain a new PDF URL. Open it and confirm that the logo appears in the intended position.
Step 9: Download the Finished PDF into n8n
The PDF.co result is a temporary URL. To attach the PDF using n8n’s email node, first download it as binary file data.
Add an HTTP Request node after Add Company Logo and name it:
Download Finished PDFConfigure it:
- Method: GET
- URL:
={{ $json.url }}- Response Format: File
- Binary Property:
data
Run the node.
A successful result will contain a Binary section with a data property.
If the PDF appears as text in the JSON output, change the HTTP Request response format to File.
Step 10: Configure Email Credentials
Add a Send Email node after Download Finished PDF.
Create or select an SMTP credential in n8n.
For Gmail, use an approved Gmail connection method or an app password where required. Store the app password in the n8n credential—not in the workflow body.
Depending on the mail provider, the credential may require:
- SMTP host
- SMTP port
- Username
- Password or app password
- SSL/TLS settings
Test the credential before sending the personalized document.
Step 11: Configure the Email
Configure the Send Email node.
Recipient
Map the recipient from the Google Sheets Trigger:
={{ $('Google Sheets Trigger').item.json.customer_email }}Subject
Use a personalized subject:
={{ "Your " + $('Google Sheets Trigger').item.json.campaign_title + " document" }}Message
Use either plain text or HTML.
Example HTML message:
<p>
Hi {{ $('Google Sheets Trigger').item.json.customer_name }},
</p>
<p>
Please find your personalized campaign document for
<strong>{{ $('Google Sheets Trigger').item.json.campaign_subtitle }}</strong>
attached.
</p>
<p>
If you have any questions, please contact our team.
</p>
<p>
Best regards,<br>
{{ $('Google Sheets Trigger').item.json.company_name }} Marketing Team
</p>If the field expects one n8n expression rather than mixed text and expressions, use:
={{
`<p>Hi ${$('Google Sheets Trigger').item.json.customer_name},</p>
<p>Please find your personalized campaign document for
<strong>${$('Google Sheets Trigger').item.json.campaign_subtitle}</strong>
attached.</p>
<p>If you have any questions, please contact our team.</p>
<p>Best regards,<br>
${$('Google Sheets Trigger').item.json.company_name} Marketing Team</p>`
}}Attachment
Attach the binary property:
dataThis is the PDF downloaded by the previous HTTP Request node.
Step 12: Test the Complete Workflow
Before activating the workflow, use a test recipient address that you control.
Run the workflow and confirm that:
- The Google Sheets Trigger retrieves the new row.
- PDF.co generates the PDF from the correct template.
- Every HTML placeholder is replaced.
- The hero image loads correctly.
- The company logo appears in the reserved area.
- The finished PDF is downloaded as
binary.data. - The email is sent to the intended test recipient.
- The PDF is included as an attachment.
- The attachment opens successfully.
Do not activate the workflow until you have verified the recipient mapping. An incorrect mapping could send personalized documents to the wrong recipients.
Step 13: Activate the Workflow
Once testing is complete, activate the workflow.
Each new Google Sheets row will now trigger the following process:
New spreadsheet row
→ Personalized PDF generated
→ Company logo added
→ Finished PDF downloaded
→ Email sent with PDF attachmentStep 14: Troubleshooting
PDF.co Does Not Appear in n8n
Install the PDF.co node before adding it to the workflow:
n8n-nodes-pdfco
Reload n8n after installation.
The Template Cannot Be Found
Confirm that the template ID belongs to the same PDF.co account used by the n8n credential.
Placeholders Remain in the PDF
Make sure the Google Sheets column names, JSON property names, and HTML placeholders match exactly.
For example:
customer_name
must correspond to:
{{customer_name}}
Template Data Is Rejected
Make sure the Template Data field receives a valid JSON string. Use JSON.stringify() in the n8n expression.
The Logo Does Not Appear
Confirm that:
- The image URL is publicly accessible; or
- The PDF.co file token belongs to your account
- The image format is supported
- The coordinates place it inside the page
- The width and height are greater than zero
The Logo Covers Other Content
Increase the empty space at the top of the HTML template or adjust the image coordinates and size.
The Email Has No Attachment
Confirm that:
- The HTTP Request node uses Response Format: File.
- The binary output property is
data. - The Send Email node attaches binary property
data.
The Wrong Person Receives the Email
Check the recipient expression and test with controlled data before activating the workflow.
The PDF.co URL Has Expired
PDF.co output links are temporary. Download the finished PDF immediately within the same workflow rather than storing its URL for later use.
You have created an automated workflow that converts Google Sheets records into personalized PDF documents and emails them to their intended recipients.
PDF.co generates the document from a reusable HTML template and adds the company logo. n8n handles the spreadsheet trigger, downloads the finished PDF, stores email credentials securely, and sends the document as an attachment.
This structure can be expanded to support invoices, proposals, certificates, campaign documents, customer reports, and other personalized PDFs.
Built something amazing? Share your workflow and tag us @pdfdotco — we’d love to feature your automation!
Related Tutorials


