Connecting Tables with join in KQL
One table rarely tells the whole story.
EmailEvents may show the message arrived.
UrlClickEvents may show the user clicked.
Endpoint telemetry may show what happened after the click.
The investigation becomes stronger when those signals are connected.
In this Agent Foskett Academy lesson, you will learn how defenders use join in KQL to connect Microsoft Defender XDR tables, follow evidence across telemetry and build a clearer investigation timeline.
Lesson overview
Learn how to use KQL join to connect email delivery, URL click and endpoint evidence during Microsoft Defender XDR investigations.
Why join matters
EmailEvents can help you understand message delivery. UrlClickEvents can help you understand link clicks. DeviceProcessEvents and DeviceNetworkEvents can help you understand what happened on the endpoint.
The join operator allows defenders to connect rows from separate tables when they share a useful field, such as a message identifier, user account, device name, URL, IP address or timestamp window.
Investigation scenario
One user clicked the link. Another user may have clicked later.
The analyst needs to connect the delivered email records with the URL click records so they can see who clicked, what they clicked and which email the click came from.
Step 1 — Create a small email evidence set
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
let suspiciousEmail = EmailEvents | where Timestamp > ago(7d) | where Subject has "invoice" or SenderFromDomain has "example.com" | project EmailTime = Timestamp, NetworkMessageId, RecipientEmailAddress, SenderFromAddress, Subject, DeliveryAction; suspiciousEmail
Step 2 — Join email delivery to URL clicks
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
let suspiciousEmail = EmailEvents | where Timestamp > ago(7d) | where Subject has "invoice" or SenderFromDomain has "example.com" | project EmailTime = Timestamp, NetworkMessageId, RecipientEmailAddress, SenderFromAddress, Subject, DeliveryAction; UrlClickEvents | where Timestamp > ago(7d) | join kind=inner suspiciousEmail on NetworkMessageId | project ClickTime = Timestamp, EmailTime, RecipientEmailAddress, SenderFromAddress, Subject, Url, ActionType, ThreatTypes | sort by ClickTime desc
What kind=inner means
In this scenario, the result shows URL clicks that can be matched back to the suspicious email evidence set.
That makes it useful when you want to answer a direct question: Which delivered suspicious emails had matching click activity?
Step 3 — Use leftouter when you want to keep all emails
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
let suspiciousEmail = EmailEvents | where Timestamp > ago(7d) | where Subject has "invoice" or SenderFromDomain has "example.com" | project EmailTime = Timestamp, NetworkMessageId, RecipientEmailAddress, SenderFromAddress, Subject, DeliveryAction; suspiciousEmail | join kind=leftouter ( UrlClickEvents | where Timestamp > ago(7d) | project ClickTime = Timestamp, NetworkMessageId, Url, ActionType, ThreatTypes ) on NetworkMessageId | project EmailTime, ClickTime, RecipientEmailAddress, SenderFromAddress, Subject, DeliveryAction, Url, ActionType, ThreatTypes | sort by EmailTime desc
Inner join vs leftouter join
Step 4 — Summarize affected users after the join
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
let suspiciousEmail = EmailEvents | where Timestamp > ago(7d) | where Subject has "invoice" or SenderFromDomain has "example.com" | project EmailTime = Timestamp, NetworkMessageId, RecipientEmailAddress, SenderFromAddress, Subject; UrlClickEvents | where Timestamp > ago(7d) | join kind=inner suspiciousEmail on NetworkMessageId | summarize Clicks = count(), UniqueUrls = dcount(Url), FirstClick = min(Timestamp), LastClick = max(Timestamp) by RecipientEmailAddress, Subject | sort by Clicks desc
Investigator notes
Do not join everything just because you can. Start with the question, choose the fields that connect the evidence, reduce each table to the columns you need, then join the results.
What you learned
Continue your investigation
Continue learning with UrlClickEvents, EmailEvents KQL Guide, KQL Threat Hunting Guide, Microsoft Security and the GEMXIT Security Review.
Develop IT. Protect IT. GEMXIT PTY LTD | GEMXIT UK LTD