1 Envelope, header, body
SMTP transports a message with an envelope (MAIL FROM, RCPT TO) that the servers
use for delivery. The header (From:, To:, Subject:, Date:)
is part of the message and is written by the sender's program; nothing forces it to match the envelope. That is why
From: alone proves nothing. A .eml file is the message as stored: header lines, an empty
line, the body.
- Date: set by the sender's computer, with its clock and its zone.
- Message-ID: a unique ID set by the first program that handled the message. Servers log it, so it links the file to server logs. In-Reply-To and References point to earlier messages of a thread.
- X-Originating-IP, X-Mailer, User-Agent: optional hints about the sender's network and program.
2 The Received chain
Each server adds Received: from X by Y with Z id …; date on top of the header. The oldest line
is at the bottom. In each line, by is the server that wrote it, and from is what the previous host
claimed to be, followed in brackets by the address the writing server actually saw. Only lines written by servers you
trust (your own organisation's) are reliable; a sender can put forged Received lines below them.
Header analyser
Three servers wrote three different zone notations (-0500, +0100, +0000), but
in UTC the hops are seconds apart, as they should be. Large gaps or times going backwards point to wrong clocks,
queued mail, or forged lines. The bottom line also shows the sender's private address (192.168.1.20) and
the public address their router used (203.0.113.77).
3 SPF, DKIM, DMARC
Three DNS-based checks, recorded by the receiving server in Authentication-Results:
- SPF: is the sending server's address allowed to send for the envelope sender's domain? The domain publishes the list as a TXT record.
- DKIM: a signature over chosen header fields and the body, made with the sending domain's private key; the public key is in DNS. A pass proves the signed parts were not changed after signing by that domain.
- DMARC: the
From:domain's policy: SPF or DKIM must pass for the same domain as the visible sender, otherwise quarantine or reject.
The SPF record is just a DNS answer. Here is the TXT answer for example.net, and the MX answer that says
which servers receive mail for it:
4 MIME, base64 and encoded words
Attachments and non-ASCII text are encoded. A multipart/mixed message is split by a
boundary string into parts, each with its own Content-Type,
Content-Transfer-Encoding (base64 or quoted-printable) and, for attachments,
Content-Disposition: attachment; filename=…. Headers with umlauts use encoded words such as
=?utf-8?Q?Gr=C3=BC=C3=9Fe?=. Decode, then hash each attachment: the hash links it to copies found
elsewhere.
Decoder
On the server side, mail systems keep a message tracking log: one line per step (receive, deliver, fail), with time, sender, recipients, subject, size and Message-ID, often for 30 days or more. It covers messages that were deleted from mailboxes, and messages that were blocked and never delivered.
5 Try it yourself
Use the analyser and the hex views above.
From which public IP address did the sender's computer hand the example message to the first server?
The bottom Received line, the address in brackets after from.
203.0.113.77, as seen and recorded by relay.example.net. The [192.168.1.20]
before it is what the client announced (its private LAN address); it is only a claim.
How many seconds passed between the first and the last Received hop of the example message?
Convert all three times to UTC first.
03:00:59 −0500 = 08:00:59 UTC; 09:01:05 +0100 = 08:01:05 UTC; 08:01:07 UTC. 08:01:07 − 08:00:59 = 8 seconds.
Which network does the SPF record of example.net allow to send mail directly?
Read the TXT answer: the ip4: mechanism.
198.51.100.0/24, plus whatever _spf.mailhost.example lists (include:).
-all means everything else fails. The relay in the example (198.51.100.30) is inside the range, so SPF passes.
Which Received line of a message in your own mailbox can you trust the most?
Who could have written each line?
The top one. Your own server wrote it. Every line below came from servers outside your control, and the lowest ones could have been written by the sender. Received lines are not signed.
These are the bytes of the SPF TXT record: a length byte, then the text. Edit them and watch the decoded answer:
- Change
2D(the "-" beforeall, the last but three byte) to7E("~"). What does~allmean for mail from other servers? - Change the first byte (the length,
3D= 61) to10. What does a resolver now read as the record, and what happens to the rest?