Power Automate Email to Excel: Auto-Save Outlook Emails

Last updated August 2026

Try it now: extract email data to Excel, CSV, or JSON

Convert your email files
No install

Connect a mailbox to pull .eml/.msg in bulk, or paste a raw email to test the converter now.

or paste an email to test
Output format
Columns to extract
Extract your own custom fields
Popular:

Create a free account to download. No credit card required.

The short answer

Build an automated cloud flow with the Outlook trigger When a new email arrives, then add the Excel Online (Business) action Add a row into a table, pointing at a workbook in OneDrive for Business or SharePoint. The Excel range has to be a real named table, not a plain block of cells, or the action will not see it. Then open the trigger's Settings, switch Concurrency Control on and set Degree of Parallelism to 1, otherwise two emails arriving in the same second will collide and you will lose rows.

Most people who search for this have already done the job by hand once. A shared mailbox collects order confirmations, or support requests, or supplier notifications, and somebody has been opening each message and typing the date, the sender and a couple of values into a spreadsheet. Power Automate can take that over, and for a straightforward log of what arrived it does the job well.

What follows is the flow that works, the four places it usually breaks, and an honest note about where a flow stops being the right tool.

How do I automatically save Outlook emails to Excel?

Six steps, and the whole thing takes about fifteen minutes the first time.

  1. Prepare the workbook first. Put it in OneDrive for Business or a SharePoint document library, not on your desktop. Add your header row, select it along with one empty row beneath, and use Format as Table. Give the table a name you will recognize. This step is the one people skip, and it is the reason the Excel action later shows an empty dropdown.
  2. Create the flow. In Power Automate, choose Create, then Automated cloud flow, and pick When a new email arrives from the Outlook connector as the trigger.
  3. Filter at the trigger, not later. The trigger has advanced options for folder, sender, subject filter and whether attachments are required. Narrowing here means the flow only runs on mail you actually want, which keeps your run history readable and your quota intact.
  4. Add the Excel action. New step, then Add a row into a table from Excel Online (Business). Choose the location, the document library, the file and the table.
  5. Map the columns. Each column in your table appears as a field. Fill them with dynamic content from the trigger: Received Time, From, Subject, Body.
  6. Fix concurrency before you go live. Select the trigger, open Settings, turn Concurrency Control on and set Degree of Parallelism to 1. Details on why in a moment.

Save it, then send yourself a test message. The flow fires shortly after the mail arrives rather than instantly, so give it a minute before deciding it is broken.

Why can Power Automate not find my Excel table?

Because the action only works with a formally defined Excel table, and a range of cells that merely looks like a table is not one. Select your data, use Format as Table on the Home ribbon, and the table appears in the dropdown after you reselect the file. A second cause is location: the Excel Online (Business) connector reads files in OneDrive for Business or SharePoint, so a workbook sitting on a local drive or in a personal consumer OneDrive will not be listed.

Why is my email body full of HTML tags in Excel?

Because Outlook hands the body to the flow as HTML, and Power Automate writes exactly what it is given. You get a cell of markup instead of the sentence you wanted.

There are two usual fixes. The lighter one is to add the Html to text action between the trigger and the Excel step, and map its output into the column instead of the raw Body. The heavier one is a chain of replace() expressions, which works for one known sender and becomes unmaintainable the moment a second sender formats their mail differently. If your goal is a readable log, Html to text is enough. If your goal is specific values pulled out of that body, neither fix helps much, which is the distinction the last section covers.

Why are rows missing when several emails arrive at once?

This is the failure that costs people a week, because it only shows up under load and the flow reports success. Microsoft documents it plainly in its own tutorial: receiving multiple emails at the same time can cause merge conflicts in Excel. Two runs open the same workbook, both write, and one write wins.

The documented mitigation is to make the connector handle one email at a time. Select the email arrives action, open Settings, set Concurrency Control to On, and set Degree of Parallelism to 1. Runs then queue instead of racing. It is slower, and on a busy mailbox that matters, but a slow row is better than a missing one.

If you are auditing a flow somebody else built and rows have gone astray, check this setting before you check anything else.

Should I use Add a row into a table or an Office Script?

Both are supported routes and they suit different jobs.

Route How it works Best for Watch out for
Add a row into a table Connector action writes one row per email, columns mapped from dynamic content A plain log: date, sender, subject, body Needs a named table; no formatting, no calculations, no cleanup
Run script (Office Scripts) Flow passes values into a TypeScript script that writes the row and can do more Tidying values, grouping threads, refreshing a PivotTable after each write You maintain code; needs Office Scripts availability on your license

Microsoft's own walkthrough of the script route is worth reading because of two details it flags. First, Power Automate should not use relative references such as getActiveWorksheet, so your worksheet and table need fixed, consistent names. Second, the script parameters only appear in the flow step after you select the script, which trips up nearly everyone the first time.

That tutorial also shows a small piece of real cleanup: the subject line arrives carrying the reply tag, so the sample script strips "Re: " and "RE: " to keep messages in one thread grouped together. It is a good illustration of the general shape of this work. The connector gives you raw values, and anything tidier is code you write and own.

Can Power Automate extract specific data from the email body into columns?

Up to a point, and the limits arrive quickly. If every message comes from one system in one fixed layout, you can slice values out with expressions such as split, indexOf and substring, or match them with a pattern. Plenty of teams run exactly that and it holds.

It stops holding in three situations. When the same information arrives from several senders who each format it differently, one set of expressions cannot cover them all. When a supplier renames a heading or reorders two lines, the expression keeps running and returns the wrong text rather than failing loudly, so bad values land in the spreadsheet quietly. And when the values sit in an HTML table in the body, you are into converting the string to XML and running XPath over it, which is a real technique but not one most teams want in a business process they need to trust.

The tell is maintenance. If you find yourself editing the flow every time a sender changes a template, the expressions have become the job rather than the tool. Our longer walkthrough of how to parse an email body in Power Automate covers the expression approach properly, and the Power Automate parse email body page shows the version where the parsing happens outside the flow and Power Automate just moves the finished fields.

What does it cost to run this?

The connectors used above are standard, so for most Microsoft 365 business plans this is included rather than an extra purchase, and Office Scripts availability depends on your specific licensing and platform. What actually grows is quieter than a line on an invoice: flow runs consume your quota, and a team that builds twenty of these ends up with twenty things to maintain, each owned by whoever happened to build it. Before that spreads across a department it is worth knowing what your software and cloud spend is really doing month to month, because automation sprawl tends to show up there long before anyone notices it.

When a flow is the right answer, and when a parser is

Use Power Automate when you want a log. One row per message, standard fields, arriving in a workbook your team already opens. It is native to Microsoft 365, there is nothing extra to buy, and the whole thing is auditable by anyone with access to the flow.

Use a parser when you want the data inside the message. If the value you need is an order number in the third paragraph, a total in an HTML table, or a delivery date written five different ways by five different suppliers, you want a tool whose job is reading varied layouts, not a chain of string functions you maintain by hand.

What you need Better tool
Log every message that arrives, with standard fieldsPower Automate flow
Named values pulled out of varied message bodiesEmail parser
Rows of an HTML table in the body, as spreadsheet rowsEmail parser
A one-off export of a folder you already haveDirect export, no flow needed
Values printed inside a PDF attachmentA document extraction tool

The two approaches also combine well. A common setup is to let a parser turn each message into named fields, then keep a short Power Automate flow whose only job is writing those finished fields into the workbook, which sidesteps the HTML problem and most of the expression maintenance at once.

Worth being straight about one limit on our side: MailParse reads the message body and HTML tables and records each attachment by filename, type and size, but it does not read the data printed inside a PDF or spreadsheet attachment. When that is where your numbers live, extract the document separately and merge the result.

If you only need a one-time export

Not every version of this problem needs a flow at all. If you just want the last two years of a folder in a spreadsheet once, building an automated trigger is the long way round, because a trigger only ever fires on mail that arrives after you switch it on. Exporting Outlook emails to Excel directly handles the backlog in one pass, and extracting data from Outlook emails covers the case where you want named fields out of that same history rather than a flat dump.

Decide which of the three you are actually doing before you build anything. A backlog is an export. An ongoing log is a flow. Named values out of messy mail is a parser. Most of the frustration with this task comes from picking the first tool that appeared in search results and then bending it around a job it was never shaped for.