To automate overdue invoice reminders, create a Power Automate scheduled cloud flow that runs each morning, reads your invoice list from an Excel table, keeps only the rows that are unpaid and past due, and sends each customer an email with the Office 365 Outlook connector. After each send, write the reminder date back to the row so the same customer is not emailed again the next day. The pattern works with Excel files in OneDrive for Business or SharePoint, and a SharePoint list is a good alternative if the data outgrows a spreadsheet.
Who this is for and what you will have at the end
This guide is for small business owners, bookkeepers and operations staff who track invoices in a spreadsheet and chase late payments by hand. You need a Microsoft 365 account with Power Automate and Outlook, and edit access to the invoice file. No coding is required, though one expression for the date check is shown.
By the end you will have a flow that runs on a schedule, finds overdue invoices, emails reminders, logs what it sent, and fails safely. The connector behavior and limits come from Microsoft Learn. Menu labels in the Power Automate designer change from time to time, so confirm the names as you build.
Design before you build
A reliable reminder flow depends more on the spreadsheet than on the flow. Set it up like this.
The invoice table
Store invoices in an Excel table (Insert, then Table), not a loose range. The Excel Online (Business) connector works with Excel files in document libraries supported by Microsoft Graph, such as OneDrive for Business and SharePoint, and the actions work on tables. Use this layout:
| Column | Example | Purpose |
|---|---|---|
| InvoiceNumber | INV-1042 | Unique key for updates |
| Customer | Fabrikam, Inc. | Used in the email |
| [email protected] | Where reminders go | |
| Amount | 1250.00 | Shown in the email |
| DueDate | 2026-10-15 | Overdue check |
| Status | Unpaid | Filter column (Unpaid or Paid) |
| LastReminderDate | 2026-10-25 | Prevents duplicates |
| ReminderCount | 1 | Optional, for escalation |
Rules from Microsoft's connector documentation that affect this layout:
- Key column values are used to find a row. When several rows match in Update a row or Delete a row, only the first is changed, and the key column field is case-sensitive. Keep InvoiceNumber unique.
- Filter Query, Order By and Select Query support only alphanumeric column names, so avoid spaces and symbols in headers.
- Table headers that contain only a number can cause unexpected behavior in Update a row. Use text headers.
- The connector does not support OData parameters for tables that contain hidden columns.
- The maximum Excel file size supported is 25 MB, and supported formats are .xlsx and .xlsb.
Avoid editing the workbook while the flow runs. Microsoft says simultaneous modifications from other connectors or manual edits are not supported and can cause merge conflicts, and that a file can stay locked for update or delete for up to six minutes after the connector last used it. Schedule the flow for a time when nobody is editing.
The reminder policy
Decide before you automate:
- How many days after the due date does the first reminder go out?
- How many days between reminders, and when do reminders stop and a person takes over?
- Who is copied, and who receives replies?
- Which invoices are excluded (disputed, on a payment plan)? Add a Status value such as Hold and skip those.
Have the wording reviewed by whoever manages your customer relationships, and keep the tone factual and courteous.
Step 1: Create the scheduled flow
Per Microsoft's guide to running a cloud flow on a schedule:
- Sign in to Power Automate at make.powerautomate.com.
- Select My flows, then the Cloud flows tab.
- Select Create from blank, then the Add a trigger node.
- Search for Recurrence and select it.
- Set Interval to 1 and Frequency to Day, and enter a Start time in the format YYYY-MM-DDTHH:MM:SSZ. The Z means UTC. Microsoft's example enters 2025-03-24T22:00:00Z for 3:00 PM Pacific time on March 24, 2025, or you can pick your own zone in the Time zone field described below.
- Open the Recurrence advanced options, set the Time zone, and under At these hours and At these minutes choose the time to run.
- For weekdays only, set Frequency to Week and choose the days under On these days.
A weekday-only schedule keeps reminders from arriving on weekends. Microsoft notes that if you choose a monthly frequency, the flow runs on the same date each month.
Step 2: Read the invoice rows
Add the Excel Online (Business) action List rows present in a table and set:
- Location, Document Library, File and Table: select your workbook and table.
- Filter Query:
Status eq 'Unpaid' - Select Query (optional): a comma-separated list of columns, for example
InvoiceNumber,Customer,Email,Amount,DueDate,LastReminderDate.
Microsoft's known-issues table adds limits that matter here:
- The action returns up to 256 rows by default. Open the action's Settings and turn on Pagination to retrieve more.
- Basic filtering supports
eq,ne,contains,startswithandendswith, only one filter function per column, and only one sorting column. - When filtering or sorting is used, data may not be up to date because of a delay.
- Filters already set in the Excel file are ignored. The action retrieves all rows regardless.
Because date comparisons are not in the supported filter functions, filter on Status in the query and check dates inside the flow.
Excel stores dates as numbers behind the scenes. The action has a DateTime Format parameter; if your due dates arrive as numbers or in an unexpected format, set it so you receive readable dates, and check the output in a test run before you write the comparison.
Step 3: Loop and check each invoice
Add Apply to each and pass in the value output from List rows present in a table. Inside it, add a Condition that is true only when the invoice is past due and has not been reminded recently.
Using expressions from the Workflow Definition Language, which Power Automate shares with Azure Logic Apps, a condition in advanced (expression) mode could look like this:
@and(
less(items('Apply_to_each')?['DueDate'], formatDateTime(utcNow(), 'yyyy-MM-dd')),
or(
empty(items('Apply_to_each')?['LastReminderDate']),
less(items('Apply_to_each')?['LastReminderDate'], formatDateTime(addDays(utcNow(), -7), 'yyyy-MM-dd'))
)
)How it works:
formatDateTime(utcNow(), 'yyyy-MM-dd')gives today's date as text, and comparing ISO-format date strings alphabetically matches chronological order. This only works if DueDate and LastReminderDate also arrive asyyyy-MM-ddtext, so verify that in a test run.addDays(utcNow(), -7)is the date seven days ago, so a reminder is sent only if the last one is more than seven days old. Microsoft documentsaddDayswith a negative number of days.empty(...)handles invoices that were never reminded.- Use
convertFromUtc(utcNow(), 'Pacific Standard Time')if the UTC date could be a day ahead of your local date when the flow runs. The function takes a Windows time zone name.
The dynamic-content name inside the loop depends on how your action is named. Adjust Apply_to_each to match, or build the condition with the visual editor and dynamic content.
Step 4: Send the reminder email
In the Yes branch of the Condition, add the Office 365 Outlook action Send an email (V2):
- To: the Email value for the row.
- Subject: for example
Reminder: Invoice INV-1042 was due October 15, 2026, built from dynamic content. - Body: a short, factual message.
A sample body:
Hello Fabrikam Accounts Payable,
Our records show invoice INV-1042 for $1,250.00, due October 15, 2026,
is still unpaid. If you have already paid it, please disregard this
message and reply with the payment date so we can update our records.
If you need a copy of the invoice or have a question about it,
reply to this email.
Thank you,
Contoso Accounts ReceivableFacts from Microsoft's Outlook connector page that affect this step:
- Each email counts as one API call per connection, even if there are several recipients.
- The throttling limit is 300 calls per connection per 60 seconds, and the page lists a maximum mail content length of 49 MB. For a small invoice list you will not approach these numbers.
- If Send an email gets a 504 response and retries, duplicate emails are possible. This is why the logging step below matters.
- To send from a shared mailbox, use Send an email from a shared mailbox (V2). It works only for Microsoft 365 shared mailboxes, the account needs permission on the mailbox, and new permissions can take about two hours to replicate. An Office 365 group address can't be used.
- The page says Office applies its own per-inbox limits and links to the Exchange Online message limits documentation, so check those limits if you plan large batches.
To attach the invoice PDF, Microsoft documents a workaround for multiple attachments: initialize an array variable, use Append to array variable for each attachment, then reference the array. For a single attachment, use the Attachments parameter directly.
Step 5: Log the reminder
Immediately after the send, add Excel Online (Business) Update a row:
- Table: the same table.
- Key Column: InvoiceNumber.
- Key Value: the invoice number from the loop.
- LastReminderDate: today's date from
formatDateTime(utcNow(), 'yyyy-MM-dd'). - ReminderCount: the old value plus one, for example
add(int(items('Apply_to_each')?['ReminderCount']), 1). If the cell can be blank, wrap it withcoalesceor use anif(empty(...), 1, ...)check.
Microsoft notes that Update a row overwrites the specified cells and leaves columns you leave blank unchanged, and that changes may take up to 30 seconds to take effect.
Keep concurrency low
The Excel connector's documentation lists a throttling limit of 100 API calls per connection per 60 seconds, and warns about 429 Too many requests errors. In the Apply to each settings, set the degree of parallelism to 1 so rows are handled one at a time, and add a short Delay action if you have many invoices.
Step 6: Notify yourself
Add a final step after the loop, such as an email to your finance mailbox with a count of reminders sent. To build the count, use a variable that increases inside the Yes branch. Also configure Run after on that step so it still runs if an earlier step fails, and send yourself a failure message when it does.
Test safely
- Make a copy of the workbook and use it in the flow while testing.
- Replace the To address with your own for the first runs, or use test rows with your own email.
- Select Test, then Manually, then Run flow, and open the run history to read each step's inputs and outputs.
- Confirm the date values look the way your condition expects.
- Check the row was updated and that a second run the same day sends nothing.
- Switch to the real file and addresses only after the above works, and review the first live runs the same day.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Only some invoices are processed | Pagination off; default limit of 256 rows | Turn on Pagination in the action settings |
| 403 Forbidden from Excel | No write access to the file | Give the flow's account edit rights, since Microsoft says write access is required for all actions |
| 502 BadGateway from Excel | File is in read-only mode | Turn off read-only mode on the workbook |
| 429 Too many requests | Too many calls in a short time | Lower concurrency and add a Delay, per Microsoft's guidance |
| Filter returns nothing | Column name has spaces or symbols, or a hidden column exists in the table | Use alphanumeric headers and unhide columns |
| Update a row changes the wrong invoice | Duplicate key values; only the first match is updated | Make InvoiceNumber unique |
| Update fails to find the row | Key column name case mismatch | Match the column name exactly |
| Dates compare incorrectly | Dates arrive as numbers or in another format | Check the output and set the DateTime Format parameter |
| Duplicate emails | Retry after 504 or missing log update | Keep the LastReminderDate check and run a single instance |
| Flow runs at the wrong hour | Start time in UTC or wrong time zone | Set the Time zone field in the Recurrence trigger |
| Shared mailbox send fails | Missing permission or a converted personal mailbox | Grant access, wait up to about two hours, and use a true shared mailbox |
| Excel file locked | Another user or process has it open | Schedule the flow outside working hours |
When to use SharePoint or a database instead
If you have thousands of invoices, several people editing, or concurrent flows, a spreadsheet becomes fragile. A SharePoint list or accounting system data source avoids many Excel connector limits. The SharePoint connector's Get items action has a Filter Query that accepts an ODATA filter to restrict the entries returned. If your accounting software has its own reminders, use them and reserve this flow for gaps.
For a similar scheduled-flow design that connects forms to a CRM, see Zapier lead routing with forms, CRM and Slack, and for a tool comparison read Zapier vs Power Automate for small business.
Summary checklist
- Invoices in an Excel table with unique invoice numbers and text-only headers
- LastReminderDate and Status columns exist
- Recurrence trigger set with the correct time zone, weekdays only if desired
- List rows present in a table filters on Status and has pagination on
- Condition checks overdue and not recently reminded
- Email sent from the right mailbox with a clear, factual message
- Update a row logs the reminder date
- Concurrency set to 1 and failure notification configured
- Tested on a copy with your own address before going live
Comments
Questions and tips are welcome. Comments are checked by the EpiFive team before they appear; please do not share passwords, phone numbers or other private details.