Detect Email Spoofing in Microsoft Defender with KQL
When an email looks like it came from someone trusted, the logs can tell a different story.
This page gives practical, copy-paste KQL queries for Microsoft Defender XDR to investigate spoofed domains, sender alignment, DMARC failures, suspicious delivery and URL click activity.
It is designed for analysts, admins and business owners who want real investigation paths, not marketing fluff.
KQL page summary
A focused Microsoft Defender KQL page built around the exact search signals Google is already showing: spoofeddomain, EmailEvents, AuthenticationDetails and KQL.
Copy-paste KQL for email spoofing checks
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
EmailEvents
| where Timestamp > ago(30d)
| where AuthenticationDetails has_any ("spf=fail", "dkim=fail", "dmarc=fail", "spoof")
| project
Timestamp,
SenderFromAddress,
SenderFromDomain,
SenderMailFromAddress,
SenderMailFromDomain,
RecipientEmailAddress,
Subject,
AuthenticationDetails,
ThreatTypes,
DeliveryAction,
NetworkMessageId
| order by Timestamp desc
Compare visible sender and envelope sender
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
EmailEvents
| where Timestamp > ago(30d)
| where SenderFromDomain != SenderMailFromDomain
| project
Timestamp,
SenderFromAddress,
SenderFromDomain,
SenderMailFromAddress,
SenderMailFromDomain,
RecipientEmailAddress,
Subject,
AuthenticationDetails,
DeliveryAction
| order by Timestamp desc
Find repeated spoofing campaigns
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
EmailEvents
| where Timestamp > ago(30d)
| where AuthenticationDetails has_any ("spf=fail", "dkim=fail", "dmarc=fail", "spoof")
| summarize
MessageCount = count(),
RecipientCount = dcount(RecipientEmailAddress)
by SenderFromAddress, SenderFromDomain, Subject, DeliveryAction
| where MessageCount >= 3
| order by MessageCount desc
Pivot from suspicious email to URL clicks
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
let SuspiciousMessages =
EmailEvents
| where Timestamp > ago(30d)
| where AuthenticationDetails has_any ("spf=fail", "dkim=fail", "dmarc=fail", "spoof")
| project NetworkMessageId, EmailTime = Timestamp, SenderFromAddress, RecipientEmailAddress, Subject;
SuspiciousMessages
| join kind=inner (
UrlClickEvents
| where Timestamp > ago(30d)
| project NetworkMessageId, ClickTime = Timestamp, AccountUpn, Url, ActionType
) on NetworkMessageId
| order by ClickTime desc
