User activityFile accessNetwork
Apple Mail: Envelope Index and EMLX on macOS
Apple Mail keeps message metadata in the Envelope Index SQLite database and each message as an .emlx file, showing email sent, received and opened.
- Location
- ~/Library/Mail/V10/MailData/Envelope Index
- Proves
- Which emails were sent or received, from and to whom, when, in which mailbox, and which attachments were opened
- Timestamps
- Envelope Index dates in Unix epoch seconds (UTC); message headers in RFC 5322 local time
- Access
- TCC-protected (Mail data): Full Disk Access for the collector
- Retention
- Until deleted or removed from the server; local copies follow account sync settings
- Collection
- Disk image, ditto
Tools
Compare all tools- Messaging ForensicsIn browser
- sqlite3CLI · built into macOS
- emlxLibrary · open source
What it is
Apple Mail stores each message as a separate .emlx file inside per-account mailbox bundles, and indexes all of them in a SQLite database named Envelope Index (no file extension). The index holds one row per message with sender, subject, dates, mailbox and flags, which makes it the fastest way to build an email timeline. The .emlx files hold the full raw message, including headers, body and (when downloaded) attachments.
The data lives in a versioned folder, ~/Library/Mail/V<n>/, whose number changes with major Mail releases.
Where it lives
| macOS | Mail folder |
|---|---|
| 11 Big Sur | ~/Library/Mail/V8/ |
| 12 Monterey | ~/Library/Mail/V9/ |
| 13 Ventura and later | ~/Library/Mail/V10/ |
| Item | Path |
|---|---|
| Envelope Index | ~/Library/Mail/V<n>/MailData/Envelope Index (+ -wal, -shm) |
| Accounts | ~/Library/Mail/V<n>/<account UUID>/ |
| Messages | .../<Mailbox>.mbox/<UUID>/Data/<digits>/Messages/<ROWID>.emlx |
| Partial downloads | <ROWID>.partial.emlx next to the above |
| Opened attachments | ~/Library/Containers/com.apple.mail/Data/Library/Mail Downloads/ |
~/Library/Mail and the Mail container are protected by macOS privacy controls since Mojave: the collecting process needs Full Disk Access. After upgrades or migrations, older V<n> folders can remain; the active one is normally the highest number with recent modification times, but examine all of them.
What it proves
- Messages present in each mailbox, with sender, subject, sent and received times, read, flagged and deleted state.
- Recipients (To and Cc) through the
recipientstable. - Which accounts were configured (mailbox URLs carry the account UUID and scheme such as
imap://orlocal://). - Attachments the user opened from Mail, through copies in
Mail Downloads. - Full message content and headers (including
Received:chains andMessage-ID) from.emlx.
It does not prove the user read a message just because read is set (rules, other devices and server sync can set flags), and it cannot show messages that were never downloaded to this Mac.
Key fields
Envelope Index (column names as seen on V10; check .schema on older versions):
| Table | Columns | Meaning |
|---|---|---|
messages | ROWID, sender, subject, date_sent, date_received, mailbox, read, flagged, deleted, conversation_id, global_message_id, remote_id, date_last_viewed | One row per message; sender, subject, mailbox are foreign keys |
subjects | ROWID, subject | Deduplicated subjects |
addresses | ROWID, address, comment | Email address and display name |
recipients | message, address, type, position | Recipients per message |
mailboxes | ROWID, url, total_count, unread_count | Mailbox URL per account |
message_global_data | ROWID, message_id_header | RFC Message-ID |
attachments | message, attachment_id, ... | Attachment records |
.emlx layout: a first line with the byte length of the message, then the raw RFC 822 / MIME message, then an XML property list with Mail metadata such as flags, date-received, date-last-viewed, conversation-id and remote-id (observed on V10).
The ROWID in messages is also the .emlx file name, which links index rows to files.
Timestamps
date_sentanddate_receivedin the Envelope Index are Unix epoch seconds (UTC), not Mac absolute time. Adding 978307200 shifts them 31 years into the future, a known mistake..emlxheaders carry the sender'sDate:in their own time zone, andReceived:headers carry server times.- File system times on
.emlxfiles show when Mail wrote them locally.
SELECT datetime(date_received, 'unixepoch') AS received_utc FROM messages LIMIT 5;
Retention
Messages stay until the user deletes them and the deletion is purged, or until the server copy is removed and Mail syncs. Trash and junk handling follow per-account settings. Attachment copies in Mail Downloads persist until removed. An Envelope Index rebuild (Mail rebuilds it when damaged) reindexes from the .emlx store, so rows for files already gone will not reappear.
Collection
# Terminal with Full Disk Access; quit Mail first if possible
mkdir -p case/mail
ditto ~/Library/Mail case/mail/Mail
ditto ~/Library/Containers/com.apple.mail/Data/Library/Mail\ Downloads case/mail/MailDownloads
shasum -a 256 case/mail/Mail/V*/MailData/Envelope\ Index*
- Mail can hold tens of gigabytes; a Data volume image is often more practical than a logical copy.
- Copy the
-waland-shmfiles withEnvelope Index.
Parsing
sqlite3against a copy of the index:
SELECT datetime(m.date_received, 'unixepoch') AS received_utc,
datetime(m.date_sent, 'unixepoch') AS sent_utc,
a.address AS sender, a.comment AS sender_name,
s.subject, mb.url AS mailbox, m.read, m.deleted, m.ROWID
FROM messages m
LEFT JOIN addresses a ON a.ROWID = m.sender
LEFT JOIN subjects s ON s.ROWID = m.subject
LEFT JOIN mailboxes mb ON mb.ROWID = m.mailbox
ORDER BY m.date_received;
- Locate the file for a row:
find case/mail/Mail/V10 -name '<ROWID>.emlx' -o -name '<ROWID>.partial.emlx'. - emlx (Python) parses
.emlxinto headers, body and the Apple plist. Stripping the first line also gives a standard.emlfor any mail viewer.
Investigator tips
- Mailbox URLs are percent-encoded (
Sent%20Messages); decode them before reporting. - Mail sets the quarantine attribute on attachments it saves; read it on files in
Mail Downloadsand look for a matching QuarantineEventsV2 entry to show when an attachment left Mail. See quarantine events and Gatekeeper. - Rows with no matching
.emlxare messages whose bodies were never downloaded or were removed from disk. - Spotlight indexes
.emlxfiles, which gives a second, independent view of mail metadata to compare with the Envelope Index. - Compare new-mail notifications and Messages for a combined communications timeline.
- Phishing cases: extract
Received:and authentication headers from the.emlx, not from the index, which does not store them.