Email Artifacts
Email forensics covers local client artifacts (Outlook PST/OST, mail rules), server-side artifacts (Exchange/Microsoft 365 audit logs), and email header analysis. Email is the primary initial access vector — forensically recovering what was sent, received, and clicked is often central to reconstructing an intrusion.
A spear-phishing email delivered an LNK file attachment that triggered a PowerShell payload when opened. The email was deleted by the user after clicking (inadvertently, or by the attacker's cleanup). The email body no longer exists in the user's mailbox. But the PST file on disk may have the deleted message in recoverable form (items aren't immediately purged from PST — they go to Deleted Items, then remain in the PST's unallocated internal space). The Exchange audit log shows the message was received, and the Message Tracking Log shows its full path through the mail system. The email headers in those logs reveal the originating infrastructure. This chapter covers how to get all of that.
Local Email Artifacts (Outlook PST/OST)
| Artifact | Location | Forensic value |
|---|---|---|
| PST file (Personal Storage Table) | %USERPROFILE%\Documents\Outlook Files\ or custom location visible in Outlook settings | Entire local email archive — all folders, messages, attachments, contacts. Contains deleted items until permanently purged. |
| OST file (Offline Storage Table) | %LOCALAPPDATA%\Microsoft\Outlook\ | Local cache of Exchange/M365 mailbox. Contains email that has since been deleted from the server if purge hasn't happened. |
| Outlook NK2/Autocomplete | %APPDATA%\Microsoft\Outlook\*.dat or %LOCALAPPDATA%\Microsoft\Outlook\RoamCache\ | Email address autocomplete cache — shows all addresses the user has ever emailed, including those not in contacts |
| Outlook mail rules | Stored inside PST/OST (Rules folder) and in registry at HKCU\Software\Microsoft\Office\<version>\Outlook\Rules | Attacker-created mail rules (auto-forward, auto-delete) are a key BEC indicator |
Analyzing PST/OST Files
# Analyze Outlook PST files with libpff tools (available in SIFT)
# libpff provides pffexport — extracts PST contents to readable files
# Export entire PST to directory (messages as .eml, attachments preserved)
pffexport -f text -t all -o /cases/CASE001/pst-export/ \
"/evidence/jsmith.pst"
# -f text: export as plain text
# -t all: export all folders including Deleted Items, Recoverable Items
# Output directory: one folder per PST folder, one file per message
# List folder structure without exporting
pffinfo "/evidence/jsmith.pst"
# Alternatively: readpst (another libpst tool, more Unix-friendly)
readpst -u -o /cases/CASE001/pst-export/ "/evidence/jsmith.pst"
# -u: unicode mode
# -o: output directory
"""Search PST file for specific content using pypff."""
import pypff
import sys
from datetime import datetime
def search_messages(pst_path: str, search_term: str):
pst = pypff.file()
pst.open(pst_path)
root = pst.get_root_folder()
results = []
_walk_folder(root, search_term.lower(), results)
pst.close()
return results
def _walk_folder(folder, term, results, path=""):
for i in range(folder.number_of_sub_folders):
subfolder = folder.get_sub_folder(i)
_walk_folder(subfolder, term, results, path + "/" + subfolder.name)
for i in range(folder.number_of_sub_messages):
msg = folder.get_sub_message(i)
subject = msg.subject or ""
sender = msg.sender_name or ""
body = ""
try:
body = msg.plain_text_body or ""
if isinstance(body, bytes):
body = body.decode("utf-8", errors="replace")
except Exception:
pass
if (term in subject.lower() or term in sender.lower() or
term in body.lower()):
dt = msg.client_submit_time
results.append({
"folder": path,
"subject": subject,
"sender": sender,
"time": str(dt),
"body_preview": body[:200]
})
if __name__ == "__main__":
pst_path = sys.argv[1]
search_term = sys.argv[2]
for r in search_messages(pst_path, search_term):
print(f"[{r['time']}] {r['folder']} | {r['sender']} | {r['subject']}")
print(f" Preview: {r['body_preview'][:100]}")
print()
Email Header Analysis
Email headers contain the routing history of an email — every server it passed through, originating IP, and authentication results. For phishing investigations, headers reveal the attacker's sending infrastructure.
Reading Email Headers for Forensic Investigation
═══════════════════════════════════════════════════════════════════
Relevant headers (read bottom-to-top for chronological order):
Authentication-Results:
spf=fail (IP not authorized to send for this domain)
dkim=none (no DKIM signature — suspicious for corporate email)
dmarc=fail (failed both SPF and DKIM checks)
→ Authentication failures = likely spoofed sender address
Received: from mail.evil-domain.com ([185.220.101.47])
by inbound.corp.com with ESMTP id abc123
→ Originating IP is the first "Received: from" in the chain
→ Resolve via whois, geolocation, VirusTotal
X-Originating-IP: 185.220.101.47
→ Some mail systems add this explicitly (very valuable)
Message-ID:
→ Message ID includes the sending server's domain
→ Non-matching domain vs From: address is suspicious
X-Mailer / User-Agent:
→ Reveals what software sent the email
→ "PHPMailer" or unusual mail clients suggest bulk phishing tools
Return-Path: attacker@different-domain.com
→ Where bounces go — often reveals the real sending domain
→ Should match From: in legitimate email
Analysis tools:
MXToolbox Email Header Analyzer (paste headers, get visual routing)
Google Admin Toolbox Messageheader Analyzer
Both provide visual timelines and highlight authentication failures
Microsoft 365 / Exchange Audit Logs
For cloud-hosted email (Microsoft 365), server-side logs provide evidence that survives local PST deletion and show attacker actions in the mailbox:
# Microsoft 365 mailbox audit log queries
# Requires: Exchange Online PowerShell module, Global Admin or Compliance role
Connect-ExchangeOnline
# Search unified audit log for mailbox access
Search-UnifiedAuditLog -StartDate "2026-09-15" -EndDate "2026-09-20" `
-UserIds "jsmith@corp.com" `
-Operations "MailItemsAccessed" `
-ResultSize 1000 |
Select-Object CreationDate, UserIds, Operations,
@{n="Details"; e={$_.AuditData | ConvertFrom-Json}} |
Export-Csv "mailbox-access.csv" -NoTypeInformation
# Hunt for suspicious inbox rules (attacker auto-forward/delete rules)
Get-InboxRule -Mailbox "jsmith@corp.com" |
Where-Object {
$_.ForwardTo -or $_.ForwardAsAttachmentTo -or
$_.DeleteMessage -or $_.MoveToFolder -or $_.RedirectTo
} |
Select-Object Name, ForwardTo, DeleteMessage, MoveToFolder |
Format-Table -AutoSize
# Check for email forwarding rules (SMTP forwarding at account level)
Get-Mailbox "jsmith@corp.com" |
Select-Object ForwardingAddress, ForwardingSmtpAddress, DeliverToMailboxAndForward
# Message Trace — track specific email's delivery path
Get-MessageTrace -SenderAddress "external@domain.com" `
-StartDate "2026-09-15" -EndDate "2026-09-20" |
Select-Object Received, SenderAddress, RecipientAddress, Subject, Status, MessageId |
Format-Table -AutoSize
BEC-Specific Email Forensics Workflow
| Question | Evidence source |
|---|---|
| When did the attacker first access the mailbox? | Unified Audit Log: MailItemsAccessed events; M365 Sign-in logs showing successful auth from attacker IP |
| What emails did the attacker read? | MailItemsAccessed in UAL — shows specific message IDs accessed, timestamped |
| Did the attacker create inbox rules? | New-InboxRule / Set-InboxRule events in UAL; Get-InboxRule on the live mailbox |
| What emails did the attacker send as the victim? | Send and SendAs operations in UAL; Sent Items folder in PST/OST (if not deleted) |
| What phishing email triggered the initial access? | Incoming message in PST, Message Trace from M365, header analysis for originating IP |
Q & A
Q: The attacker deleted all sent items and inbox rules before you could export them. Are they recoverable?
In Microsoft 365, yes — the Recoverable Items folder (also called the "dumpster") retains deleted items for 14-30 days by default, and for much longer if a Litigation Hold or In-Place Hold is enabled. In Exchange Online, Compliance Search via the Security and Compliance Center can search the Recoverable Items folder even after the user has permanently deleted items. Use: New-ComplianceSearch -ContentMatchQuery "..." -ExchangeLocation jsmith@corp.com -AllowNotFoundExchangeLocationsEnabled $true followed by New-ComplianceSearchAction -SearchName ... -Purge -PurgeType HardDelete (to preserve) or Export. The UAL will also show the DeleteMessage events — even if the content is gone, the audit log records that deletion happened and when. Inbox rules deleted via the API also leave UAL events: Remove-InboxRule records are evidence the rule existed even if the rule itself is gone.