To convert CSV to HTML table markup for a Power Automate flow, run the CSV through a browser-based RFC 4180 parser, copy the resulting thead and tbody fragment, and drop it into a Compose or Variable action. Power Automate's built-in "Create HTML table" action accepts a JSON array rather than a raw CSV string, and the older "Convert CSV to HTML table" connector is listed as deprecated with no replacement guaranteed to match your schema. The CSV to HTML Table Converter takes comma-delimited text, lets you decide whether the first record is a header, and emits an HTML fragment that follows the WHATWG table model. Parsing, escaping, preview rendering, and clipboard access happen entirely in your current browser tab, so the CSV never leaves your machine and no Power Automate connector is invoked. Every cell is escaped for HTML text content before markup is assembled, so a CSV cell containing <script> or <img onerror> shows as literal text in the preview instead of becoming an active element on the page.

convert csv to html table power automate
Convert CSV to HTML Table for Power Automate: Safer Steps

Power Automate's Built-in CSV to HTML Path and Its Limits

Microsoft Power Automate ships two actions that look like CSV to HTML converters, but neither matches a parser-first workflow. The "Create HTML table" action in the Data Operations group takes a JSON array shaped like [{"col1":"row1","col2":"a"},{"col1":"row2","col2":"b"}] as its From input, applies a header row by default, and emits a fully styled HTML table wrapped in a div with inline CSS. If your trigger hands you raw CSV — for example an email attachment parsed with "Parse CSV" or a manual paste from a SharePoint library — you must first run Create HTML table on a JSON expression built from split, map, and compose steps, which adds latency and silently mangles any cell containing a comma inside quoted text.

Encodian's "Convert - Excel" connector and the older "Convert CSV to HTML table" action handle raw CSV more directly, but the Encodian route is a paid API call and the Convert CSV to HTML table action is marked deprecated on its documentation page. A deprecated action keeps working until the connector owner turns it off, and flows built on top of it then need to be migrated without a one-to-one replacement that preserves header scope, accessibility semantics, or responsive styling.

A browser-side parser fits this gap directly. The CSV to HTML Table Converter takes comma-delimited text, applies the documented RFC 4180 dialect rules, and emits a fragment you can paste straight into a Compose, a Variable, or an Office 365 Outlook "Send an email (V2)" IsHtml body field, then add the wrapper styling yourself. The escape happens once, on your machine, before the markup leaves the browser.

The Output: A Fragment, Not a Page

The output is a fragment, not a page. It contains a <table> root with one optional <thead> row of <th> cells followed by a <tbody> group of <tr> rows of <td> cells. There is no doctype, html, head, body, caption, CSS, JavaScript, ARIA description, sorting, filtering, pagination, or responsive wrapper inside that fragment. With the header option enabled, the first record becomes one thead row; with it disabled, every record becomes a td row in tbody. Empty middle and trailing cells are retained, and a leading UTF-8 BOM is stripped before parsing while any later U+FEFF stays as data.

Every cell is escaped for HTML text content before markup is assembled. Ampersands, angle brackets, quotes, and apostrophes become entities. A CSV cell that reads <script>alert(1)</script> arrives in the output as <td>&lt;script&gt;alert(1)&lt;/script&gt;</td>. The on-page preview is rendered separately through React text nodes and never uses dangerouslySetInnerHTML, which is why a malicious-looking cell stays as plain text on this page. Downstream applications must still place the copied fragment inside an HTML content context and enforce their own content security policy.

The parser does not trim cell text, infer numbers or dates, calculate formulas, merge cells, interpret comments, detect spreadsheet types, or repair malformed records. Every record must contain exactly the same number of fields as the first record; crossing a boundary returns an error with no partial or silently truncated table.

Convert CSV to HTML Table for a Power Automate Flow

  1. Pull the CSV body from your Power Automate trigger into a Variable or Compose action and copy the raw string — for example the Output of "When a new email arrives" parsed with "Parse CSV", or the Body of an HTTP request.
  2. Open the CSV to HTML Table Converter, paste the CSV string into the input area, and toggle the "first record contains column headings" option to match your source.
  3. Click Convert. The reported row count should equal the number of data records plus one if the header option is on, and the column count should match the field count of the first record. If the counts diverge, your CSV has an uneven row or an unclosed quote.
  4. Inspect both the safe preview and the generated source. A quoted cell containing a comma should appear in a single column; a doubled-quote like "" should decode to one literal " inside that cell.
  5. Click Copy HTML to grab the escaped fragment, then paste it into a Compose action in Power Automate named, for example, HtmlTable, and reference it from a downstream "Send an email (V2)" action's IsHtml body field.
  6. Wrap the pasted fragment in a containing div or table caption in the email expression, add the caption and scope attributes required by your audit standards, and test the email on a target mailbox to confirm rendering.

Putting the Fragment Into a Power Automate Run

The fragment has no wrapper, so Power Automate's email and approval actions need a small wrapping expression to render reliably. Inside a Compose or Set variable action you can build a string variable such as concat('<div><table border="1">', variables('HtmlTable'), '</table></div>'), then reference that variable in an Office 365 Outlook "Send an email (V2)" IsHtml body. The Outlook action filters script tags before rendering, so escaping at the parser side is sufficient; no CSP header is sent by Outlook, but the email client itself applies its own filtering.

For Microsoft Teams, paste the same string into a "Post adaptive card" or "Post message" action with HTML formatting, although Teams' HTML support is narrower than Outlook's and large tables may need to be split across multiple adaptive card columns. For approvals, paste the wrapped string into the Details field of a "Start and wait for approval" action, which renders limited HTML including tables. In each case the key point is that the parser produced escaped text once, so any cell containing markup shows as visible text rather than as a clickable element.

Hard limits of 500,000 input characters, 10,000 rows, 200 columns, 200,000 cells, and 5,000,000 output characters protect the parser. A Power Automate flow whose CSV exceeds any boundary returns a clear error rather than a truncated fragment, which lets you sample the file or chunk the body before re-running the conversion.

Parsing Rules That Keep Columns Aligned

The parser follows a deliberately narrow RFC 4180-style dialect. Comma is the only delimiter; semicolons, tabs, and pipes remain ordinary cell characters. CRLF is the canonical record ending, while standalone LF and CR are accepted as documented interoperability extensions for real producers. A final record ending is optional and does not create a phantom row. A quoted field can contain commas and record endings, and two double quotes inside a quoted field decode to one literal quote. A double quote appearing in the middle of an unquoted field is rejected, which is exactly what prevents the silent column shifts caused by splitting each line on commas.

Source featureBehaviorEffect on output
Comma inside a quoted fieldPreserved as literal cell textStays in the same column
Doubled quote "" inside a quoted fieldDecoded to one literal "Single character in the cell
Embedded CRLF inside a quoted fieldPreserved as a line break inside the cellRow count unchanged
Trailing record endingOptional, not requiredNo phantom trailing row
Unquoted field containing a "Rejected with an errorConversion blocked, no partial output
Leading U+FEFFTreated as a UTF-8 BOM and removedOther occurrences remain data
Uneven record widthRejected with an errorConversion blocked, no partial output

Adding Accessibility and Responsive Behavior

A syntactically valid table can still be inaccessible or unusable when it is extremely wide, lacks a caption, uses unclear headings, or depends on color alone. The fragment supplies the structural skeleton; the destination page supplies the semantics. The WHATWG HTML tables specification recommends a caption as the first child of a table, which screen readers announce before the column headers, and it recommends scope="col" on th cells when a header applies to its column.

For responsive behavior, a common pattern is to wrap the table in a div with overflow-x:auto so wide tables scroll horizontally on small viewports. For mobile-first designs, a transform that converts each row into a stacked definition list can be added with a small CSS rule and data-label attributes. Whatever the choice, the parser-generated fragment should be reviewed for clarity of headings, presence of a caption, and color-independent row striping before the email or page is sent to end users.

The end-to-end workflow for Power Automate is straightforward: pull the CSV string into a Variable, paste it into the CSV to HTML Table Converter, copy the escaped thead and tbody fragment, and drop it into a Compose action that an email or approval expression can read. The parser does the column alignment and the escaping; the destination adds the caption, the scope attributes, and the responsive wrapper. When the deprecated connector finally stops accepting flows, the same browser-side steps keep working because the dialect rules and the escape behavior live in the parser, not in the Power Automate runtime.

If you're weighing options, CSV to JSON Command Line vs Online: A Practical Comparison covers this in detail.