imessage-exporter Documentation

Export iMessage data + run iMessage Diagnostics

5,460 stars Rust Rust 1 file ยท ~11,016 tokens #apple#backup#cli-app#export#imessage#reverse-engineering
RAW Doc

File: README.md

imessage-exporter

This crate provides both a library to interact with iMessage data as well as a binary that can perform some useful read-only operations using that data. The aim of this project is to provide the most comprehensive and accurate representation of iMessage data available.

This free and open-source software can:

  • Save, export, backup, and archive iMessage data to open, portable formats
  • Preserve multimedia content (images, videos, audio) from conversations
  • Facilitate easy migration of message history between devices and platforms
  • Run diagnostics on the iMessage database
  • Give you full ownership and control over your communication history
  • Support compliance with data retention policies or legal requirements
  • Run on macOS, Linux, and Windows

Example Export

Binary

The imessage-exporter binary exports iMessage data to txt or html formats. It can also run diagnostics to find problems with the iMessage database.

Installation instructions for the binary are located here.

Library

The imessage_database library provides models that allow us to access iMessage information as native, cross-platform data structures.

Documentation for the library is located here.

Supported Features

This crate supports every iMessage feature as of macOS Golden Gate 27.0 and iOS 27.0:

  • iMessage, RCS, SMS, and MMS
  • Multi-part messages
  • Replies/Threads
  • Formatted text
  • Attachments
  • Expressives
  • Tapbacks
  • Stickers
  • Apple Pay
  • Group chats
  • Digital Touch
  • URL Previews
  • Audio messages
  • App Integrations
  • Edited messages
  • Business messages
  • Handwritten messages

See more detail about supported features here.

Frequently Asked Questions

The FAQ document is located here.

Special Thanks

  • All of my friends, for putting up with me sending them random messages to test things
  • SQLiteFlow, the SQL viewer I used to explore and reverse engineer the iMessage database
  • Xplist, an invaluable tool for reverse engineering the payload_data plist format
  • Compart, an amazing resource for looking up esoteric unicode details
  • GNU Project and Archive.org, for hosting source code referenced to reverse engineer the typedstream format

File: docs/tables/attachment.md

Attachment Table Structure

cid name type notnull dflt_value pk
0 ROWID INTEGER 0 1
1 guid TEXT 1 0
2 created_date INTEGER 0 0 0
3 start_date INTEGER 0 0 0
4 filename TEXT 0 0
5 uti TEXT 0 0
6 mime_type TEXT 0 0
7 transfer_state INTEGER 0 0 0
8 is_outgoing INTEGER 0 0 0
9 user_info BLOB 0 0
10 transfer_name TEXT 0 0
11 total_bytes INTEGER 0 0 0
12 is_sticker INTEGER 0 0 0
13 sticker_user_info BLOB 0 0
14 attribution_info BLOB 0 0
15 hide_attachment INTEGER 0 0 0
16 ck_sync_state INTEGER 0 0 0
17 ck_server_change_token_blob BLOB 0 0
18 ck_record_id TEXT 0 0
19 original_guid TEXT 1 0
20 is_commsafety_sensitive INTEGER 0 0 0
21 emoji_image_content_identifier TEXT 0 NULL 0
22 emoji_image_short_description TEXT 0 NULL 0
23 preview_generation_state INTEGER 0 0 0

File: docs/tables/chat.md

Chat Table Structure

cid name type notnull dflt_value pk
0 ROWID INTEGER 0 1
1 guid TEXT 1 0
2 style INTEGER 0 0
3 state INTEGER 0 0
4 account_id TEXT 0 0
5 properties BLOB 0 0
6 chat_identifier TEXT 0 0
7 service_name TEXT 0 0
8 room_name TEXT 0 0
9 account_login TEXT 0 0
10 is_archived INTEGER 0 0 0
11 last_addressed_handle TEXT 0 0
12 display_name TEXT 0 0
13 group_id TEXT 0 0
14 is_filtered INTEGER 0 0 0
15 successful_query INTEGER 0 0
16 engram_id TEXT 0 0
17 server_change_token TEXT 0 0
18 ck_sync_state INTEGER 0 0 0
19 original_group_id TEXT 0 0
20 last_read_message_timestamp INTEGER 0 0 0
21 cloudkit_record_id TEXT 0 0
22 last_addressed_sim_id TEXT 0 0
23 is_blackholed INTEGER 0 0 0
24 syndication_date INTEGER 0 0 0
25 syndication_type INTEGER 0 0 0
26 is_recovered INTEGER 0 0 0
27 is_deleting_incoming_messages INTEGER 0 0 0
28 is_pending_review INTEGER 0 0 0

File: docs/tables/duplicates.md

The Duplicate Problem

iMessage has had a long history of splitting both one-on-one and group chats into separate chats. This creates a problem for this tool: in order to iterate over the table of Messages to export them, the tool has to understand where to sort them.

Types of Duplicated Data

Both handles (participants) and chats (threads) can become duplicated, where handle duplication leads to chat duplication.

Duplicate Handles

Handles (contacts) are often duplicated, usually when a contact sends messages from a phone number and an iCloud account. As a result. the phone number and the email address for the same contact may exist under different Handle IDs.

Duplicate Conversations

Because of the aforementioned handle problem, some conversations with the same handle are mapped into separate Chat IDs.

Sample Data

These sample tables help visualize the problem.

Handles Table

Contact A has an email Y and a phone number X. Each are listed in the table under a different Handle ID. Contact B has a single phone number Z. The iMessage database makes no connection to your Contacts app here, it just knows these items exist.

Handle ID Contact Person Centric ID
1 Y A
2 X A
3 Z B

The Person Centric ID is a unique identifier for each contact. Here, we can use it to determine which Handles belong to A and which belong to B.

Chats Table

When you receive a message from A, you either receive from the address Y or Z. Each of these is listed under a separate chat (thread):

Chat ID Handle ID Group ID
10 1 A
11 2 A
12 3 B
12 2 B

Note: The Chat ID is not unique, it represents group chats as well, so in this example there is a group chat 12 with 3 participants, yourself, A, and B.

The Many-To-Many Problem

Chats between yourself and A should go to the same chat, because Y and X are actually the same person. Further, any messages sent to chat 12 from any of the addresses of the participants should go to the same chat, not a separate one with the same participants. This does not happen, because the iMessage Database uses the Handle ID field here, not the Person Centric ID.

If contact A sends messages from Y and X, you will see two separate conversations. Given the above table, messages from Y will go to 10 and messages from X will go to 11, even though said messages should belong to the same chat.

Further, if contact A sends messages from Y and X to you and B, only messages from X will go to chat 12. Messages A sends from Y will go to a new chat, 13, that contains the same participants but with A under a second ID:

Chat ID Handle ID
10 1
11 2
12 3
12 2
13 1
13 3

Chats 12 and 13 are the same group of people, but because the IDs of the participants are different, the messages get sorted into a separate chat.

Solving the Problems

Handles Solution

Applying a small two-pass check solves this problem, since the handles table only contains a few columns of metadata.

First, generate a map of each Person Centric ID to its corresponding handles. The second pass iterates over each handle in the table, building a hashmap of Handle ID to a string that combines all of the corresponding handles' metadata. For example, for the above table, we would generate a hashmap that looks like

json
{
    1: "X, Y",
    2: "X, Y",
    3: "Z"
}

Now, any lookups against a contact ID will result in the same metadata.

Chats Solution

Person Centric ID gives us a unique field that exists on a per-contact basis. In the above handles table, all of the handles associated with A have the same Person Centric ID. If we want to map our conversations against this, we need to fix this many-to-many problem. We can solve it with a few hash tables, with the second containing a new field:

  1. Receive a reference to the hashmap generated for the Handle table
  2. Participants to Unique Chat ID: Set(Person Centric ID) -> Set(Chat ID)
  3. Chat to Unique Chat: Chat ID -> Unique Chat ID

The steps to generate this unique chat identifier are as follows:

  • Generate hashmap 1 that contains all of the sets of participants
  • Generate hashmap 2 by iterating through the values of 1, inserting each new set of participants
  • Generate hashmap 3 by inverting hashmap 2

From here, when we iterate over messages, we can use the Chat to Unique Chat table to organize our messages into the proper chats.


File: docs/tables/handle.md

Handle Table Structure

cid name type notnull dflt_value pk
0 ROWID INTEGER 0 1
1 id TEXT 1 0
2 country TEXT 0 0
3 service TEXT 1 0
4 uncanonicalized_id TEXT 0 0
5 person_centric_id TEXT 0 0

File: docs/tables/messages.md

Messages Table Structure

cid name type notnull dflt_value pk
0 ROWID INTEGER 0 1
1 guid TEXT 1 0
2 text TEXT 0 0
3 replace INTEGER 0 0 0
4 service_center TEXT 0 0
5 handle_id INTEGER 0 0 0
6 subject TEXT 0 0
7 country TEXT 0 0
8 attributedBody BLOB 0 0
9 version INTEGER 0 0 0
10 type INTEGER 0 0 0
11 service TEXT 0 0
12 account TEXT 0 0
13 account_guid TEXT 0 0
14 error INTEGER 0 0 0
15 date INTEGER 0 0
16 date_read INTEGER 0 0
17 date_delivered INTEGER 0 0
18 is_delivered INTEGER 0 0 0
19 is_finished INTEGER 0 0 0
20 is_emote INTEGER 0 0 0
21 is_from_me INTEGER 0 0 0
22 is_empty INTEGER 0 0 0
23 is_delayed INTEGER 0 0 0
24 is_auto_reply INTEGER 0 0 0
25 is_prepared INTEGER 0 0 0
26 is_read INTEGER 0 0 0
27 is_system_message INTEGER 0 0 0
28 is_sent INTEGER 0 0 0
29 has_dd_results INTEGER 0 0 0
30 is_service_message INTEGER 0 0 0
31 is_forward INTEGER 0 0 0
32 was_downgraded INTEGER 0 0 0
33 is_archive INTEGER 0 0 0
34 cache_has_attachments INTEGER 0 0 0
35 cache_roomnames TEXT 0 0
36 was_data_detected INTEGER 0 0 0
37 was_deduplicated INTEGER 0 0 0
38 is_audio_message INTEGER 0 0 0
39 is_played INTEGER 0 0 0
40 date_played INTEGER 0 0
41 item_type INTEGER 0 0 0
42 other_handle INTEGER 0 0 0
43 group_title TEXT 0 0
44 group_action_type INTEGER 0 0 0
45 share_status INTEGER 0 0 0
46 share_direction INTEGER 0 0 0
47 is_expirable INTEGER 0 0 0
48 expire_state INTEGER 0 0 0
49 message_action_type INTEGER 0 0 0
50 message_source INTEGER 0 0 0
51 associated_message_guid TEXT 0 0
52 associated_message_type INTEGER 0 0 0
53 balloon_bundle_id TEXT 0 0
54 payload_data BLOB 0 0
55 expressive_send_style_id TEXT 0 0
56 associated_message_range_location INTEGER 0 0 0
57 associated_message_range_length INTEGER 0 0 0
58 time_expressive_send_played INTEGER 0 0
59 message_summary_info BLOB 0 0
60 ck_sync_state INTEGER 0 0 0
61 ck_record_id TEXT 0 0
62 ck_record_change_tag TEXT 0 0
63 destination_caller_id TEXT 0 0
64 is_corrupt INTEGER 0 0 0
65 reply_to_guid TEXT 0 0
66 sort_id INTEGER 0 0
67 is_spam INTEGER 0 0 0
68 has_unseen_mention INTEGER 0 0 0
69 thread_originator_guid TEXT 0 0
70 thread_originator_part TEXT 0 0
71 syndication_ranges TEXT 0 0
72 synced_syndication_ranges TEXT 0 0
73 was_delivered_quietly INTEGER 0 0 0
74 did_notify_recipient INTEGER 0 0 0
75 date_retracted INTEGER 0 0 0
76 date_edited INTEGER 0 0 0
77 was_detonated INTEGER 0 0 0
78 part_count INTEGER 0 0
79 is_stewie INTEGER 0 0 0
80 is_kt_verified INTEGER 0 0 0
81 is_sos INTEGER 0 0 0
82 is_critical INTEGER 0 0 0
83 bia_reference_id TEXT 0 NULL 0
84 fallback_hash TEXT 0 NULL 0
85 associated_message_emoji TEXT 0 NULL 0
86 is_pending_satellite_send INTEGER 0 0 0
87 needs_relay INTEGER 0 0 0
88 schedule_type INTEGER 0 0 0
89 schedule_state INTEGER 0 0 0
90 sent_or_received_off_grid INTEGER 0 0 0
91 date_recovered INTEGER 0 0 0
92 is_time_sensitive INTEGER 0 0 0
93 ck_chat_id TEXT 0 0

File: docs/diagnostics.md

Diagnostics

Diagnostic output from imessage-exporter looks like:

txt
iMessage Database Diagnostics

Handle diagnostic data:
    Total handles: 552
    Handles with more than one ID: 2
    Total duplicated handles: 100
Message diagnostic data:
    Total messages: 183453
    Messages not associated with a chat: 43210
    Messages belonging to more than one chat: 36
    Recoverable messages: 1
    Date range: Sep 20, 2019  1:53:14 PM to Mar 09, 2026  5:03:14 PM
                6 years, 170 days, 4 hours, 58 minutes, 24 seconds
Attachment diagnostic data:
    Total attachments: 49422
        Data referenced in table: 44.13 GB
        Data present on disk: 31.31 GB
    Missing files: 15037 (30%)
        No path provided: 14929
        No file located: 108
Thread diagnostic data:
    Total chats: 432
    Total duplicated chats: 11
    Chats with no handles: 2
Global diagnostic data:
    Total database size: 339.88 MB
    Handles with resolved names: 231/452 (51%)
    Schema capabilities:
        Recoverable deleted messages: Detected
        Reply threads: Detected
        Tapbacks and poll votes: Detected
        Message filter categories: Detected

Environment Diagnostics

Detected converters:
    Image converter: sips
    Audio converter: afconvert
    Video converter: ffmpeg

Handle diagnostic data

Total handles

The total number of handles present in the provided iMessage database.

Handles with more than one ID

The number of contacts that have multiple entries in the handle table, deduplicated by matching their person_centric_id across rows. The person_centric_id is a field used by Apple to disambiguate contacts. Further deduplication also happens, as noted in the next line.

Total duplicated handles

In addition to the foregoing person_centric_id, other deduplication steps map identical handles across services, number formats, and email formats to the same handle ID. The value reflects the number of handles that had multiple entries in the iMessage database coalesed into a single handle.

Message diagnostic data

Total messages

The total number of rows in the messages table.

Messages not associated with a chat

If a message exists in the messages table but does not have an entry in the chat_message_join table, it is considered orphaned and will be listed in either the Orphaned.html or Orphaned.txt file in the export directory. Likely, these come from messages that were deleted and the chat removed from the chat_message_join table, but the corresponding messages were not removed from the messages table.

Messages belonging to more than one chat

If a message exists in the messages table and maps to multiple chats in chat_message_join, the message will exist in all of those chats when exported.

Recoverable messages

The number of messages that were marked as deleted from conversations but are recoverable and will be rendered in-line in exports.

Date range

The range of total available messages in the database in both exact and relative format.

Attachment diagnostic data

Total attachments

The total number of rows in the attachments table

Data referenced in table

The sum of the total_bytes column in the attachments table. I don't know why they are different, but the former is the actual storage taken up by iMessage attachments.

Data present on disk

Represents the total size of the attachments listed in the attachments when following the listed path to the respective file. Missing files may have been removed by the user or not properly downloaded from iCloud.

Missing files

The first line shows the count and the percentage of files missing. In the example above, 15037 (30%) means that 15,037 files (30% of the total number of attachments) are referenced in the table but do not exist.

There are two different types of missing files:

No path provided

This means there was a row in the attachments table that did not contain a path to a file.

No file located

This means there was a path provided, but there was no file at the specified location.

Thread diagnostic data

Total chats

The total number of chats present in the table.

Total duplicated chats

The number of split group chats that have been coalesced together.

Chats with no handles

Emits the count of chats that contain no chat participants.

Global diagnostic data

Total database size

The total size of the database file on the disk.

Handles with resolved names

The number of handles in the database that were successfully matched to contact names from the contacts index, out of the total number of handles found. This is followed by the match ratio as a percentage.

Schema capabilities

imessage-database probes the database schema once and builds its queries from what the schema actually supports, so databases missing optional features still read correctly. This section shows which optional features the reader detected.

Recoverable deleted messages

Whether the chat_recoverable_message_join table exists. When present, messages deleted within the last 30 days can be read and filtered.

Reply threads

Whether the message.thread_originator_guid column exists. When present, replies can be grouped under the messages they respond to.

Tapbacks and poll votes

Whether the message.associated_message_guid column exists. When present, tapbacks and poll votes can be resolved to the messages they target.

Message filter categories

Whether the message.filter_action and message.filter_sub_action columns exist. When present, the filter category each message was received under is read alongside the row.

Detected converters

imessage-exporter uses third-party tools to convert images when using --copy-method basic or --copy-method full. This section shows what programs are detected on the current system.

Image converter

The currently detected image converter, if present.

One of:

  • sips (macOS Builtin)
  • magick (imagemagick)
  • None

Audio converter

The currently detected audio converter, if present.

One of:

  • afconvert (macOS Builtin)
  • ffmpeg
  • None

Video converter

The currently detected video converter, if present.

One of:

  • ffmpeg
  • None

File: docs/faq.md

Frequently Asked Questions

I cannot connect to the messages database. What do I do?

Ensure your terminal emulator has full disk access if using the default location or ensure that the path to the database file is correct. You can enable this in System Settings > Privacy & Security > Full Disk Access.


Are emojis, tapbacks (reactions), and other special message features preserved in the export?

Yes, all iMessage features are supported. See here for more detail.


Can it export messages from third-party apps that integrate with iMessage?

Yes. See here for more detail on supported features.


Does `imessage-exporter` export message conversations that are in iCloud or on a user's iPhone/iPad but not on the user's Mac?

imessage-exporter only reads data present in the provided source, which can be a macOS chat.db, a local iOS backup (encrypted or unencrypted), or a jailbroken iOS sms.db. It cannot read data that is only stored in iCloud.


Can I force iCloud to download attachments that were offloaded?

In the Messages app, if you click the info (โ“˜) button for a conversation and scroll to the bottom, there is a button that downloads all of the attachments for that conversation. This works on both macOS and iOS.

Can it export group conversations as well as individual chats?

Yes.


Can I export only specific conversations?

Yes, the --conversation-filter (-t) argument filters by contact name, phone number, or email. Multiple filters can be comma-separated, e.g., -t "[email protected],5558675309". Substring matching is supported, so -t "+1555" matches all numbers with that prefix. All conversations containing the matched participants are included.

See here for details on imessage-exporter arguments.


How does the exporter handle previously exported messages?

If files with the current output type exist in the output directory, imessage-exporter will alert the user and the export will not start. If the export directory is clear, imessage-exporter will export all messages by default. Alternatively, it will export messages between the dates specified by the --start-date and --end-date arguments.

See here for details on imessage-exporter arguments.


Is it possible to export a conversation and re-integrate it back onto another Apple ID?

No, I do not want to be trusted with write access to your iMessage data. This software is read only.


Is there a search function?

No, this software just builds exports. I use ripgrep to search though the exported files.


Can it export messages between a specific date range?

Yes, the --start-date and --end-date arguments specify date ranges for exports.

See here for details on imessage-exporter arguments.


Are voice messages saved?

Expired ones cannot be because they are deleted from disk by the system. If you kept them, they are included in the exports.


Are messages deleted from the messages app erased from the database?

This software can recover some, but not all, deleted messages.

Messages removed by deleting an entire conversation or by deleting a single message from a conversation are moved to a separate collection for up to 30 days. Messages present in this collection are restored to the conversations they belong to. Apple details this process here.

Messages that have expired from this restoration process are permanently deleted and cannot be recovered.

In some instances, deleted messages are removed from the chat_message_join table but not from the messages table. These messages will populate in orphaned.html or orphaned.txt.


What is the `orphaned` file in my export?

Messages that cannot be associated with any conversation are written to orphaned.html or orphaned.txt. This can happen when a message's chat has been deleted from the chat_message_join table, or when the database has inconsistencies. These messages are preserved so no data is lost.


What export formats are supported? Can I export to PDF?

imessage-exporter supports txt and html export formats. There is no native PDF export, but you can export as HTML and then print to PDF from Safari. Use the --no-lazy flag when exporting for PDF, as it disables lazy-loading of images which is required for the print-to-PDF workflow to include all images.


How do I customize the appearance of HTML exports?

Each HTML export file links to an external style.css in the export directory. You can create this file to override the default styles. Since custom styles load after the embedded defaults, they take precedence at the same specificity.


What does `--copy-method` do and which should I choose?

  • disabled (default): Attachments are not copied; the export references them in-place by filesystem path
  • clone: Copies all attachment files as-is, preserving original formats and quality
  • basic: Copies all files, converting HEIC images to JPEG for broader compatibility
  • full: Copies all files, converting HEIC to JPEG, CAF/AMR audio to MP4, MOV video to MP4, and animated sticker HEICS to GIF

basic and full require external tools (sips or ImageMagick for images, afconvert or ffmpeg for audio, ffmpeg for video). The --diagnostics output shows which converters are detected on your system.


What does the `--diagnostics` flag show?

Diagnostics mode prints a summary of the database without exporting anything:

  • Handle data: total handles, duplicated handles
  • Message data: total messages, orphaned messages, messages in multiple chats, recoverable deleted messages, and the date range of all messages
  • Attachment data: total attachments, referenced vs. on-disk data sizes, and missing file counts
  • Thread data: total chats, duplicated chats, chats with no handles
  • Global data: database file size, percentage of handles with resolved contact names, and detected media converters

What does `--attachment-root` do?

This option overrides where the app looks for attachment files. It is useful when attachment data is stored separately from the database, such as on an external drive. The provided path replaces the default ~/Library/Messages root and affects both the Attachments and StickerCache directories. It also works with jailbroken iOS sms.db databases (use --platform macOS). This option has no effect on iOS backups.


Why do I see "Unable to build contacts index"?

This warning means the Contacts database could not be read. The export will continue, but participants will be labeled with phone numbers and email addresses instead of resolved contact names. This commonly happens due to missing Full Disk Access permissions, since the contacts database is also protected. You can also specify a custom contacts database path with --contacts-path.


How fast is `imessage-exporter`?

This is a complicated question that depends on CPU, database size, chosen export type, encryption state, and chosen attachment handling style.

On my M1 Max MacBook Pro, approximate performance is as follows:

--copy-method Messages exported per second
disabled > 145,000
clone โ‰ˆ 42,000
basic โ‰ˆ 350
full โ‰ˆ 250

For more information on --copy-method, see here and here.

However, if you recently deleted a large amount of data from Messages, the database will be slow for awhile, resulting in significantly reduced performance from imessage-exporter.


File: docs/features.md

Features

The library and binary crates aim to provide the most comprehensive and accurate representation of iMessage data available.

Targeted Versions

This tool targets the current latest public release for Messages.app. It may work with older databases, but all features may not be available.

Supported data sources

  • Local macOS messages
  • Encrypted or unencrypted local iOS backups
    • Unencrypted backups are resolved normally
    • Encrypted backups are resolved with crabapple
  • Jailbroken iOS filesystem data
    • Uses sms.db, which follows the same schema as macOS chat.db
    • Resolved as a macOS database with an alternate attachment root

Supported Message Features

  • Plain Text
    • Correctly extracts time-zone corrected timestamps
    • Detects when a message was read and calculates the time until read for both parties
      • Humanizes display of time-until-read duration
    • Parses typedstream message body data using crabstep
    • Detects the service a message was sent from
      • In HTML exports, balloons are colored correctly for the service they were sent with
      • Supports iMessage, SMS, MMS, RCS, and Satellite (iMessage Lite)
    • Displays translated message content alongside the original text
    • Resolves contact names from the Contacts database when available
  • Formatted Text
    • Parses formatted text ranges from typedstream message body data
    • Supports all iMessage text format ranges:
      • Mentions
      • Hyperlinks
      • OTP/2FA
      • Animations and Styles
      • Data detectors, parsed from DDScannerResult payloads:
        • Unit and timezone conversions
        • Currency amounts (symbol and amount)
        • Postal addresses (street, city, state, postal code, and country)
        • Package tracking (carrier and tracking number)
        • Flights (airline and flight number)
  • Edited and Unsent messages
    • Detects if messages components were edited or unsent
      • Edited messages
        • Parses typedstream edited body data
        • Displays content and timestamps for each edit
        • Humanizes display of edit timestamp gaps
        • Edited messages received before Ventura display as normal messages without history
      • Unsent messages
        • No content, but are noted in context
    • Recently deleted messages are recovered when available
  • Multi-part messages
    • iMessages can have multiple parts, denoted by ranges in typedstream message body data
    • Parts are displayed as
      • New lines in TXT exports
      • Separate balloons in HTML exports
    • Handles Edited and Unsent parts
  • Threads and Message Replies
    • Threads are displayed both threaded under the parent as well as in-place
      • This is to preserve context, which can be lost if replying to older messages
      • Messages from a thread and were rendered in-place are annotated as such
      • In HTML exports, threaded messages are hyperlinked to allow for easy reading in context
    • For multi-part messages, replies are threaded under the correct message part
  • Attachments
    • Any type of attachment that can be displayed on the web is embedded in the HTML exports
    • Attachments can be copied to the export directory or referenced in-place
    • Less-compatible attachments can be converted for even more portable exports:
      • Image HEIC files convert to JPEG
      • Sticker HEIC files convert to PNG
      • Animated Sticker HEICS (HEIC sequence) files convert to GIF
      • Video MOV files convert to mp4
      • Audio CAF files convert to mp4
      • Audio AMR files convert to mp4
    • Attachments are displayed as
      • File paths in TXT exports
      • Embeds in HTML exports (including ``, <video>, and <audio>)
    • Attachment date metadata is set to the date and time of message receipt
  • Expressives
    • Detects both bubble and screen effects
    • Messages sent with expressives are annotated
  • Tapbacks
    • Detects tapbacks to messages
    • Messages sent or received with tapbacks are annotated
    • For multi-part messages, tapbacks are placed under the correct message part
  • Stickers
    • Detects stickers sent or placed on messages
    • Messages sent with stickers are
      • Displayed in HTML exports
      • Annotated in TXT exports
    • For multi-part messages, stickers are placed under the correct message part
    • Sticker effects are annotated in all exports
    • Sticker tapbacks are also supported
    • Genmoji are displayed with their prompt descriptions
    • Inline stickers (Memoji, Genmoji, and custom stickers placed within the message text) render inline in HTML exports, scaled like jumbo emoji (larger when only a few are present)
  • Apple Pay
    • Displays Apple Pay transaction (source, amount, type) messages
  • URL previews
    • Parses the NSKeyedArchiver payload to extract preview data
      • Extracts cached metadata for each URL
      • Preview images display in HTML exports
      • URLs that have rotten may still retain some context if they have cached data
    • Handles cases where URL messages are overloaded with other message types
      • Apple Music (including preview streams and lyrics)
      • Apple Maps (including Placemark data)
      • App Store (including app metadata)
      • Rich Collaboration
  • App Integrations
    • Parses the NSKeyedArchiver payload to extract balloon data
    • Supports system message types as well as third party applications
      • Apple Fitness messages
      • Photo Slideshow messages
      • SharePlay/Facetime messages
      • Check In messages
      • Find My messages
      • Polls and Votes
      • Business Chat messages
        • Quick Replies
        • Interactive Forms
        • List Pickers
  • Handwritten Messages
    • Parses the protobuf payload to extract handwritten message data
      • Displayed as embedded svg in HTML exports
      • TXT export behavior depends on attachment settings:
        • disabled: embedded inline as an ascii graphic
        • clone, basic, full: saved as an svg file
  • Digital Touch
    • Parses the protobuf payload to extract Digital Touch message data
      • Supports all Digital Touch effects:
        • Taps
        • Sketches
        • Kisses
        • Heartbeats, including heartbreaks
        • Fireballs
        • Photos and videos
      • HTML exports render a static frame depicting the captured data as an embedded svg on a black 4:5 canvas
        • A photo is shown as the canvas backdrop, with any sketch drawn over it
        • A video is shown as an embedded video player
      • TXT exports describe each effect on a single line, including stroke and point counts or beats per minute
  • Duplicated group chats
    • Handles (participants) and chats (threads) can become duplicated
    • On startup:
      • Different handles that belong to the same person are combined
      • Chatrooms that contain identical contacts (i.e., duplicated handles) are combined
      • Divergent chatrooms that map to the same conversation in the chat_lookup table are combined
  • Announcements
    • Handles all types of chatroom announcements
      • Group photo changes
      • Chat participant modifications
      • Phone number changes
      • Chat background settings

File: imessage-database/README.md

imessage-database

This library provides interfaces to interact with iMessage Databases.

Installation

This library is available on crates.io.

Documentation

Documentation is available on docs.rs.

Example

rust,no_run
use imessage_database::{
    error::table::TableError,
    tables::{
        messages::Message,
        table::{get_connection, Table},
    },
    util::dirs::default_db_path,
};

fn iter_messages() -> Result<(), TableError> {
    // Create a read-only connection to an iMessage database
    let db = get_connection(&default_db_path()).unwrap();

    // Iterate over a stream of messages
    Message::stream(&db, |message_result| {
        match message_result {
            Ok(mut message) => {
                // Deserialize the message body
                if let Ok(body) = message.parse_body(&db) {
                    message.apply_body(body);
                }

                // Emit debug info for each message
                println!("Message: {:#?}", message)
            },
            Err(e) => eprintln!("Error: {:?}", e),
        };

        // You can substitute your own closure error type
        Ok::<(), TableError>(())
    })?;

    Ok(())
}