Power Automate sends the same email two or three times
A flow that runs twice has a trigger that fires on every change, including changes the flow makes itself, or it has a repeat run or a second copy of the flow. Add a trigger condition so the flow starts only when the item is ready, and add a Yes/No "email sent" flag that the flow sets after it sends, which acts as a loop guard.
Microsoft says the SharePoint trigger "When an item is created or modified" "fires for every change to SharePoint items." The flag and the trigger condition are our advice, not a Microsoft rule. Microsoft's own pages support the ideas behind them.
Causes at a glance
- Self-triggering update: the flow edits the item that starts it. Fix: the flag plus a trigger condition (Steps 2, 4 and 5).
- Two copies of the flow: an old test copy or a coworker's copy. Fix: turn off the extra copy (Step 1).
- A repeat run: Microsoft says one run can have actions duplicated. Fix: design the flow to be idempotent (Step 2).
- Apply to each over a list of items: the flow sends one email per item in the loop, so a long list means a long string of emails from one run. Our advice, not a Microsoft rule: send one summary email after the loop instead.
What duplicate emails look like
A client gets the same "your order is complete" message three times. A manager gets two copies of the same alert. In the run history you may see several runs for one item, or one run that looks normal while the email arrived twice.
A real example from a Microsoft Q&A answer thread: a person built a flow on the trigger "When an item is created or modified". It should send one email when a Status column changed to Completed. The email went out several times. They had tried a Condition on Status, a Delay, and a change to the Status value after sending. None of them solved it.
Why it happens
There are three causes. Check them in this order.
- The trigger fires on every change. Microsoft says: "This trigger fires for every change to SharePoint items." Someone fixes a typo, adds a comment, or changes a date. Each save is a run.
- The flow edits the item it is watching. If your flow updates a column on the same item, that update is a change too. The trigger sees it and starts another run. This is how a flow can end up in a loop. This follows from the fact above. Test it on your own list to confirm.
- A repeat or a copy. Microsoft says a single run can have "some (or all) of its actions duplicated" because of the "at-least-once" design of Azure Logic Apps. Microsoft also names "other copies of the flow active in different environments and triggering based on same condition."
Notice what a Condition action inside the flow does not do. A Condition runs after the trigger has already fired. Microsoft says that when you filter with conditions inside the flow, the flow still runs and the call counts as an API request. So a Condition inside the flow cannot stop the trigger from starting. It can only decide what happens next.
Signs this is your problem
- Several runs in the run history for one item, close together in time.
- The email arrives again after someone edits an unrelated column.
- The count of runs grows faster than the count of items.
- The flow edits the same list item that starts it.
Step 1. Look for a second copy of the flow
Start with the easy check. Duplicates can come from two flows doing the same job.
- Sign in to Power Automate and open My flows. Exact names may differ in your version.
- Look for flows with similar names, old test copies, or flows owned by a coworker.
- Turn off any copy that is not needed. Keep one.
Microsoft's help page on triggers lists "other copies of the flow active in different environments" as one reason a flow triggers more than once. See "Troubleshoot common problems with Power Automate triggers" in the sources below.
Step 2. Add a Yes/No "email sent" column
This is the main fix. It makes your flow safe to run twice. Microsoft's troubleshooting page says to design flows to be "idempotent - accounting for the possibility of duplicate inputs." Its example is "checking to see if a duplicate SharePoint document already exists before trying to create it."
One way to start:
- Open your SharePoint list.
- Add a column. Choose Yes/No as the type.
- Name it with no spaces, for example EmailSent. Set the default to No.
- Keep the name short and plain. A name without spaces keeps formulas simple.
Step 3. Make the list status sort in order
If your list has a Status column, make it a Choice column with number prefixes so the order stays fixed:
- 1 Open
- 2 In progress
- 3 Completed
A Choice column sorts by its text. The number prefix is there to keep your order. SharePoint does not sort by the position of the choice.
Every list also has a Title column. It is required by default. Rename it to something useful, such as "Order name", or turn off Require in the column settings.
Step 4. Add a trigger condition
A trigger condition stops the run before it starts. Microsoft says: "If the trigger condition isn't met, the flow isn't triggered, and no run history is logged."
- Open the flow and choose Edit.
- Select the trigger card.
- Open Settings.
- Next to Trigger conditions, choose Add.
- Type an expression. Every trigger condition must start with the @ symbol.
- Save the flow.
In the new designer you see a Settings tab, with a + Add button next to Trigger conditions. In the classic designer, you open the trigger card, then the ellipsis (...) and Settings, and choose Add under Trigger Conditions. Exact names and button places may differ. Microsoft's page "Customize your triggers with conditions" has the steps for both.
Here is an example for our list. It says: run only when Status is 3 Completed and EmailSent is No.
@and(equals(triggerBody()?['Status']?['Value'], '3 Completed'), equals(triggerBody()?['EmailSent'], false))
The text inside the quotes and brackets must match your column choices exactly. Use internal column names, not display names. A column with a space in its name has a different internal name, so check it before you type. If you have more than one condition, Microsoft says all conditions must be met by default. If any one of them is optional, use the @or syntax.
The exact expression is our advice, not a Microsoft rule. Test it on one item before you rely on it.
Step 5. Set the flag inside the flow
Now the flow must mark the item after it sends.
- Start with the trigger and its condition.
- Add the action that sends your email.
- Add an Update item action for the same list. This update is your loop guard: it marks the item so the flow ignores its own change.
- Set EmailSent to Yes. If Title is required in your list, set Title to the Title from the trigger. Update item needs it. Leave other columns unchanged.
This update is a change, so the trigger fires again. That is fine now. The trigger condition checks EmailSent is No, so the new run does not start. Order matters: send first, then set the flag. If the email step fails, the flag stays No and you can retry.
Step 6. Check one item end to end
- Create a test item with Status 1 Open. No run should start.
- Change it to 3 Completed. One run should start and one email should arrive.
- Edit another column on the same item. No new run should start.
- Open the flow's run history. You should see one run, for the change to 3 Completed. Microsoft's trigger conditions page says an unmet condition logs no run history, and its troubleshooting page says a skipped check means the condition was not met. Either way, no extra run is the result you want.
If you also read the list in the flow
Some flows read the list before they send, for example to count open items. If you use the Get items action, know that it returns 100 items by default. Microsoft says you can raise the limit with Top Count in Advanced options, up to the list view threshold of 5,000. Set Top Count and Pagination yourself. The flow only sees the rows Get items fetched. A flag check does not need Get items at all, because the trigger already carries the item's values.
What to avoid
- Do not rely on a Delay action to stop duplicates. The poster in the Q&A thread tried one and it did not help.
- Do not rely on a Condition inside the flow to prevent the trigger from firing. It runs after the trigger.
- Do not set the flag before the email goes out. If the email fails, nobody gets it and the flag says it was sent.
- Do not use a display name in a trigger condition. Use the internal name.
- Do not keep old test copies of the flow turned on.
Honest limits
A flag column and a trigger condition cut duplicates. They do not remove every one. If two runs start at nearly the same moment, both may read EmailSent as No before either one sets it to Yes. It can happen. For high stakes email, such as invoices, add a second check just before you send. Read the item again, and send only if EmailSent is still No. That is our advice, not a Microsoft rule.
Also, views and flags do not control who can see a list. Use list permissions for that.
For a reminder flow that runs on a schedule instead of on each edit, see "Late tasks nobody notices: setting up late alerts". For a flow that stops running by itself, see "Why Power Automate turned your flow off, and how to turn it back on". To trace who edited an item, see "See who changed a row: SharePoint version history".
Cancel runs that are already queued
If a flow has already started a pile of bad runs, you can cancel them. Microsoft says to open the flow's run history and use Cancel all flow runs, or select up to 20 runs in the Waiting or Running state. Microsoft also says to confirm with Yes, and you can tick a box to turn the flow off so you can fix the cause. Microsoft says the process "can take up to 24 hours". Runs move from Waiting to Canceling to Canceled. If you turn the flow off, runs that are still waiting stay Waiting until you turn the flow back on. Fix the trigger first, or new runs will keep arriving.
When to get help
You can build all of this yourself in Microsoft 365. If you would rather have it built and tested for your team, I do that. A tracker like this is a fixed price: $5,000 for one, built in 2 weeks. See "What a SharePoint tracker costs to build". Bring one example of the problem to a free call.
I am Al Davies. I run 250 High Street LLC and build SharePoint trackers and Power Automate flows for operations teams. I work remotely. The first call is free, and I will not try to sell you anything.
See trackers I built: Tools I built
FAQ
Why is my Power Automate flow running twice or multiple times?
The SharePoint trigger fires for every change, your flow may edit its own item, or a second copy of the flow is active; Microsoft also says one run can have actions duplicated.
Why is Power Automate sending duplicate emails?
The same causes apply; add an EmailSent flag and a trigger condition so a repeat run sends nothing, which is our advice, not a Microsoft rule.
How do I cancel all flow runs in Power Automate?
Open the flow's run history and select Cancel all flow runs, or pick up to 20 Waiting or Running runs; Microsoft says it can take up to 24 hours.
What does idempotent mean?
It means a repeat run does no extra harm. Microsoft's troubleshooting page uses the word and gives examples, such as checking whether a record already exists before creating it.
Will a trigger condition show up in my run history?
Not as a normal run. Microsoft says that if the condition is not met, the flow is not triggered and no run history is logged.
Sources
- Microsoft Q&A, While using the trigger when item is modified or created, mail is triggering multiple times
- Microsoft Learn, Customize your triggers with conditions
- Microsoft Learn, Troubleshoot common problems with Power Automate triggers
- Microsoft Learn, In-depth analysis into Get items and Get files SharePoint actions
- Microsoft Learn, Cancel or resubmit flow runs in bulk in Power Automate