Email Analysis Investigation Guide
Investigating a suspicious email end to end: reading headers and authentication results correctly, extracting and decoding URLs and QR codes, validating attachments from the raw EML, and checking the sender domain.
On this page
- Step 1: Headers and authentication
- Received headers: the mail path
- SPF: is this server allowed to send for the envelope domain?
- DKIM: is there a valid signature, and whose?
- DMARC: does authentication match the From address?
- The forwarding false positive
- Step 2: URLs and QR codes
- QR codes
- Step 3: Attachments
- Verify the real file type from the EML
- Step 4: Sender domain
- Putting it together
Most email security platforms do the first pass for you: they flag authentication failures, extract URLs and attachments, and highlight mismatched senders. Start there. This guide covers what to do when the platform view isn’t enough, including manual analysis of the raw .eml file.
The workflow:
Headers and authentication -> URLs and QR codes -> attachments -> sender domain -> verdict
For the full response side (preserving the email, scoping recipients, containment), see Step-by-Step Investigation of a Phishing Email.
Step 1: Headers and authentication
Received headers: the mail path
Each mail server that handles the message adds a Received header to the top. Read them bottom to top to follow the message from origin to inbox.
The top entries were added by your own mail servers and can be trusted. The lower entries were added before the message reached you, and an attacker can forge them. The most useful line is usually the first one your infrastructure added: it shows the real IP that handed you the message.
Received: from mx.recipient.example (203.0.113.10) by mailstore.recipient.example ... <- your servers
Received: from mail.sender.example (198.51.100.25) by mx.recipient.example ... <- who handed you the message
Received: from [192.0.2.44] by mail.sender.example ... <- origin (forgeable)
What to look for:
- a handoff IP or host that doesn’t fit the claimed sender and isn’t a known mail service
- gaps or reversals in the timestamps between hops
- a handoff IP with bad reputation in threat intelligence
A From domain that differs from the sending server is not a red flag on its own. Legitimate mail is routinely sent through third-party services (Microsoft 365, Google Workspace, marketing and ticketing platforms).
SPF: is this server allowed to send for the envelope domain?
SPF checks the envelope sender (the Return-Path, or smtp.mailfrom in the results), not the From address the user sees. An attacker can pass SPF for a domain they own while the visible From shows someone else’s domain.
| Result | Meaning |
|---|---|
pass |
The sending IP is authorized for the envelope domain |
fail |
The domain says this IP is not authorized (-all) |
softfail |
Probably not authorized; accepted but marked (~all) |
neutral |
The domain’s record deliberately makes no assertion (?all) |
none |
The domain has no SPF record |
permerror / temperror |
The record is broken, or DNS failed during the check |
DKIM: is there a valid signature, and whose?
DKIM adds a cryptographic signature to the message. The d= value is the domain that signed it.
dkim=passproves the message was signed byd=and not changed since. It says nothing about whetherd=is the domain the user thinks they’re dealing with.dkim=failis common and usually benign. Mailing lists, footers and disclaimers, and security gateways that rewrite links all modify messages after signing. Treat a failure as a reason to look closer, not as evidence of tampering.- No DKIM signature at all is common in spoofed mail, and in some small legitimate senders.
DMARC: does authentication match the From address?
DMARC is what connects authentication to the From address the user sees. It passes only if SPF or DKIM passes and that passing domain aligns with the From domain.
That’s why this combination is the classic spoof:
Authentication-Results: mx.recipient.example;
spf=pass smtp.mailfrom=bulk-mailer.example;
dkim=pass header.d=bulk-mailer.example;
dmarc=fail (p=reject) header.from=yourbank.example
SPF and DKIM both pass, for the attacker’s own domain. Neither aligns with yourbank.example, so DMARC fails.
The domain’s DMARC policy tells receivers what to do on failure: p=none (just report), p=quarantine (junk it), or p=reject (block it). Many legitimate domains still publish p=none, so a DMARC failure there is common and weak on its own. A failure against p=reject that still reached the inbox deserves a hard look.
The forwarding false positive
A common false positive: legitimate mail that was forwarded.
- A partner at
partner.exampleemails[email protected]. - That mailbox auto-forwards to an external address.
- The final receiver sees the message arrive from
company.example’s servers, which aren’t inpartner.example’s SPF record, so SPF fails.
What rescues it:
- DKIM usually survives forwarding if the message wasn’t modified, and an aligned DKIM pass means DMARC still passes.
- SRS (Sender Rewriting Scheme) rewrites the envelope sender during forwarding so SPF is checked against the forwarder instead.
- ARC (
ARC-Seal,ARC-Authentication-Resultsheaders) records the authentication results as they were at each hop, so a trusted forwarder’s earlier pass is preserved.
Before calling an SPF failure malicious, check for forwarding hops in the Received chain and for ARC headers.
Step 2: URLs and QR codes
Use the platform’s link extraction, or pull URLs from the raw EML. Then check them without clicking:
- reputation: VirusTotal, URLScan.io
- safe rendering: URLScan.io screenshots, or an isolated browser service such as Browserling
Things that hide the real destination:
- Security link wrappers. Rewritten “safe link” URLs carry the original URL as an encoded parameter. Decode it before assessing.
- Encoding. Base64 or percent-encoded URLs and JavaScript redirects decode cleanly in CyberChef.
- Recipient tracking. A URL containing the recipient’s email address (plain or Base64) is a strong credential-phishing signal: the kit pre-fills the victim’s login.
QR codes
QR codes move the link out of text where scanners look. In the raw EML, the MIME headers only tell you where the image is:
Content-Type: image/png; name="qrcode.png"
Content-Disposition: inline; filename="qrcode.png"
Content-Transfer-Encoding: base64
Content-ID: <[email protected]>
The URL is inside the image itself. Copy the Base64 block under those headers into CyberChef and apply From Base64 then Parse QR Code to read the destination, then assess it like any other URL.
Red flags:
- the recipient’s email address embedded in the URL
- redirect chains that end on an unrelated domain
- a CAPTCHA or “human verification” step in front of a login page, which is often there to keep scanners out
Step 3: Attachments
Start in the platform’s attachment view: check the file hash against VirusTotal, Hybrid Analysis, or Joe Sandbox, and use the platform’s safe preview to see the rendered document.
Red flags in the content:
- login forms, credential requests, or payment and banking changes
- links or buttons leading to login pages
- mismatched branding, fonts, or distorted images
- an extension that doesn’t match the real file type (next section)
Verify the real file type from the EML
Attackers disguise file types: invoice.pdf.exe, an HTML file named like a document, or a ZIP renamed to .pdf. When the platform doesn’t extract the attachment cleanly, check it from the raw EML.
-
Open the raw EML and find the attachment’s MIME part:
Content-Disposition: attachment; filename="invoice.pdf" Content-Transfer-Encoding: base64 JVBERi0xLjQKJ... -
Copy the Base64 block into CyberChef and apply From Base64, then To Hex (or Detect File Type).
-
Compare the first bytes with a signature list such as Gary Kessler’s file signatures.
| File type | First bytes (hex) |
|---|---|
25 50 44 46 (%PDF) |
|
| ZIP, and Office DOCX / XLSX / PPTX | 50 4B 03 04 (PK) |
| Windows executable or DLL | 4D 5A (MZ) |
| Legacy Office (DOC / XLS) and MSI | D0 CF 11 E0 |
| Windows shortcut (LNK) | 4C 00 00 00 |
| RTF | 7B 5C 72 74 66 ({\rtf) |
JVBERi0 in the example decodes to 25 50 44 46: the file really is a PDF. A matching signature only confirms the type. A real PDF can still carry malicious links or scripts, so it goes through the content checks above like anything else.
HTML attachments deserve extra suspicion: they’re a common way to smuggle a payload or render a fake login page locally, where URL scanning never sees it.
Step 4: Sender domain
WHOIS and DNS:
- Domain age: registered in the last 30 days is a strong signal for a sender domain.
- Registrar and name servers: unusual combinations, or infrastructure shared with known phishing domains.
- Lookalikes: character swaps, extra letters, or a brand name with extra words (
brand-secure-login.example).
Reputation: Cisco Talos Intelligence and AbuseIPDB for the domain and the handoff IP from Step 1.
Weaker signals, useful only alongside others:
- privacy-protected WHOIS (the default at most registrars now)
- inexpensive or free DNS and hosting providers
Putting it together
No single check decides the verdict. Strong cases combine several:
DMARC fail against the From domain
+ newly registered lookalike sending domain
+ URL carrying the recipient's address behind a CAPTCHA page
= credential phishing
A single weak signal, such as an SPF softfail on forwarded mail or privacy-protected WHOIS, is usually not enough on its own. Write down which evidence carried the verdict, so the next analyst can follow the reasoning.