Convert the Email Body and Every Attachment into One Consolidated PDF in Power Automate: A 7-Step Outlook + PDF4me Workflow

The painful part of email-driven workflows is not the email, it is everything that comes with it. The body holds the context (who sent it, why, what to do), the attachments hold the artefacts (the invoice, the form, the signed contract), and storing them separately means future-you needs three clicks to reconstruct the message later. This walkthrough builds the exact pattern in Power Automate with PDF4me Convert to PDF, PDF4me Merge multiple PDF files, Outlook, Dropbox, and a single Apply to each loop. Seven flow actions. One incoming email lands. One consolidated PDF goes out, body first then attachment by attachment, timestamped and dropped into your archive folder automatically.
An Outlook When a new email arrives (V3) trigger fires the moment a message lands at [email protected]. An array variable named email opens up. PDF4me Convert to PDF turns the HTML body into a PDF first, the converted body is pushed onto the array as page 1. An Apply to each walks every attachment (two DOCX files in this run: 3Page.docx, Docx_2Pages.docx), converts each to PDF, and appends in turn. PDF4me Merge multiple PDF files consumes the whole array and emits one consolidated PDF. Dropbox Create file writes it back as merge-20260611-103323.pdf, a timestamped name that never collides. Body first, attachments in order, one PDF, one folder, audit-ready.
Why-Based Q&A
Why convert the body to PDF first? The body is the context: who sent it, why, what to do. Future-you reading the consolidated PDF wants page 1 to set the scene before the attachments roll in. Converting triggerOutputs()?['body/body'] (the HTML body) into a PDF first means the merge action sees the message itself as the lead document, not as a separate text dump.
Why one array variable for both body and attachments? The merge action wants a single ordered collection. Initialize once, push the body in step 4, push each converted attachment in step 5, and the array is exactly the document order you want. Two separate arrays would force a Compose action later to concatenate them, which is just more wiring for the same outcome.
Why base64ToBinary on every push? PDF4me Convert to PDF returns its output as a base64 string wrapped on $content. Outlook attachments arrive as base64 on contentBytes. PDF4me Merge multiple PDF files needs binary buffers. The same base64ToBinary(...) call bridges both sources, just pointed at different property names. Skip the conversion and the merge action errors with "invalid content".
Why a timestamped output name? Two emails from the same sender within an hour would collide if the filename was constant. concat('merge-', formatDateTime(utcNow(), 'yyyyMMdd-HHmmss'), '.pdf') produces names like merge-20260611-103323.pdf, lexicographically sortable, second-precision unique, and instantly readable as a UTC timestamp.
What You'll Get
Input: Any incoming email at the watched address (here, [email protected]) with one or more attachments. This walkthrough uses a short message body ("Hi, Hope you are doing well...") and two DOCX attachments (3Page.docx, Docx_2Pages.docx). Output: A single consolidated PDF dropped into /blog data/merge blog template/output/, named merge-YYYYMMDD-HHmmss.pdf. Page 1 is the body. Page 2 onwards is each attachment in attachment order, rendered through Aspose Words.
The incoming email

The flow watches the Outlook inbox at [email protected]. Once Gmail forwards or this address receives directly, the trigger fires.
The output Dropbox folder after two runs

Page 1 of the merged PDF

Page 1 is the converted email body. Page 2 onwards is the first attachment (3Page.docx). The second attachment (Docx_2Pages.docx) follows after that. One PDF, full message reconstructed.
What You Need
- Power Automate. Open Power Automate. Any plan with premium connectors (PDF4me Connect is premium).
- PDF4me API key. Get your API key. Connect it the first time you add a PDF4me action.
- Office 365 Outlook. For the When a new email arrives (V3) trigger and to read attachment
contentBytes. Any inbox that the connector can authenticate against works. - Dropbox (or SharePoint, OneDrive, Google Drive). For the final consolidated PDF.
- An email with attachments. The walkthrough uses two DOCX samples. 3Page.docx and Docx_2Pages.docx. Email them to the watched address to mirror every screenshot.
Grab the samples and the expected output first. Download both DOCX files, attach them to a quick email to your watched address, then publish the flow. Your first run should produce a merge-YYYYMMDD-HHmmss.pdf that mirrors the linked sample exactly (only the timestamp differs).
The Flow at a Glance
- Outlook: When a new email arrives (V3) (trigger).
- Initialize variable named
email(Array). - PDF4me: Convert to PDF (Body). Reads the HTML body, returns a PDF.
- Append to array variable with
base64ToBinaryon the converted body. - Apply to each on
triggerOutputs()?['body/attachments']:- PDF4me: Convert to PDF the attachment.
- Append to array variable with
base64ToBinaryon the converted PDF.
- PDF4me: Merge multiple PDF files into a single PDF file. Array in, one PDF out.
- Dropbox: Create file. File Name expression stamps the UTC timestamp.
Complete flow overview

Seven actions. The Apply to each card shows "1 of 2" because the test email had two attachments. PDF4me sits in the flow three times: convert body, convert attachment, merge everything.
Step 1: Outlook: When a New Email Arrives (V3)
Flow so far: trigger only.
- In Power Automate click Create, choose Automated cloud flow.
- Name the flow (e.g.
Email to Consolidated PDF), pick Office 365 Outlook: When a new email arrives (V3) as the trigger, click Create. - Connect your Office 365 mailbox.
- Expand Advanced parameters and Show all to reveal filtering options.
- Configure:
- To:
[email protected](filter so only mail addressed to this address triggers the flow) - Include Attachments:
Yes - Only with Attachments:
Yes
- To:
Trigger configuration

Tip. Only with Attachments Yes is what keeps the flow from firing on every internal notification, calendar invite, or reply. Combine with a To filter on a dedicated alias (e.g. [email protected]) for a clean intake address that only receives mail you actually want consolidated.
Step 2: Initialize Variable email
Flow so far: trigger plus Initialize variable.
Open an empty array to collect the body PDF and every attachment PDF.
- Click + New step, pick Initialize variable.
- Configure:
- Name:
email - Type:
Array - Value: leave blank
- Name:
Initialize variable configuration

Step 3: PDF4me: Convert to PDF (Body)
Flow so far: trigger plus Initialize variable plus Convert to PDF Body.
The Outlook trigger emits the message body as HTML on body/body. PDF4me Convert to PDF reads HTML directly, so the entire conversion is one action.
- Click + New step, search PDF4me, pick Convert to PDF.
- Rename the action to Convert to PDF Body so step 5's Convert to PDF action can have its own clean name later.
- Connect PDF4me Connect with your API key (first time only).
- Configure:
- File Content (expression, click
fx):triggerOutputs()?['body/body'] - File Name:
email-body.html
- File Content (expression, click
Convert to PDF Body configuration

The .html extension on the filename tells PDF4me which renderer to use. Send .docx, .xlsx, .png, or .jpg just as easily, the same action handles all of them.
Step 4: Append to Array Variable (Email Body)
Flow so far: trigger plus Initialize variable plus Convert to PDF Body plus Append (email body).
Push the converted body PDF onto the email array as page 1.
- Click + New step, pick Append to array variable.
- Rename the action to Append to array variable (email body) for clarity.
- Configure:
- Name:
email - Value (expression):
base64ToBinary(body('Convert_to_PDF_Body')?['$content'])
- Name:
Append email body configuration

Step 5: Apply to Each Attachment, Convert, and Append
Flow so far: trigger plus Initialize variable plus Convert to PDF Body plus Append (email body) plus Apply to each.
Loop over every attachment, convert each to PDF, and append in turn so the final merge respects attachment order.
Step 5a: Apply to each (pick the source)
- Click + New step, pick Apply to each.
- Configure:
- Select an output from previous steps (expression):
triggerOutputs()?['body/attachments']
- Select an output from previous steps (expression):

Step 5b: Convert to PDF (the attachment)
- Inside the loop click Add an action, pick PDF4me: Convert to PDF.
- Configure:
- File Content (expression):
base64ToBinary(items('Apply_to_each')?['contentBytes']) - File Name (dynamic content): pick name from the Apply to each current item
- File Content (expression):

The name dynamic-content token resolves at run time to items('Apply_to_each')?['name'], so each attachment is converted using its original filename (which carries the source extension and tells PDF4me which renderer to use).

Step 5c: Append to array variable (the converted attachment)
- Below Convert to PDF inside the same loop, Add an action, pick Append to array variable.
- Configure:
- Name:
email - Value (expression):
base64ToBinary(body('Convert_to_PDF')?['$content'])
- Name:

The two property names matter. Outlook attachment bytes live on contentBytes. PDF4me Convert to PDF output lives on $content. Both are base64. Keep the names straight when you paste the expressions and the loop just works.
Step 6: PDF4me: Merge Multiple PDF Files
Flow so far: trigger plus Initialize variable plus Convert to PDF Body plus Append (body) plus Apply to each plus Merge multiple PDFs.
The whole email array (body PDF first, then attachment PDFs in attachment order) goes into a single Merge call.
- Below the Apply to each loop click + New step, search PDF4me, pick Merge multiple PDF files into a single PDF file.
- Configure:
- Body/docContent: pick the
emailvariable token - Output File Name:
Email Attachment Merge Output.pdf
- Body/docContent: pick the
Merge action configuration

Step 7: Dropbox: Create File with a Timestamped Name
Flow so far: trigger plus Initialize variable plus Convert to PDF Body plus Append plus Apply to each plus Merge plus Create file.
Write the consolidated PDF to Dropbox with a UTC-timestamped filename so every run lands as a fresh, sortable file.
- Click + New step, pick Dropbox: Create file.
- Configure:
- Folder Path:
/blog data/merge blog template/output - File Name (expression, click
fx):concat('merge-', formatDateTime(utcNow(), 'yyyyMMdd-HHmmss'), '.pdf') - File Content: pick the File Content token from the Merge multiple PDFs action
- Folder Path:
File name expression

Final action with File Content mapped

Tip. Want one folder per sender domain? Replace the static Folder Path with concat('/inbox-pdfs/', split(triggerOutputs()?['body/from'], '@')[1], '/'). PDFs auto-route to subfolders like /inbox-pdfs/yourcompany.com/ based on the sender's domain.
Run the Flow and Verify
- Save the flow at the top right.
- Email a message with one or more attachments to the watched address (the walkthrough used
[email protected]). - Open Run history. The trigger should fire within seconds. Watch each action turn green: Convert to PDF Body takes about 10 seconds for a short HTML body, Apply to each runs in parallel by default and finishes both attachments in about 22 seconds, Merge multiple PDFs takes around 11 seconds.
- Open Dropbox at
/blog data/merge blog template/output/. A file namedmerge-YYYYMMDD-HHmmss.pdfis there. - Open the PDF. Page 1 is the body text. Page 2 onwards is each attachment, fully rendered, in attachment order.
What did you actually build? A zero-touch email-to-archive pipeline. Every message with attachments turns into one consolidated PDF, body first then attachments in order, timestamped so nothing collides, dropped into a shared folder your team or auditors can search. The same recipe handles two attachments or twenty without any change. Same recipe works in Make (Outlook trigger plus iterator over attachments plus PDF4me Merge) and Zapier (Email by Zapier or Outlook trigger plus Looping plus PDF4me Merge).
Common Variations You Can Add Without Rebuilding
endsWith(toLower(items('Apply_to_each')?['name']), '.pdf') or similar. Skips signatures and inline image attachments cleanly.body/body. Page 1 of the consolidated PDF now carries a header you can grep on later.PDF/A-2b after the merge. The archived consolidated PDF is now ISO 19005 compliant, fit for legal hold or regulator submission.Troubleshooting
One of the Append to array Value expressions is not wrapped in base64ToBinary(...). Each push (body and attachments) needs the conversion. Re-open both Append actions, switch to the expression editor, and confirm the expressions are base64ToBinary(body('Convert_to_PDF_Body')?['$content']) and base64ToBinary(body('Convert_to_PDF')?['$content']) verbatim.
The Convert to PDF Body action did not receive a real HTML body. Check the trigger's Include Attachments stayed Yes (without it the body sometimes arrives empty) and that File Content resolves to triggerOutputs()?['body/body'], not body/bodyPreview.
The trigger fired on a mail with no attachments because Only with Attachments is set to No. Either flip it to Yes, or wrap the Apply to each in a Condition that runs only when length(triggerOutputs()?['body/attachments']) is greater than zero.
The default Apply to each runs in parallel, which can scramble append order. Open the loop's Settings and set Concurrency Control Degree of parallelism to 1. The loop now runs sequentially and attachments land in the array in the exact order Outlook returned them.
Next Steps
The same seven-step pattern (trigger then init array then convert body then loop-convert-and-append then merge then save with a timestamp) works for any "email plus attachments to one PDF" automation. Ship it once and every incoming message becomes a searchable, sortable archive entry, automatically.