Automation & Cloud

Power Automate CSV to Teams: Automate P1/P2 ServiceNow Incident Alerts

In IT operations, incident information is often exported from ServiceNow or another ITSM platform as a CSV file and sent through email. Learn how to parse CSV attachments and trigger automated Teams notifications for High and Critical incidents.

Published: July 29, 2026 Read time: 15 minutes By: ChaitZ

About the Author

Chaitanya is the founder of Cyvora Studio. He documents real-world experiences with cloud automation, incident workflows, and developer tools.

What We Are Building

In IT operations, the traditional process of managing email incident exports is simple but repetitive:

  1. Receive the incident email.
  2. Open the CSV attachment.
  3. Find high-priority incidents.
  4. Read the incident details.
  5. Copy the relevant information.
  6. Open Microsoft Teams.
  7. Send the incident information to the operations team.

This is exactly the type of repetitive process that Microsoft Power Automate can automate. In this tutorial, we will build a Power Automate workflow that reads a CSV attachment from an email, converts it into text, parses the incident information, identifies High and Critical incidents, and automatically sends the relevant details to Microsoft Teams.

The final automation follows this architecture:

Outlook Email
     │
     ▼
CSV Attachment
     │
     ▼
Power Automate
     │
     ├── Convert Base64 → Text
     │
     ├── Clean CSV Content
     │
     ├── Split CSV into Rows
     │
     ├── Skip Header
     │
     ├── Split Rows into Columns
     │
     ├── Check Incident Priority
     │
     └── Filter High/Critical Incidents
                 │
                 ▼
        Microsoft Teams Alert

What is required

  • An Outlook mailbox trigger that watches the correct scheduled email folder.
  • Attachment handling that confirms the incoming file is a CSV before processing.
  • A cleanup step to normalize line breaks, carriage returns, and escaped characters.
  • A row and column parsing process to convert the CSV into useful values for logic checks.
  • A priority rule, such as High or Critical, that decides when a Teams notification is sent.
  • A Teams message action that posts only the relevant incident details.

What is good in this pattern

This design is strong because it uses the email as a lightweight event source, keeps the flow reusable, filters noise early, and limits Teams notifications to only the records that actually matter. The logic is simple to understand, easy to troubleshoot, and scalable for recurring report-based alerts.

Full Flow Visualization

Below is a visual representation of the entire automation flow:

Full Flow Visualization

The result is an automated incident notification system. Instead of manually monitoring a CSV report, the operations team receives the important incidents directly in Teams.

Why Automate CSV Incident Processing?

Incident management often involves repetitive data-processing tasks. For example, an operations team may receive a CSV containing hundreds of incidents, while only a small number require immediate attention.

A human operator might have to search for:

Priority = High
Priority = Critical

Power Automate can perform this filtering automatically.

Manual vs. Automated Process

Manual Process Automated Process
Receive email Receive email
Open CSV & search for P1/P2 Power Automate processes CSV automatically
Copy details & open Teams High/Critical incident detected by flow
Manually post message Instant Microsoft Teams notification sent

⚡ Operational Impact

Automating this flow reduces manual effort and shortens the time between report arrival, incident detection, and operational team notification. This can contribute to faster acknowledgement and resolution, but the flow itself does not prove an MTTR reduction.

Prerequisites

To build a similar workflow, you will need:

  • Microsoft Power Automate
  • Microsoft Outlook / Microsoft 365
  • Microsoft Teams
  • A CSV file containing incident information
  • A consistent CSV structure
  • Access to create Power Automate flows

For this example, assume that the CSV contains incident fields such as:

Incident,Priority,Short Description,Assignment Group,Assigned To,Caller,Created,Category,Sub Category,Location,Description

Step 1: Trigger the Power Automate Flow

Start with the Outlook trigger: When a new email arrives (V3). Configure the trigger so that only relevant emails are processed.

  • Email folder (e.g. Inbox / Incidents)
  • Subject filter (e.g. SNOW | NEW P1/P2 INCIDENT)
  • Include Attachments: Yes
Power Automate Outlook trigger, attachment loop, and CSV condition
Step 1–2: Outlook trigger, attachment loop, and CSV-file validation.

Why use a subject filter? Without filtering, every email arriving in the monitored mailbox could trigger the flow. A subject filter reduces unnecessary executions and saves flow run quotas.

Step 2: Process Email Attachments

An email can contain multiple attachments. Therefore, the flow uses an Apply to each action to process each attachment individually and verify if it has a .csv extension.

Expression to check for CSV files:

endsWith(items('Apply_to_each')?['name'], '.csv')

Recommended branch behavior: if the attachment is not a CSV, leave the No branch with no processing action. Avoid using Terminate here, because terminating the flow can stop processing other attachments in the same email.

Step 3: Convert the CSV Attachment from Base64 to Text

This is one of the most important steps when working with email attachments in Power Automate. Attachment content is initially provided as Base64-encoded binary data.

Use a Compose action with the following expression:

base64ToString(item()?['contentBytes'])
Power Automate CSV conversion and cleanup Compose actions
Steps 3–8: Converting the attachment to text, normalizing line endings, splitting rows, and skipping the header.

Step 4: Clean the CSV Content

CSV files exported from enterprise systems can contain Windows-style line endings. Normalize \r\n to \n and remove any remaining carriage returns before splitting the file into rows.

replace(replace(outputs('CSV_Text'), decodeUriComponent('%0D%0A'), decodeUriComponent('%0A')), decodeUriComponent('%0D'), '')

decodeUriComponent('%0A') represents a line-feed character and decodeUriComponent('%0D') represents a carriage return.

Step 5: Handle Windows Line Breaks

Windows systems use \r\n (Carriage Return + Line Feed). Strip out \r using:

replace(outputs('Clean_CSV_Text'), decodeUriComponent('%0D'), '')

Step 6: Split the CSV into Rows

Split the normalized string at every newline character to generate an array of rows:

split(outputs('Remove_CR'), decodeUriComponent('%0A'))

Optional: Count the CSV Rows for Testing

During testing, you can verify the total number of parsed lines by calling:

length(outputs('CSV_Lines'))

Step 8: Skip the CSV Header

The first item in the row array represents column headers (e.g. Incident,Priority...). Skip the first item using:

skip(outputs('CSV_Lines'), 1)

Optional: Inspect the First Data Row

During development, you can inspect the first actual incident row without looping by combining first() and skip():

first(skip(outputs('CSV_Lines'), 1))

Step 10: Ignore Empty Rows

Check that trailing blank lines or spaces are ignored inside the loop condition. If the condition is false, use an empty/no-op branch so the current iteration simply moves on:

greater(length(trim(item())), 0)
Power Automate row processing and empty-row condition
Steps 10–11: Processing each CSV row, ignoring empty rows, and preparing columns for priority checks.

Step 11: Split Each Incident into Columns

Inside the row processing loop, the example flow removes simple quote/backslash artifacts and then splits the row by commas:

split(replace(replace(item(), '"', ''), '\\', ''), ',')

Step 12: Access Individual CSV Columns

The example CSV has 11 fields, so the zero-based indexes run from 0 through 10. Keep this mapping aligned with the actual export schema:

Index Expression Target CSV Field
outputs('Cols')[0]Incident
outputs('Cols')[1]Priority
outputs('Cols')[2]Short Description
outputs('Cols')[3]Assignment Group
outputs('Cols')[4]Assigned To
outputs('Cols')[5]Caller
outputs('Cols')[6]Created
outputs('Cols')[7]Category
outputs('Cols')[8]Sub Category
outputs('Cols')[9]Location
outputs('Cols')[10]Description

Step 13: Filter High and Critical Incidents

Filter only High and Critical incidents using an or() and contains() condition on column index 1. If the condition is false, use a no-op branch rather than terminating the flow:

or(
    contains(outputs('Cols')[1], 'High'),
    contains(outputs('Cols')[1], 'Critical')
)

In this example, High and Critical are treated as the organization's P2/P1-style alert levels. ServiceNow priority labels vary by implementation, so change the condition to match the exact values used in your export.

Power Automate split columns and High Critical priority condition
Steps 11–13: Splitting columns and filtering for High or Critical priority.

Step 14: Send the Incident to Microsoft Teams

Use the Teams connector action: Post message in a chat or channel. Format the body using extracted column fields.

Power Automate Post message in a chat or channel Teams action
Step 14: Configuring the Teams action to post the selected incident fields.

Example Microsoft Teams Alert

When triggered, the operations channel receives a formatted notification:

🚨 NEW P1 / P2 INCIDENT

Incident: INC[Number]
Priority: Critical
Short Description: Demo Short Description
Assignment Group: Infrastructure Operations
Assigned To: Engineer A
Caller: User A
Created: [Created Date]
Category: Infrastructure
Sub Category: Server
Location: Data Center
Description: Demo Description

Complete Power Automate Workflow

Here is the complete control flow summary for the entire solution:

┌──────────────────────────────┐
│      New Email Arrives       │
│      Outlook Trigger         │
└──────────────┬───────────────┘
               │
               ▼
┌──────────────────────────────┐
│      Get Attachments         │
└──────────────┬───────────────┘
               │
               ▼
┌──────────────────────────────┐
│   Loop Through Attachments   │
└──────────────┬───────────────┘
               │
               ▼
          Is it CSV?
          /         \
        No           Yes
        │             │
        ▼             ▼
      Ignore     Base64 → Text
                      │
                      ▼
                Clean CSV Text
                      │
                      ▼
                Split into Rows
                      │
                      ▼
                 Skip Header
                      │
                      ▼
              Process Each Row
                      │
                      ▼
                 Empty Row?
                  /      \
                Yes       No
                │          │
                ▼          ▼
              Ignore   Split Columns
                            │
                            ▼
                      Check Priority
                       /          \
                     Low       High/Critical
                      │             │
                      ▼             ▼
                   Ignore     Teams Message

Key Power Automate Expressions

Function Purpose
base64ToString() Converts Base64 attachment data to readable text
replace() Replaces unwanted characters or formatting
decodeUriComponent() Generates characters such as line breaks (%0A, %0D)
split() Splits text into rows or columns
skip() Skips the CSV header row
first() Retrieves the first item from an array
length() Counts characters or array items
trim() Removes leading/trailing whitespace
endsWith() Checks whether a filename ends with .csv
contains() Checks whether text contains a specific value
or() Combines multiple logical conditions
greater() Compares numeric values

Common Problems & Troubleshooting

CSV attachment isn't readable

Check that the Outlook trigger includes attachments and that the correct attachment content bytes are passed to base64ToString().

CSV rows aren't splitting correctly

Check the line endings. Windows uses \r\n rather than just \n. Strip %0D using replace() before splitting.

Header is being processed as an incident

Ensure the array passed to your loop uses skip(outputs('CSV_Lines'), 1).

Blank Teams messages are being generated

Add a condition checking greater(length(trim(item())), 0) to filter out trailing empty lines.

Incorrect fields appear in Teams

Verify positional column index mapping if the upstream CSV schema was altered.

Important Limitations

1. CSV Is Not the Same as Excel

A CSV file is unformatted plain text with delimiters, whereas .xlsx files are zip-compressed XML workbooks. This tutorial parses plain text. For Excel files, use the native Power Automate Excel Online connector.

2. Commas Inside Fields

If a field value contains commas (e.g. "Server down, impact high"), a plain split(item(), ',') will split inside the field. The approach in this tutorial is therefore best for simple, predictable CSV exports. It is not a full RFC-compliant CSV parser and can also require additional handling for embedded line breaks or complex escaped quotes.

How This Automation Helps IT Operations

  • Incident Alerting: Instantly push P1/P2 critical alerts to operational channels.
  • Monitoring Reports: Parse scheduled system status emails.
  • ServiceNow Automation: Automatically relay high-priority ticket exports.
  • SLA Tracking: Alert teams before ticket breach thresholds occur.

Best Practices

  1. Keep CSV schema consistent: Avoid changing export column positions.
  2. Validate incoming attachments: Always test file extension and size.
  3. Handle empty records: Filter empty lines prior to column splitting.
  4. Test special characters: Verify handling of quotes and line breaks.
  5. Add error handling: Wrap core steps inside Power Automate Scope blocks.
  6. Avoid exposing sensitive data: Only post necessary fields to public Teams channels.

Frequently Asked Questions

1. Can Power Automate read CSV files?

Yes. Power Automate can process CSV content as text using expressions such as base64ToString(), replace(), and split(). For more complex CSV structures, a dedicated parsing approach may be preferable.

2. How do I convert a CSV attachment to text in Power Automate?

If the attachment content is available as Base64, use base64ToString(item()?['contentBytes']). This converts the attachment content into a string that can be processed by subsequent actions.

3. How do I split CSV rows in Power Automate?

After converting the CSV to text, use the split() function with a newline delimiter: split(csvText, decodeUriComponent('%0A')). This creates an array of rows.

4. How do I skip the CSV header in Power Automate?

Use skip(outputs('CSV_Lines'), 1). This removes the first item from the array.

5. How do I filter CSV data in Power Automate?

After splitting a row into columns, use conditions such as contains(outputs('Cols')[1], 'Critical'). You can combine conditions using or().

6. Can Power Automate send CSV data to Microsoft Teams?

Yes. Once the CSV has been converted and parsed, the extracted fields can be inserted into a Post message in a chat or channel Teams action.

7. Can this work with ServiceNow incident reports?

Yes. If ServiceNow exports incident information in a predictable CSV structure, Power Automate can process the report and send selected incidents to Microsoft Teams.

8. What is the difference between CSV and Excel in Power Automate?

CSV is plain text separated by delimiters, while Excel .xlsx files contain structured worksheets and tables. CSV can be manually parsed with text functions, while Excel data is generally better handled through Power Automate's Excel connector.