FIELD NOTE / M365 / AUTOMATION / IDEMPOTENCY
The shared mailbox workflow creates every case twice
The support team sees two cases with the same customer, subject and attachment, created seconds apart. Deleting the duplicate feels harmless until the next retry creates a third. Give every intake item a stable identity and make each side effect safely repeatable. Lower concurrency can reduce overlap but cannot enforce uniqueness.
The situation: one email, two valid-looking cases
Consider a composite Perth service desk that accepts requests through help@, a Microsoft 365 shared mailbox. A Power Automate cloud flow triggers when a new message arrives, creates a Dataverse case, copies attachments to SharePoint, sends an acknowledgement and moves the message into a Processed folder. The process has worked for months.
After a connector interruption, two runs start for the same message. The first creates the case, then times out while copying a large attachment. The platform retries the failed action. An operator also sees the run marked failed and manually resubmits it. The second run cannot see any durable record that the first case already exists, so it creates another. Both records look legitimate and each sends a separate acknowledgement.
The niche failure is an at-least-once delivery path feeding a create-only business process. The trigger, an action retry and a human replay can each be reasonable in isolation. Together they expose that the workflow has no business-level duplicate boundary.
Contain the duplicate factory without losing intake
Name one incident lead and one business owner. Pause downstream actions that create financial, access, scheduling or customer commitments. Do not immediately delete emails, run history or duplicate cases: they are the evidence needed to reconstruct what happened. If the mailbox is the only intake route, direct new mail to a controlled holding folder or replacement queue so operators retain visibility during containment.
Capture the mailbox message identifiers, flow run IDs, trigger timestamps, retry histories, Dataverse record IDs, SharePoint file paths and acknowledgement message IDs. Mark suspected duplicates, but let the business owner decide which record is authoritative. Select the authoritative record from business progression, completed side effects and staff action. Creation time alone cannot make that decision.
Tell operators not to press Resubmit until the replay effect is understood. Resubmit repeats the workflow definition and leaves external systems unchanged.
Separate concurrency, retries and replay
Concurrency means two workflow instances can execute at the same time. Retry means one trigger or action can be attempted again after a transient failure. Replay means a person or system deliberately runs a previous input again. All three can produce duplicates, but they require different controls.
Trigger concurrency set to one serialises runs. Atomic uniqueness remains a separate destination control. Power Automate waiting-run limits can cause later triggers to be retried or missed under sustained load, and a manual replay still occurs after the first run has finished. Similarly, changing an action retry policy may reduce repeated calls but can make transient failures visible to users without preventing a second workflow instance from doing the same work.
Use run history to identify which boundary duplicated: multiple trigger instances, repeated attempts inside one action, or an operator resubmission. The repair must remain safe under all three.
Choose a durable idempotency key
A useful key represents the business instruction and survives connector and run changes. For email intake, the Internet Message ID is often more stable across mailbox operations than a connector item ID, but forwarding, message reconstruction and upstream systems can change it. Where the sender supplies a case or request number, combine that identifier with an agreed source namespace. Otherwise generate an intake ID once and persist it before any external side effect.
Store the key in a system that can enforce uniqueness—such as an alternate key in Dataverse, a database unique constraint, or another atomic reservation mechanism. A SharePoint “Get items then create” check is vulnerable when two runs perform the read before either performs the write. The test and reservation must be one controlled operation, or the destination must reject the second create.
Do not use subject, sender and arrival minute as the sole key. Legitimate customers repeat subjects, and timestamps drift. Store the original identifiers and a separate human-readable fingerprint for investigation.
Persist the intake identity before case creation
messageId = triggerOutputs()?['body/id']
internetMessageId = triggerOutputs()?['body/internetMessageId']
intakeKey = sha256(mailboxId + ':' + immutableMessageId)Connector message IDs can change after a move. Where Graph is used, request immutable identifiers with the documented Prefer: IdType="ImmutableId" header and store the mailbox scope with the ID. Enforce intakeKey as a unique key in the reservation store. A duplicate-key result returns the existing case ID and skips every external side effect.
Reserve, perform, record
- Reserve: attempt to create an intake ledger row with the unique idempotency key and status Received.
- Detect: if the key already exists, read its state and return the existing case reference instead of creating another.
- Perform: create or update the business record using the reserved key, then execute downstream effects in an explicit order.
- Record: store each side effect, external identifier, attempt count and outcome against the ledger.
- Complete: move the mailbox item and mark the ledger complete only after the required acceptance conditions are true.
If the process spans systems without a shared transaction, treat it as a small saga. Identify compensable steps, the point after which retry is safer than compensation, and the reconciliation required when a response is uncertain. A timeout means “outcome unknown,” not necessarily “nothing happened.”
Repair the live workflow in controlled increments
Copy the production definition into a solution-aware development path. Add the ledger and destination uniqueness rule first. Change the flow so the reservation occurs before case creation, and so a duplicate reservation returns the existing case and completes the run as an idempotent replay. Record the flow run ID and source identifiers for traceability.
Then isolate high-impact side effects. An acknowledgement should carry the case ID and should not send twice for the same completion state. Attachment copying should use deterministic paths or stored destination IDs. Updates should set the desired state and tolerate repeated execution. Review trigger conditions to reserve runs for eligible mail, while preserving a route for messages the connector cannot process.
Adjust concurrency only after measuring the destination capacity and queue behaviour. Serial execution can contain overlapping writes while the unique-key and ledger changes are being released. Preserve the old flow disabled and exported until reconciliation and rollback evidence are complete.
Prove the negative cases
Send one ordinary message and confirm one case, one attachment set and one acknowledgement. Then deliver the same source identifier twice simultaneously. Force a timeout after case creation, allow the action retry, and manually replay the failed run. In every test, the ledger should resolve to one authoritative case and show every attempt.
Test two legitimate messages from the same sender with the same subject and confirm that each receives a distinct intake key. Test a large or unsupported attachment, a moved message, a throttled destination and a failure after acknowledgement. Confirm operators can see received, in progress, complete, duplicate and needs reconciliation states without reading sensitive payloads from run history.
Acceptance replays the same delivery and obtains one business outcome. Uncertain results enter a visible reconciliation queue, and duplicate handling retains every legitimate request.
Operate the pattern instead of trusting it
Monitor duplicate detections, age of incomplete ledger rows, retry counts, queue depth and manual replays. Alert when queue age or backlog growth exceeds the operating threshold. Record transient retries as metrics. Keep a supported replay procedure that selects incomplete ledger items, states which effects will run again and requires business approval for irreversible actions.
Review connector limits and mailbox permissions when volumes or ownership change. Maintain the flow in a solution with connection references, environment variables, accountable owners and a tested export. Community reports are valuable signals for connector edge cases, but production assertions should resolve to current Microsoft documentation and local run evidence.
The broader lesson is simple: reliable automation assumes delivery can repeat. A flow becomes operationally trustworthy when its data model treats repeated delivery as an expected state. The run-status icon reports execution only.