├── .github
└── workflows
│ └── test.yml
├── .gitignore
├── Cargo.lock
├── Cargo.toml
├── LICENSE
├── README.md
├── build.sh
├── docs
├── binary
│ └── img
│ │ ├── icloud_download.png
│ │ └── safari_local_file_restrictions.png
├── diagnostics.md
├── faq.md
├── features.md
├── hero.png
└── tables
│ ├── attachment.md
│ ├── chat.md
│ ├── duplicates.md
│ ├── handle.md
│ └── messages.md
├── imessage-database
├── Cargo.toml
├── README.md
├── build.rs
├── src
│ ├── error
│ │ ├── attachment.rs
│ │ ├── handwriting.rs
│ │ ├── message.rs
│ │ ├── mod.rs
│ │ ├── plist.rs
│ │ ├── query_context.rs
│ │ ├── streamtyped.rs
│ │ ├── table.rs
│ │ └── typedstream.rs
│ ├── lib.rs
│ ├── message_types
│ │ ├── app.rs
│ │ ├── app_store.rs
│ │ ├── collaboration.rs
│ │ ├── digital_touch
│ │ │ ├── digital_touch.proto
│ │ │ ├── digital_touch_proto.rs
│ │ │ ├── mod.rs
│ │ │ └── models.rs
│ │ ├── edited.rs
│ │ ├── expressives.rs
│ │ ├── handwriting
│ │ │ ├── handwriting.proto
│ │ │ ├── handwriting_proto.rs
│ │ │ ├── mod.rs
│ │ │ └── models.rs
│ │ ├── mod.rs
│ │ ├── music.rs
│ │ ├── placemark.rs
│ │ ├── sticker.rs
│ │ ├── text_effects.rs
│ │ ├── url.rs
│ │ └── variants.rs
│ ├── tables
│ │ ├── attachment.rs
│ │ ├── chat.rs
│ │ ├── chat_handle.rs
│ │ ├── handle.rs
│ │ ├── messages
│ │ │ ├── body.rs
│ │ │ ├── message.rs
│ │ │ ├── mod.rs
│ │ │ ├── models.rs
│ │ │ ├── query_parts.rs
│ │ │ └── tests
│ │ │ │ ├── announcement.rs
│ │ │ │ ├── date_tests.rs
│ │ │ │ ├── edited_tests.rs
│ │ │ │ ├── expressive_tests.rs
│ │ │ │ ├── guid_tests.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── query_tests.rs
│ │ │ │ └── variant.rs
│ │ ├── mod.rs
│ │ └── table.rs
│ └── util
│ │ ├── bundle_id.rs
│ │ ├── dates.rs
│ │ ├── dirs.rs
│ │ ├── mod.rs
│ │ ├── output.rs
│ │ ├── platform.rs
│ │ ├── plist.rs
│ │ ├── query_context.rs
│ │ ├── size.rs
│ │ ├── streamtyped.rs
│ │ └── typedstream.rs
└── test_data
│ ├── app_message
│ ├── ApplePayRecurring.plist
│ ├── Business.plist
│ ├── CheckinEnded.plist
│ ├── CheckinLate.plist
│ ├── CheckinLocation.plist
│ ├── CheckinTimer.plist
│ ├── FindMy.plist
│ ├── Game.plist
│ ├── OpenTableInvited.plist
│ ├── Sent265.plist
│ └── Slideshow.plist
│ ├── app_store
│ └── AppStoreLink.plist
│ ├── chat_properties
│ ├── ChatProp1.plist
│ ├── ChatProp2.plist
│ ├── ChatProp3.plist
│ └── ChatProp4.plist
│ ├── collaboration_message
│ └── Freeform.plist
│ ├── db
│ └── test.db
│ ├── digital_touch_message
│ ├── fireball.bin
│ ├── heartbeat.bin
│ ├── heartbreak.bin
│ ├── kiss.bin
│ ├── sketch.bin
│ └── tap.bin
│ ├── edited_message
│ ├── Deleted.plist
│ ├── Edited.plist
│ ├── EditedAndDeleted.plist
│ ├── EditedAndUnsent.plist
│ ├── EditedToLink.plist
│ ├── EditedToLinkAndBack.plist
│ ├── EditedWithFormatting.plist
│ └── MultiPartOneDeleted.plist
│ ├── handwritten_message
│ ├── handwriting.ascii
│ ├── handwriting.bin
│ ├── handwriting.svg
│ ├── handwriting_half.ascii
│ ├── hello.ascii
│ ├── hello.bin
│ ├── hello.svg
│ ├── pollock.ascii
│ ├── pollock.bin
│ ├── pollock.svg
│ ├── test.ascii
│ ├── test.bin
│ └── test.svg
│ ├── music_message
│ ├── AppleMusic.plist
│ └── AppleMusicLyrics.plist
│ ├── shared_placemark
│ └── SharedPlacemark.plist
│ ├── stickers
│ ├── comic.heic
│ ├── no_effect.heic
│ ├── outline.heic
│ ├── puffy.heic
│ └── shiny.heic
│ ├── typedstream
│ ├── 35123
│ ├── 0123456789
│ ├── AppMessage
│ ├── AppleMusicLyrics
│ ├── Array
│ ├── Attachment
│ ├── AttachmentI16
│ ├── AttributedBodyTextOnly
│ ├── AttributedBodyTextOnly2
│ ├── Blank
│ ├── Code
│ ├── CustomReaction
│ ├── Date
│ ├── EditedWithFormatting
│ ├── Email
│ ├── EmojiBoldUnderline
│ ├── ExtraData
│ ├── Formatted
│ ├── LongMessage
│ ├── Mention
│ ├── MultiAttachment
│ ├── MultiPart
│ ├── MultiPartWithDeleted
│ ├── OverlappingFormat
│ ├── PhoneNumber
│ ├── SingleLink
│ ├── StyledLink
│ ├── TextEffects
│ ├── TextStyles
│ ├── TextStylesMixed
│ ├── TextStylesSingleRange
│ ├── Transcription
│ ├── URL
│ ├── URLMessage
│ └── WeirdText
│ └── url_message
│ ├── MetadataURL.plist
│ ├── Reminder.plist
│ ├── Twitter.plist
│ └── URL.plist
└── imessage-exporter
├── Cargo.toml
├── README.md
└── src
├── app
├── compatibility
│ ├── attachment_manager.rs
│ ├── backup.rs
│ ├── converters
│ │ ├── audio.rs
│ │ ├── common.rs
│ │ ├── image.rs
│ │ ├── mod.rs
│ │ ├── sticker.rs
│ │ └── video.rs
│ ├── mod.rs
│ └── models.rs
├── error.rs
├── export_type.rs
├── mod.rs
├── options.rs
├── progress.rs
├── runtime.rs
└── sanitizers.rs
├── exporters
├── exporter.rs
├── html.rs
├── mod.rs
├── resources
│ ├── attachments
│ │ ├── boar.png
│ │ └── davis.jpeg
│ ├── example.html
│ └── style.css
└── txt.rs
└── main.rs
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Test
2 |
3 | on:
4 | pull_request:
5 | branches:
6 | - release
7 | - develop
8 |
9 | env:
10 | CARGO_TERM_COLOR: always
11 |
12 | jobs:
13 | Test:
14 | name: iMessage Exporter Tests
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v4
19 | - run: rustup update stable && rustup default stable
20 | - run: cargo clippy
21 | - run: cargo build
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Development environment
2 | /.vscode
3 |
4 | # Generated files
5 | /target
6 | /output
7 |
8 | # OS Files
9 | .DS_Store
10 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [workspace]
2 | resolver = "2"
3 | members = ["imessage-database", "imessage-exporter"]
4 |
5 | [profile.release]
6 | # Perform Link Time Optimization
7 | lto = true
8 | # Use a single codegen unit for the entire crate
9 | codegen-units = 1
10 | # Do not unwind stack on crash
11 | panic = "abort"
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # imessage-exporter
2 |
3 | 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.
4 |
5 | This free and open-source software can:
6 |
7 | - Save, export, backup, and archive iMessage data to open, portable formats
8 | - Preserve multimedia content (images, videos, audio) from conversations
9 | - Facilitate easy migration of message history between devices and platforms
10 | - Run diagnostics on the iMessage database
11 | - Give you full ownership and control over your communication history
12 | - Support compliance with data retention policies or legal requirements
13 | - Run on macOS, Linux, and Windows
14 |
15 | ## Example Export
16 |
17 | 
18 |
19 | ## Binary
20 |
21 | The `imessage-exporter` binary exports iMessage data to `txt` or `html` formats. It can also run diagnostics to find problems with the iMessage database.
22 |
23 | Installation instructions for the binary are located [here](imessage-exporter/README.md).
24 |
25 | ## Library
26 |
27 | The `imessage_database` library provides models that allow us to access iMessage information as native, cross-platform data structures.
28 |
29 | Documentation for the library is located [here](imessage-database/README.md).
30 |
31 | ### Supported Features
32 |
33 | This crate supports every iMessage feature as of macOS 15.5 (24F74) and iOS 18.5 (22F75):
34 |
35 | - iMessage, RCS, SMS, and MMS
36 | - Multi-part messages
37 | - Replies/Threads
38 | - Formatted text
39 | - Attachments
40 | - Expressives
41 | - Tapbacks
42 | - Stickers
43 | - Apple Pay
44 | - Group chats
45 | - Digital Touch
46 | - URL Previews
47 | - Audio messages
48 | - App Integrations
49 | - Edited messages
50 | - Handwritten messages
51 |
52 | See more detail about supported features [here](docs/features.md).
53 |
54 | ## Frequently Asked Questions
55 |
56 | The FAQ document is located [here](/docs/faq.md).
57 |
58 | ## Special Thanks
59 |
60 | - All of my friends, for putting up with me sending them random messages to test things
61 | - [SQLiteFlow](https://www.sqliteflow.com), the SQL viewer I used to explore and reverse engineer the iMessage database
62 | - [Xplist](https://github.com/ic005k/Xplist), an invaluable tool for reverse engineering the `payload_data` plist format
63 | - [Compart](https://www.compart.com/en/unicode/), an amazing resource for looking up esoteric unicode details
64 | - [GNU Project](https://github.com/gnustep/libobjc) and [Archive.org](https://archive.org/details/darwin_0.1), for hosting source code referenced to reverse engineer the `typedstream` format
65 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | # Create output directory
2 | mkdir -p output
3 |
4 | # Get latest tags
5 | git pull
6 |
7 | # Get version number from tag name
8 | export VERSION=$(git describe --tags $(git rev-list --tags --max-count=1))
9 |
10 | if [ -n "$VERSION" ]; then
11 | # Confirm version number with user before build
12 | read -p "Build with version $VERSION? C-c to cancel, any key to continue " -n 1 -r
13 | echo
14 |
15 | # Update version number in Cargo.toml for build
16 | # macOS sed requires the weird empty string param
17 | # Otherwise it returns `invalid command code C`
18 | sed -i '' "s/version = \"0.0.0\"/version = \"$VERSION\"/g" imessage-database/Cargo.toml
19 |
20 | if [ -n "$PUBLISH" ]; then
21 | echo 'Publishing database library...'
22 | cargo publish -p imessage-database --allow-dirty
23 | else
24 | echo 'PUBLISH env var not set!'
25 | fi
26 |
27 | # Update version number in Cargo.toml for build
28 | sed -i '' "s/version = \"0.0.0\"/version = \"$VERSION\"/g" imessage-exporter/Cargo.toml
29 | sed -i '' s/'{ path = "..\/imessage-database" }'/\"$VERSION\"/g imessage-exporter/Cargo.toml
30 |
31 | if [ -n "$PUBLISH" ]; then
32 | echo 'Publishing exporter binary...'
33 | cargo publish -p imessage-exporter --allow-dirty
34 | else
35 | echo 'PUBLISH env var not set!'
36 | fi
37 |
38 | # Build for Apple Silicon
39 | cargo build --target aarch64-apple-darwin --release
40 | cp target/aarch64-apple-darwin/release/imessage-exporter output/imessage-exporter-aarch64-apple-darwin
41 | cd target/aarch64-apple-darwin/release
42 | tar -czf ../../../output/imessage-exporter-aarch64-apple-darwin.tar.gz imessage-exporter
43 | cd ../../..
44 |
45 | # Build for 64-bit Intel macOS
46 | cargo build --target x86_64-apple-darwin --release
47 | cp target/x86_64-apple-darwin/release/imessage-exporter output/imessage-exporter-x86_64-apple-darwin
48 | cd target/x86_64-apple-darwin/release/
49 | tar -czf ../../../output/imessage-exporter-x86_64-apple-darwin.tar.gz imessage-exporter
50 | cd ../../..
51 |
52 | # Build for 64-bit Intel Windows (requires `brew install mingw-w64`)
53 | cargo build --target x86_64-pc-windows-gnu --release
54 | cp target/x86_64-pc-windows-gnu/release/imessage-exporter.exe output/imessage-exporter-x86_64-pc-windows-gnu.exe
55 | cd target/x86_64-pc-windows-gnu/release/
56 | tar -czf ../../../output/imessage-exporter-x86_64-pc-windows-gnu.tar.gz imessage-exporter.exe
57 | cd ../../..
58 |
59 | # Put the version number back
60 | sed -i '' "s/version = \"$VERSION\"/version = \"0.0.0\"/g" imessage-database/Cargo.toml
61 | sed -i '' "s/version = \"$VERSION\"/version = \"0.0.0\"/g" imessage-exporter/Cargo.toml
62 | sed -i '' s/\"$VERSION\"/'{path = "..\/imessage-database"}'/g imessage-exporter/Cargo.toml
63 |
64 | unset VERSION
65 | else
66 | echo 'No version tag set!'
67 | fi
68 |
--------------------------------------------------------------------------------
/docs/binary/img/icloud_download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReagentX/imessage-exporter/b20e0086125f5c65cb6ef094da1757be26798c2b/docs/binary/img/icloud_download.png
--------------------------------------------------------------------------------
/docs/binary/img/safari_local_file_restrictions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReagentX/imessage-exporter/b20e0086125f5c65cb6ef094da1757be26798c2b/docs/binary/img/safari_local_file_restrictions.png
--------------------------------------------------------------------------------
/docs/diagnostics.md:
--------------------------------------------------------------------------------
1 | # Diagnostics
2 |
3 | Diagnostic output from `imessage-exporter` looks like:
4 |
5 | ```txt
6 | iMessage Database Diagnostics
7 |
8 | Handle diagnostic data:
9 | Contacts with more than one ID: 2
10 | Message diagnostic data:
11 | Total messages: 183453
12 | Messages not associated with a chat: 43210
13 | Messages belonging to more than one chat: 36
14 | Attachment diagnostic data:
15 | Total attachments: 49422
16 | Data referenced in table: 44.13 GB
17 | Data present on disk: 31.31 GB
18 | Missing files: 15037 (30%)
19 | No path provided: 14929
20 | No file located: 108
21 | Thread diagnostic data:
22 | Chats with no handles: 2
23 | Global diagnostic data:
24 | Total database size: 339.88 MB
25 | Duplicated contacts: 78
26 | Duplicated chats: 16
27 |
28 | Environment Diagnostics
29 |
30 | Detected converters:
31 | Image converter: sips
32 | Audio converter: afconvert
33 | Video converter: ffmpeg
34 | ```
35 |
36 | ## Handle diagnostic data
37 |
38 | ### Contacts with more than one ID
39 |
40 | 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 below.
41 |
42 | ## Message diagnostic data
43 |
44 | ### Total messages
45 |
46 | The total number of rows in the `messages` table.
47 |
48 | ### Messages not associated with a chat
49 |
50 | 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.
51 |
52 | ### Messages belonging to more than one chat
53 |
54 | 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.
55 |
56 | ## Attachment diagnostic data
57 |
58 | ### Total attachments
59 |
60 | The total number of rows in the `attachments` table
61 |
62 | #### Data referenced in table
63 |
64 | 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.
65 |
66 | #### Data present on disk
67 |
68 | 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.
69 |
70 | ### Missing files
71 |
72 | 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.
73 |
74 | There are two different types of missing files:
75 |
76 | #### No path provided
77 |
78 | This means there was a row in the `attachments` table that did not contain a path to a file.
79 |
80 | #### No file located
81 |
82 | This means there was a path provided, but there was no file at the specified location.
83 |
84 | ## Thread diagnostic data
85 |
86 | Emits the count of chats that contain no chat participants.
87 |
88 | ## Global diagnostic data
89 |
90 | ### Total database size
91 |
92 | The total size of the database file on the disk.
93 |
94 | ### Duplicated contacts
95 |
96 | Duplicated contacts occur when a single contact has multiple valid phone numbers or iMessage email addresses. The iMessage database stores handles as rows, and multiple rows can match to the same contact.
97 |
98 | ### Duplicated chats
99 |
100 | The number of separate chats that contain the same participants. See the [duplicates](/docs/tables/duplicates.md) for a detailed explanation of the logic used to determine this number.
101 |
102 | ## Detected converters
103 |
104 | `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.
105 |
106 | ### Image converter
107 |
108 | The currently detected image converter, if present.
109 |
110 | One of:
111 |
112 | - `sips` (macOS Builtin)
113 | - `magick` (`imagemagick`)
114 | - None
115 |
116 | ### Audio converter
117 |
118 | The currently detected audio converter, if present.
119 |
120 | One of:
121 |
122 | - `afconvert` (macOS Builtin)
123 | - `ffmpeg`
124 | - None
125 |
126 | ### Video converter
127 |
128 | The currently detected video converter, if present.
129 |
130 | One of:
131 |
132 | - `ffmpeg`
133 | - None
134 |
--------------------------------------------------------------------------------
/docs/faq.md:
--------------------------------------------------------------------------------
1 | # Frequently Asked Questions
2 |
3 | ## I cannot connect to the messages database. What do I do?
4 |
5 | Ensure your terminal emulator has [full disk access](https://kb.synology.com/en-us/C2/tutorial/How_to_enable_Full_Disk_Access_on_a_Mac) if using the default location or ensure that the path to the database file is correct.
6 |
7 | ***
8 |
9 | ## Are emojis, tapbacks (reactions), and other special message features preserved in the export?
10 |
11 | Yes, all iMessage features are supported. See [here](features.md) for more detail.
12 |
13 | ***
14 |
15 | ## Can it export messages from third-party apps that integrate with iMessage?
16 |
17 | Yes. See [here](features.md) for more detail on supported features.
18 |
19 | ***
20 |
21 | ## Does `imessage-exporter` export message conversations that are in iCloud or on a user's iPhone/iPad but not on the user's Mac?
22 |
23 | `imessage-exporter` only reads data present in the provided source, which can be either macOS's `chat.db` or a local full iOS backup. It cannot read data that is only stored in iCloud.
24 |
25 | ***
26 |
27 | ## Can I force iCloud to download attachments that were offloaded?
28 |
29 | 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.
30 |
31 | 
32 |
33 | ## Can it export group conversations as well as individual chats?
34 |
35 | Yes.
36 |
37 | ***
38 |
39 | ## How does the exporter handle previously exported messages?
40 |
41 | If files with the current output type exist in the output directory, `imessage-exporter` will alert the user that they will overwrite existing exported data and the export will be cancelled. 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.
42 |
43 | See [here](../imessage-exporter/README.md#how-to-use) for details on `imessage-exporter` arguments.
44 |
45 | ***
46 |
47 | ## Is it possible to export a conversation and re-integrate it back onto another Apple ID?
48 |
49 | No, I do not want to be trusted with write access to your iMessage data. This software is *read only*.
50 |
51 | ***
52 |
53 | ## Is there a search function?
54 |
55 | No, this software just builds exports. I use [`ripgrep`](https://github.com/BurntSushi/ripgrep) to search though the exported files.
56 |
57 | ***
58 |
59 | ## Will it run on Windows/Linux?
60 |
61 | I don't pre-build binaries for Windows or Linux, but it should compile to those [targets](https://doc.rust-lang.org/nightly/rustc/platform-support.html). As long as you can point it at an iMessage database, it should work.
62 |
63 | ***
64 |
65 | ## Can it export messages between a specific date range?
66 |
67 | Yes, the `--start-date` and `--end-date` arguments specify date ranges for exports.
68 |
69 | See [here](../imessage-exporter/README.md#how-to-use) for details on `imessage-exporter` arguments.
70 |
71 | ***
72 |
73 | ## Are voice messages be saved?
74 |
75 | Expired ones cannot because they are deleted. If you kept them then they are included in the exports.
76 |
77 | ***
78 |
79 | ## Are messages deleted from the messages app erased from the database?
80 |
81 | This software can recover some, but not all, deleted messages.
82 |
83 | 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](https://support.apple.com/en-us/HT202549#delete).
84 |
85 | Messages that have expired from this restoration process are permanently deleted and cannot be recovered.
86 |
87 | 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`.
88 |
89 | ***
90 |
91 | ## How fast is `imessage-exporter`?
92 |
93 | This is a complicated question that depends on CPU, database size, chosen export type, encryption state, and chosen attachment handling style.
94 |
95 | On my M1 Max MacBook Pro, approximate performance is as follows:
96 |
97 | | `--copy-method` | Messages exported per second |
98 | |---|---|
99 | | `disabled` | > 100,000 |
100 | | `clone` | ≈ 42,000 |
101 | | `basic` | ≈ 350 |
102 | | `full` | ≈ 250 |
103 |
104 | For more information on `--copy-method`, see [here](../imessage-exporter/README.md#how-to-use) and [here](./features.md#supported-message-features).
105 |
106 | 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`.
107 |
--------------------------------------------------------------------------------
/docs/features.md:
--------------------------------------------------------------------------------
1 | # Features
2 |
3 | The library and binary crates aim to provide the most comprehensive and accurate representation of iMessage data available.
4 |
5 | ## Targeted Versions
6 |
7 | This tool targets the current latest public release for Messages.app. It may work with older databases, but all features may not be available.
8 |
9 | ## Supported data sources
10 |
11 | - Local macOS messages
12 | - Encrypted or unencrypted local iOS backups
13 | - Unencrypted backups are resolved normally
14 | - Uses [crabapple](https://github.com/ReagentX/crabapple) to decrypt data from encrypted iOS backups
15 |
16 | ## Supported Message Features
17 |
18 | - Plain Text
19 | - Correctly extracts time-zone corrected timestamps
20 | - Detects when a message was read and calculates the time until read for both parties
21 | - Humanizes display of time-until-read duration
22 | - Parses `typedstream` message body data
23 | - Detects the service a message was sent from
24 | - In HTML exports, balloons are colored correctly for the service they were sent with
25 | - Supports iMessage, SMS, MMS, and RCS
26 | - Formatted Text
27 | - Parses formatted text ranges from `typedstream` message body data
28 | - Supports all iMessage text format ranges:
29 | - [Mentions](https://support.apple.com/guide/messages/mention-a-person-icht306ee34b/mac)
30 | - Hyperlinks
31 | - OTP/2FA
32 | - Unit Conversions
33 | - [Animations and Styles](https://support.apple.com/guide/iphone/style-and-animate-messages-iphe5c5af4d4/ios)
34 | - Edited and Unsent messages
35 | - Detects if messages components were edited or unsent
36 | - [Edited messages](https://support.apple.com/guide/iphone/unsend-and-edit-messages-iphe67195653/ios)
37 | - Parses `typedstream` edited body data
38 | - Displays content and timestamps for each edit
39 | - Humanizes display of edit timestamp gaps
40 | - Edited messages received before Ventura display as normal messages without history
41 | - Unsent messages
42 | - No content, but are noted in context
43 | - Multi-part messages
44 | - iMessages can have multiple parts, denoted by ranges in `typedstream` message body data
45 | - Parts are displayed as
46 | - New lines in TXT exports
47 | - Separate balloons in HTML exports
48 | - Handles Edited and Unsent parts
49 | - Threads and Message Replies
50 | - [Threads](https://support.apple.com/en-us/104974) are displayed both threaded under the parent as well as in-place
51 | - This is to preserve context, which can be lost if replying to older messages
52 | - Messages from a thread and were rendered in-place are annotated as such
53 | - In HTML exports, threaded messages are hyperlinked to allow for easy reading in context
54 | - For multi-part messages, replies are threaded under the correct message part
55 | - Attachments
56 | - Any type of attachment that can be displayed on the web is embedded in the HTML exports
57 | - Attachments can be copied to the export directory or referenced in-place
58 | - Less-compatible attachments can be converted for even more portable exports:
59 | - Image `HEIC` files convert to `JPEG`
60 | - Sticker `HEIC` files convert to `PNG`
61 | - Animated Sticker `HEICS` (HEIC sequence) files convert to `GIF`
62 | - Video `MOV` files convert to `mp4`
63 | - Audio `CAF` files convert to `mp4`
64 | - Attachments are displayed as
65 | - File paths in TXT exports
66 | - Embeds in HTML exports (including ``, `