A Matrix-iMessage puppeting bridge. Send and receive iMessages from any Matrix client.
This is the v2 rewrite using rustpush and bridgev2 — it connects directly to Apple's iMessage servers without SIP bypass, Barcelona, or relay servers.
Features: text, images, video, audio, files, reactions/tapbacks, edits, unsends, typing indicators, read receipts, group chats, SMS forwarding, and contact name resolution.
Platforms: macOS (full features) and Linux (via hardware key extracted from a Mac once).
macOS 13+ required (Ventura or later). Sign into iCloud on the Mac running the bridge (Settings → Apple ID) — this lets Apple recognize the device so login works without 2FA prompts.
git clone https://github.com/lrhodin/imessage.git
cd imessage
make install-beeperThe installer handles everything: Homebrew, dependencies, building, Beeper login, config, and LaunchAgent setup. Once running, DM @sh-rustpushbot:beeper.local in Beeper and send login.
Already have an iMessage bridge (e.g. BlueBubbles)? Use a custom bridge name to run both side by side:
BRIDGE_NAME=sh-rustpush-v2 make install-beeperThis registers a separate bridge so it doesn't collide with the existing one. DM @sh-rustpush-v2bot:beeper.local instead.
git clone https://github.com/lrhodin/imessage.git
cd imessage
make installThe installer auto-installs Homebrew and dependencies if needed, asks three questions (homeserver URL, domain, your Matrix ID), generates config files, and starts the bridge as a LaunchAgent. It will pause and tell you exactly what to add to your homeserver.yaml to register the bridge.
Once running, DM @imessagebot:yourdomain in your Matrix client and send login.
The bridge runs on Linux using a hardware key extracted once from a real Mac. No Mac needed at runtime for Intel keys; Apple Silicon Macs require the NAC relay (a small background process on the Mac).
Ubuntu 22.04+ (or equivalent). Only git, make, and sudo are needed — the build installs everything else:
sudo apt install -y git makegit clone https://github.com/lrhodin/imessage.git
cd imessage
go run tools/extract-key/main.goThis reads hardware identifiers (serial, MLB, ROM, etc.) and outputs a base64 key. The Mac is not modified.
Apple Silicon Macs lack the encrypted IOKit properties needed by the x86_64 NAC emulator. You must also run the NAC relay:
# Terminal 1: start the relay (keeps running)
go run tools/nac-relay/main.go
# Terminal 2: extract key with relay URL
go run tools/extract-key/main.go -relay http://<your-mac-ip>:5001/validation-dataThe relay URL is embedded in the key. If the bridge runs outside your LAN, forward port 5001 TCP to your Mac.
Intel Macs: No NAC relay needed. The bridge runs the x86_64 NAC emulator locally on Linux.
git clone https://github.com/lrhodin/imessage.git
cd imessage
make install-beepergit clone https://github.com/lrhodin/imessage.git
cd imessage
make installOn first run expect ~3 minutes for the Rust library to compile.
DM the bridge bot and choose the "Apple ID (External Key)" login flow:
- Paste your hardware key (base64)
- Enter your Apple ID and password
- Enter the 2FA code sent to your trusted devices
The bridge registers with Apple's servers and starts receiving iMessages.
Follow the prompts: Apple ID → password → 2FA (if needed) → handle selection. If the Mac is signed into iCloud with the same Apple ID, login completes without 2FA.
If your Apple ID has multiple identities registered (e.g. a phone number and an email address), you'll be asked which one to use for outgoing messages. This is what recipients see your messages "from". To change it later, set preferred_handle in the config (see Configuration) or log in again.
Tip: In a DM with the bot, commands don't need a prefix. In a regular room, use
!im login,!im help, etc.
To bridge SMS (green bubble) messages, enable forwarding on your iPhone:
Settings → Messages → Text Message Forwarding → toggle on the bridge device.
Incoming iMessages automatically create Matrix rooms. If Full Disk Access is granted (macOS), existing conversations from Messages.app are also synced.
To start a new conversation:
resolve +15551234567
This creates a portal room. Messages you send there are delivered as iMessages.
The bridge connects directly to Apple's iMessage servers using rustpush with local NAC validation (no SIP bypass, no relay server). On macOS with Full Disk Access, it also reads chat.db for message history backfill and contact name resolution.
On Linux, NAC validation uses one of two paths:
- Intel key: open-absinthe emulates Apple's
IMDAppleServicesx86_64 binary via unicorn-engine, hooking IOKit/CoreFoundation calls and feeding them hardware data from the extracted key - Apple Silicon key + relay: The bridge fetches validation data from a NAC relay running on the Mac, which calls Apple's native
AAAbsintheContextframework
flowchart TB
subgraph macos["🖥 macOS"]
HS1[Homeserver] -- appservice --> Bridge1[mautrix-imessage]
Bridge1 -- FFI --> RP1[rustpush]
RP1 -- IOKit/AAAbsinthe --> NAC1[Local NAC]
end
subgraph linux["🐧 Linux"]
HS2[Homeserver] -- appservice --> Bridge2[mautrix-imessage]
Bridge2 -- FFI --> RP2[rustpush]
RP2 -- unicorn-engine --> NAC2[open-absinthe]
RP2 -. "Apple Silicon key" .-> Relay[NAC Relay on Mac]
end
Client1[Matrix client] <--> HS1
Client2[Matrix client] <--> HS2
RP1 <--> Apple[Apple IDS / APNs]
RP2 <--> Apple
style macos fill:#f0f4ff,stroke:#4a6fa5,stroke-width:2px,color:#1a1a2e
style linux fill:#f0fff4,stroke:#4aa56f,stroke-width:2px,color:#1a1a2e
style Apple fill:#1a1a2e,stroke:#1a1a2e,color:#fff
style Client1 fill:#fff,stroke:#999,color:#333
style Client2 fill:#fff,stroke:#999,color:#333
style Relay fill:#ffe0b2,stroke:#e65100,color:#333
Real-time messages flow through Apple's push notification service (APNs) via rustpush and appear in Matrix immediately.
Backfill runs once on first login: the bridge reads chat.db and creates portals for all chats with activity in the last initial_sync_days (default: 1 year, configurable). On macOS this reads the local database directly; on Linux with the NAC relay, it proxies queries over HTTP to the Mac. After initial sync, everything is real-time via rustpush.
# View logs
tail -f data/bridge.stdout.log
# Restart (auto-restarts via KeepAlive)
launchctl kickstart -k gui/$(id -u)/com.lrhodin.mautrix-imessage
# Stop until next login
launchctl bootout gui/$(id -u)/com.lrhodin.mautrix-imessage
# Uninstall
make uninstall# If using systemd (from make install / make install-beeper)
systemctl --user status mautrix-imessage
journalctl --user -u mautrix-imessage -f
systemctl --user restart mautrix-imessage
# If running directly
./mautrix-imessage-v2 -c data/config.yaml# View logs
tail -f /tmp/nac-relay.log
# Restart
launchctl kickstart -k gui/$(id -u)/com.imessage.nac-relay
# Stop
launchctl bootout gui/$(id -u)/com.imessage.nac-relayConfig lives in data/config.yaml (generated during install). To reconfigure from scratch:
rm -rf data
make install # or make install-beeperKey options:
| Field | Default | What it does |
|---|---|---|
network.initial_sync_days |
365 |
How far back to backfill on first login |
network.displayname_template |
First/Last name | How bridged contacts appear in Matrix |
network.preferred_handle |
(from login) | Outgoing identity (tel:+15551234567 or mailto:user@example.com) |
backfill.max_initial_messages |
10000 |
Max messages to backfill per chat |
encryption.allow |
true |
Enable end-to-bridge encryption |
database.type |
sqlite3-fk-wal |
sqlite3-fk-wal or postgres |
make build # Build .app bundle (macOS) or binary (Linux)
make rust # Build Rust library only
make bindings # Regenerate Go FFI bindings (needs uniffi-bindgen-go)
make clean # Remove build artifactscmd/mautrix-imessage/ # Entrypoint
pkg/connector/ # bridgev2 connector
├── connector.go # bridge lifecycle + platform detection
├── client.go # send/receive/reactions/edits/typing
├── login.go # Apple ID + external key login flows
├── chatdb.go # chat.db backfill + contacts (macOS)
├── ids.go # identifier/portal ID conversion
├── capabilities.go # supported features
└── config.go # bridge config schema
pkg/rustpushgo/ # Rust FFI wrapper (uniffi)
rustpush/ # OpenBubbles/rustpush (vendored)
└── open-absinthe/ # NAC emulator (unicorn-engine, cross-platform)
nac-validation/ # Local NAC via AppleAccount.framework (macOS)
tools/
├── extract-key/ # Hardware key extraction (run on Mac)
└── nac-relay/ # NAC validation + contacts + backfill relay (run on Mac)
imessage/ # macOS chat.db + Contacts reader
AGPL-3.0 — see LICENSE.