Messages

Message Attachments

Overview

When users send or receive files, images, videos, or other media through Messages.app, Apple stores attachment metadata in the attachment table of chat.db and the actual files in a structured directory under ~/Library/Messages/Attachments/. The metadata provides forensic evidence of file transfers even when the attachment files themselves have been deleted from disk.

Each attachment is linked to its parent message through the message_attachment_join table, and a single message can have multiple attachments.

File Locations

ArtifactPath
Attachment metadata~/Library/Messages/chat.db (attachment table)
Attachment files~/Library/Messages/Attachments/{00-ff}/{UUID}/filename

The Attachments directory uses a two-level hexadecimal sharding scheme:

~/Library/Messages/Attachments/
  00/
  01/
  ...
  ab/
    A1B2C3D4-E5F6-7890-ABCD-EF1234567890/
      photo.jpg
  ...
  ff/

Database Schema

attachment Table

CREATE TABLE attachment (
    ROWID INTEGER PRIMARY KEY AUTOINCREMENT,
    guid TEXT UNIQUE NOT NULL,
    created_date INTEGER DEFAULT 0,         -- Core Data nanoseconds
    start_date INTEGER DEFAULT 0,
    filename TEXT,                           -- Full local filesystem path
    uti TEXT,                                -- Uniform Type Identifier
    mime_type TEXT,                          -- MIME content type
    transfer_state INTEGER DEFAULT 0,       -- Transfer status
    is_outgoing INTEGER DEFAULT 0,          -- 1 = sent, 0 = received
    user_info BLOB,
    transfer_name TEXT,                     -- Original filename as sent
    total_bytes INTEGER DEFAULT 0,          -- File size in bytes
    is_sticker INTEGER DEFAULT 0,           -- 1 = sticker, not file attachment
    sticker_user_info BLOB,
    attribution_info BLOB,
    hide_attachment INTEGER DEFAULT 0,
    ck_sync_state INTEGER DEFAULT 0,
    ck_server_change_token_blob BLOB,
    ck_record_id TEXT,
    original_guid TEXT,
    sr_ck_sync_state INTEGER DEFAULT 0,
    sr_ck_server_change_token_blob BLOB,
    sr_ck_record_id TEXT,
    is_commsafety_sensitive INTEGER DEFAULT 0  -- Communication Safety flag
);

message_attachment_join Table

CREATE TABLE message_attachment_join (
    message_id INTEGER REFERENCES message(ROWID) ON DELETE CASCADE,
    attachment_id INTEGER REFERENCES attachment(ROWID) ON DELETE CASCADE,
    UNIQUE(message_id, attachment_id)
);

Key Fields for Analysis

ColumnForensic Significance
filenameFull path to the file on disk; may begin with ~/ or absolute path
transfer_nameOriginal filename as named by the sender
mime_typeMIME type (e.g., image/jpeg, application/pdf)
utiApple Uniform Type Identifier (e.g., public.jpeg)
total_bytesFile size; 0 may indicate a failed or pending transfer
is_outgoingDirection: 1 = user sent the file, 0 = user received it
transfer_stateTransfer status: 0 = not started, 3 = in progress, 5 = complete
is_stickerDistinguishes sticker images from regular file attachments
is_commsafety_sensitiveFlagged by Apple Communication Safety (child safety feature)
created_dateWhen the attachment record was created (Core Data nanoseconds)

Transfer State Values

ValueMeaning
0Not started / queued
3Transfer in progress
5Transfer complete

Useful Queries

-- List all attachments with their message context
SELECT
    datetime(a.created_date / 1000000000 + 978307200, 'unixepoch') AS created_utc,
    a.transfer_name AS original_name,
    a.mime_type,
    a.total_bytes,
    CASE WHEN a.is_outgoing = 1 THEN 'SENT' ELSE 'RECEIVED' END AS direction,
    a.filename AS local_path,
    m.guid AS message_guid
FROM attachment a
JOIN message_attachment_join maj ON maj.attachment_id = a.ROWID
JOIN message m ON maj.message_id = m.ROWID
ORDER BY a.created_date DESC;

-- Largest attachments
SELECT transfer_name, mime_type, total_bytes, filename
FROM attachment
WHERE total_bytes > 0
ORDER BY total_bytes DESC
LIMIT 20;

Timestamps

The created_date and start_date columns use Core Data nanosecond timestamps (nanoseconds since 2001-01-01 00:00:00 UTC).

UTC datetime = datetime(created_date / 1000000000 + 978307200, 'unixepoch')

Analysis Notes

  • File existence: The filename column may reference a file that no longer exists on disk. The attachment metadata persists in the database even after the user deletes the file or clears the Messages attachment storage.
  • Path format: Paths may use ~/Library/Messages/Attachments/... with tilde notation or absolute paths. Both forms reference the same location.
  • Stickers vs attachments: The is_sticker flag distinguishes decorative sticker images from genuine file transfers. Stickers are typically small images applied as overlays on messages.
  • Hidden attachments: The hide_attachment flag indicates attachments that are not displayed in the conversation UI, such as certain system-generated attachments or rich link previews.
  • Communication Safety: On macOS 14+ with Communication Safety enabled, is_commsafety_sensitive flags attachments detected as potentially sensitive content.
  • Tilde expansion: When correlating filename paths to actual files on disk, replace the leading ~ with the user's home directory path (e.g., /Users/username).

Version Differences

macOS VersionChanges
10.15 CatalinaBaseline schema
14 Sonomais_commsafety_sensitive column added
15 SequoiaRCS attachment support

Tool Support

ToolCapability
macforCollects attachment metadata with message association; does not copy attachment files by default
sqlite3 CLIManual querying of attachment table

References

Previous
Chat Database