Purview DLP Exchange Alert Info
Query
let alert_id = "<<<>>>";
let query_period = 1d;
let internet_message_ids = toscalar(
AlertEvidence
| where Timestamp > ago(query_period)
| where AlertId == strcat("dl", alert_id) and EntityType == "MailMessage"
| extend AdditionalFields = todynamic(AdditionalFields)
| summarize make_set(AdditionalFields["InternetMessageId"])
);
let network_message_ids = toscalar(
AlertEvidence
| where Timestamp > ago(query_period)
| where AlertId == strcat("dl", alert_id) and EntityType == "MailMessage"
| summarize make_set(NetworkMessageId)
);
CloudAppEvents
| where Timestamp > ago(query_period)
| where ActionType in ("AlertTriggered", "AlertUpdated") and tostring(RawEventData["AlertId"]) == alert_id
| summarize arg_max(Timestamp, *)
| extend
AlertId = tostring(RawEventData["AlertId"]),
Data = todynamic(tostring(RawEventData["Data"]))
| extend
UserPrincipalName = tolower(tostring(Data["f3u"])),
Severity = tostring(Data["sev"]),
Workload = tostring(Data["wl"]),
SensitiveInformationContentType = split(tostring(Data["sict"]), ";"),
SensitiveInformationTypeMatchInfo = split(tostring(Data["sitmi"]), ";"),
PolicyId = tostring(Data["dpid"]),
PolicyName = tostring(Data["dpn"]),
RuleId = tostring(Data["drid"]),
RuleName = tostring(Data["drn"]),
ProtectionActions = split(tostring(Data["dact"]), ", "),
ObjectName = tostring(Data["von"]),
SenderFromAddress = tostring(Data["mfrm"]),
RecipientEmailAddress = split(tostring(Data["to"]), ","),
CCEmailAddress = split(tostring(Data["cc"]), ","),
BCCEmailAddress = split(tostring(Data["bcc"]), ",")
| where Workload == "Exchange" and tostring(RawEventData["Category"]) == "DataLossPrevention"
| project
Timestamp,
Application,
ActionType,
AlertId,
UserPrincipalName,
Severity,
Workload,
SensitiveInformationContentType,
SensitiveInformationTypeMatchInfo,
PolicyId,
PolicyName,
RuleId,
RuleName,
ProtectionActions,
Subject = ObjectName,
SenderFromAddress,
RecipientEmailAddress,
CCEmailAddress,
BCCEmailAddress,
AlertTriggered_RawEventData = RawEventData,
AlertTriggered_ReportId = ReportId,
// We will assume there is only 1 email associated to an alert
InternetMessageId = tostring(internet_message_ids[0]),
NetworkMessageId = tostring(network_message_ids[0])
| lookup kind=leftouter (
EmailEvents
| where Timestamp > ago(query_period)
| where NetworkMessageId == tostring(network_message_ids[0])
| summarize FinalRecipientEmailAddress = array_sort_asc(make_list(RecipientEmailAddress)) by NetworkMessageId, DeliveryAction
| summarize FinalRecipientEmailAddress = make_bag(bag_pack(DeliveryAction, FinalRecipientEmailAddress)) by NetworkMessageId, DeliveryAction
) on NetworkMessageId
| lookup kind=leftouter (
EmailUrlInfo
| where Timestamp > ago(query_period)
| where NetworkMessageId == tostring(network_message_ids[0])
| summarize EmailUrlInfo = make_list(bag_pack("Url", Url, "UrlDomain", UrlDomain, "UrlLocation", UrlLocation)) by NetworkMessageId
) on NetworkMessageId
| lookup kind=leftouter (
EmailAttachmentInfo
| where Timestamp > ago(query_period)
| where NetworkMessageId == tostring(network_message_ids[0])
| distinct NetworkMessageId, FileName, FileType, SHA256, FileSize
| summarize EmailAttachmentInfo = make_list(bag_pack("FileName", FileName, "FileType", FileType, "FileSize", FileSize, "SHA256", SHA256)) by NetworkMessageId
) on NetworkMessageIdExplanation
This KQL query is designed to gather and process information related to a specific alert in an email system, particularly focusing on data loss prevention (DLP) incidents in Exchange. Here's a simplified breakdown of what the query does:
-
Define Variables:
alert_id: A placeholder for the specific alert ID you are interested in.query_period: The time frame for the query, set to 1 day.
-
Extract Internet and Network Message IDs:
- It retrieves the
InternetMessageIdandNetworkMessageIdassociated with the specified alert from theAlertEvidencetable, filtering by the alert ID and ensuring the data is recent (within the last day).
- It retrieves the
-
Filter Cloud App Events:
- It looks into the
CloudAppEventstable for events related to the alert, specifically those that are either "AlertTriggered" or "AlertUpdated". - It extracts and processes various fields from the event data, such as user information, severity, policy details, and email addresses.
- It focuses on events related to the "Exchange" workload and categorized under "DataLossPrevention".
- It looks into the
-
Project Relevant Data:
- The query selects specific fields to output, including timestamps, user details, policy information, and email metadata.
- It assumes there is only one email associated with the alert and uses the first
InternetMessageIdandNetworkMessageIdfound.
-
Enrich Data with Email Details:
- It performs left outer joins with three other tables (
EmailEvents,EmailUrlInfo, andEmailAttachmentInfo) to enrich the alert data with additional email-related information:- EmailEvents: Provides the final recipient email addresses and delivery actions.
- EmailUrlInfo: Adds information about URLs contained in the email, including domain and location.
- EmailAttachmentInfo: Includes details about any attachments in the email, such as file name, type, size, and hash.
- It performs left outer joins with three other tables (
The overall goal of this query is to compile a comprehensive view of a specific alert related to email data loss prevention, combining alert metadata with detailed email content and context.
Details

Jose Sebastián Canós
Released: May 7, 2025
Tables
AlertEvidence
CloudAppEvents
EmailEvents
EmailUrlInfo
EmailAttachmentInfo
Keywords
AlertEvidenceCloudAppEventsEmailEventsEmailUrlInfoEmailAttachmentInfoMailMessageRawEventDataDataLossPreventionExchangeUserPrincipalNameSeverityWorkloadSensitiveInformationContentTypeSensitiveInformationTypeMatchInfoPolicyIdPolicyNameRuleIdRuleNameProtectionActionsObjectNameSenderFromAddressRecipientEmailAddressCCEmailAddressBCCEmailAddressInternetMessageIdNetworkMessageIdFinalRecipientEmailAddressDeliveryActionUrlUrlDomainUrlLocationFileNameFileTypeSHA256FileSize
Operators
lettoscalarwhereagostrcatextendtodynamicsummarizemake_setintostringarg_maxsplitprojectlookupkind=leftouterarray_sort_ascmake_listmake_bagbag_packdistinct