The problem: an AI agent that couldn't touch the mailbox
When we architect systems for mission-critical enterprise environments, requirements that appear deceptively simple on paper often reveal the steepest operational cliffs.
A customer approached us with a straightforward automation requirement: they were deploying an AI agent to triage incoming regulatory inquiry emails. These are high-consequence communications. They arrive in shared mailboxes, require a rapid operational response, and an audit trail designed to meet the organization's compliance and tamper-resistance requirements for internal and external regulatory review.
The core design requirement was simple to state and surprisingly hard to satisfy: export the incoming emails to a SharePoint document library so the agent could work from a governed copy, rather than reaching into the mailbox directly.
That requirement quickly hit a platform boundary.
Across Microsoft 365, there is no native toggle or out-of-the-box workflow that bridges Exchange Online and SharePoint based on data sensitivity. Exchange Online handles transport; Microsoft Purview evaluates classification and policy compliance; Power Platform offers automation. Yet no single native capability provides the complete workflow: detect a qualifying inbound email, retrieve its MIME content, and store the resulting .eml file in SharePoint.
Without a supported and repeatable solution, this requirement became a blocker for the AI initiative. Granting an automated agent broad mailbox permissions conflicted with the goal of least-privilege access. Alternatively, asking compliance officers to run periodic manual exports was unscalable and introduced unacceptable latency.
To solve this, we designed an event-driven, three-tier architecture that classifies qualifying email, captures the resulting telemetry, retrieves the message's MIME representation, and stores it as an .eml file. The resulting design avoids scheduled mailbox polling, custodian-run export scripts, and stored application secrets.
The architecture in brief
The architecture uses three Microsoft cloud services, separating classification and detection from message retrieval and storage.
The architecture does not depend on a custom-built service. Its value comes from how Microsoft Purview, Microsoft Sentinel, and Azure Logic Apps are connected, along with design choices such as managed identity, event-driven execution, and separate storage destinations that support operation in a regulated environment.
End-to-end pipeline
Let's walk through each stage.
Stage 1 — Microsoft Purview auto-labeling & audit generation
The process begins when Microsoft Purview auto-labeling evaluates qualifying Exchange Online email against the configured policy conditions. We scoped these policies to target sensitive communications originating from external regulatory sender domains. The policies define matching conditions: in this case, the sender domain. When an email matches, Purview applies a sensitivity label and writes an audit event to the Microsoft 365 unified audit log.
That audit event, identified by ActionType = "AutoSensitivityLabelRuleMatch", provides the telemetry signal for the downstream workflow. By relying on an existing compliance signal generated by Microsoft 365, the design avoids introducing a separate mailbox-scanning mechanism or third-party journaling integration. Microsoft Sentinel can then detect the targeted activity through CloudAppEvents.
This design explicitly tracks three separate auto-labeling policies, distinguished by policy ID:
Note: Scoping detection to specific policy IDs narrows the query to the policies used by this workflow, excludes unrelated labeling activity, and makes detected events easier to correlate with their corresponding regulatory controls.
Stage 2 — Microsoft Sentinel detection rule (KQL)
The relevant activity is available in the CloudAppEvents advanced hunting table when the required Microsoft Defender for Cloud Apps and Microsoft 365 activity integration is configured. Microsoft Sentinel can query this telemetry through its Microsoft Defender XDR integration.
A Sentinel analytics rule filters for the targeted auto-labeling activity, parses RawEventData, and projects the message and policy metadata required by the automation workflow.
In this implementation, fields such as sender, recipients, subject, workload item ID, and policy details are extracted from RawEventData and its nested ExchangeMetaData value. Because audit payload schemas can evolve, validate these field paths against events in your own tenant before deploying the rule as-is.
Sample KQL rule
```kusto
// Sentinel Analytics Rule — AutoSensitivityLabelRuleMatch
// Table : CloudAppEvents
CloudAppEvents
| where ActionType == "AutoSensitivityLabelRuleMatch"
| where Application == "Microsoft Exchange Online"
| extend RawData = parse_json(RawEventData)
| where tostring(RawData.PolicyId) in (
"dcd0132b-7117-4466-8be9-880b5652e106",
"a3900a77-0025-42e8-84b6-327de32cba6f",
"0387080a-3861-45ab-84e1-4dee8d58490e"
)
| extend ExchangeMeta = parse_json(tostring(RawData.ExchangeMetaData))
| extend MessageID = tostring(RawData.WorkLoadItemId)
| extend Sender = tostring(ExchangeMeta.From)
| extend Recipients = tostring(ExchangeMeta.To)
| extend Subject = tostring(RawData.ItemName)
| extend CC = tostring(ExchangeMeta.CC)
| extend BCC = tostring(ExchangeMeta.BCC)
| extend SentTime = todatetime(ExchangeMeta.Sent)
| extend LabelName = tostring(RawData.LabelName)
| extend LabelId = tostring(RawData.LabelId)
| extend PolicyName = tostring(RawData.PolicyName)
| extend PolicyId = tostring(RawData.PolicyId)
| extend ExecutionRuleName = tostring(RawData.ExecutionRuleName)
| extend Severity = tostring(RawData.Severity)
| extend RuleMode = tostring(RawData.RuleMode)
| project
TimeGenerated,
AccountId,
AccountDisplayName,
MessageID,
Sender,
Recipients,
Subject,
CC,
BCC,
SentTime,
LabelName,
LabelId,
PolicyName,
PolicyId,
ExecutionRuleName,
Severity,
RuleMode
```
Two design decisions are worth emphasizing:
- Filter before parsing. Filtering on ActionType and Application before calling parse_json() reduces the number of records that require JSON processing.
- Deterministic entity mapping. Flattening and projecting these fields from RawEventData creates a predictable set of fields that can be mapped into the Sentinel alert and consumed by the Logic App. Map MessageID to the MailMessage entity's Internet Message ID so the Logic App receives an identifier it can use to locate the corresponding Microsoft Graph message before retrieving its MIME content.
Stage 3 — Azure Logic Apps & automated EML extraction
The automation layer is driven by Azure Logic Apps. A KQL-based Microsoft Sentinel analytics rule detects the targeted activity and generates a Sentinel alert. That alert invokes the Logic App through the Microsoft Sentinel alert trigger, providing the alert and its associated entities as input to the orchestration workflow. When no qualifying alerts are generated, the message-processing workflow does not execute, avoiding the recurring mailbox queries associated with scheduled polling.
Once triggered, the Logic App uses the message metadata from the alert to resolve the corresponding message through Microsoft Graph. It then retrieves the message's MIME representation by calling the message endpoint with /$value. That MIME response can be stored with an .eml extension.
For regulated communications, credential handling is a core design consideration. This architecture avoids stored client secrets for Microsoft Graph access. The Logic App uses its system-assigned managed identity and the Microsoft Graph application permissions required for the message retrieval operation.
For production deployments, do not treat tenant-wide Mail.Read as the final least-privilege boundary. Constrain the application's mailbox scope using the Exchange Online application-access controls supported in your environment and grant only the Graph permissions required by the implementation.
Storage architecture: where the emails land
Each exported email is saved to two locations and organized by date. Azure Blob Storage supports the automation and storage workflow, while SharePoint provides the governed copy consumed by users and the AI solution.
The naming structure is “Timestamp_ShortMessageIdentifier_SanitizedSenderAddress”. It provides a consistent naming convention that helps correlate the stored file with the message processed by the Sentinel alert and Logic App workflow. Date-partitioned folders keep both locations easy to browse, retire, or apply lifecycle or retention policy against.
Why this closed the gap for the AI agent
The original blocker was access: the AI agent needed a governed SharePoint-resident copy of qualifying regulatory email without receiving direct mailbox access.
This pipeline provides that separation. The agent reads from LogicAppUploads/, where access can be controlled with standard SharePoint permissions and the organization's governance configuration. Only mail that enters the targeted Purview policy and Sentinel detection path is exported, so the agent's input is constrained by the same classification workflow used to identify the messages in the first place.
One important distinction is that the stored .eml file and the SharePoint item have their own governance context. If the solution requires a SharePoint sensitivity label, retention label, immutable retention, or other records-management control on the exported copy, configure those controls explicitly rather than assuming the original email's Purview label is automatically transferred to the new file.
Architectural takeaways for Mission Critical Deployments
- Use existing compliance signals where they meet the requirement. Purview auto-labeling can provide the event used to start downstream detection without introducing a separate mailbox-scanning service.
- Match the intended policy IDs. Explicit policy filtering keeps unrelated labeling activity out of the automation path and makes detections easier to audit.
- Prefer event-driven orchestration to mailbox polling. Triggering the workflow from detection activity avoids unnecessary mailbox queries and scheduled executions when there is no qualifying work.
- Avoid stored secrets for sensitive pipelines. A Logic App managed identity removes the need to store a client secret for Graph authentication. Combine it with the narrowest practical Graph permission and mailbox scope.
- Separate runtime storage from user-facing access when their requirements differ. Blob Storage and SharePoint can serve different consumers, but retention, immutability, permissions, and lifecycle requirements should be configured deliberately for each destination.
When faced with a capability gap in enterprise architecture, the instinct is often to reach for a bespoke tool or write custom code. More often than not, the answer is already sitting on the board, scattered across services you likely already license and run. By aligning Purview’s classification engine, Sentinel’s event stream, and Logic Apps’ event-driven orchestration, we built a repeatable pattern that not only delivered the email artifact to the AI agent, but also gave the security and compliance team an unyielding architectural boundary. Sometimes the best solutions aren’t about reinventing the wheel; they’re simply about wiring the right signals together with intent.