imsg connects to a paired iPhone using the standard Bluetooth MAP (Message Access Profile)
and PBAP (Phone Book Access Profile) protocols. No iCloud credentials, no Apple Silicon, no macOS bridge.
- Linux with BlueZ (
bluetoothdrunning)
π That's it!
curl -sSfL https://releases.gnu.foo/imsg/latest/install.sh | shOr via cargo:
cargo install imsgNote
Before you begin: your iPhone must be paired to this machine via bluetoothctl, and
imsg needs the RFCOMM channel numbers iOS has assigned to its MAP and PBAP services β
these are dynamic and change across iOS versions and re-pairings so they can't be hardcoded.
Run setup to discover them automatically from any paired device:
curl -sSfL "https://releases.gnu.foo/imsg/latest/setup-$(uname -m)" -o setup && chmod +x setup && ./setupFeed the printed channel numbers into step 1 below.
imsg config set-device A1:B2:C3:D4:E5:F6If your channel numbers differ from the defaults (map=2, pbap=13), set them in
~/.config/imsg/imsg.toml:
[device]
address = "A1:B2:C3:D4:E5:F6"
map_channel = 2
pbap_channel = 13imsg list # inbox
imsg list --unread # unread only
imsg list sent # sent folder
imsg list --from +15550001234 --limit 20 # filter by sender
imsg list --since 20260601T000000 --long # since a date, show MAP handles
imsg get <handle> # full message body
imsg get <handle> --mark-read # fetch and mark as read
imsg send +15550001234 "hey" # send a message
imsg threads # conversations grouped by contact| Command | What it does |
|---|---|
send <number> <message> |
Send a message |
list [folder] |
List messages β inbox (default), sent, outbox, deleted; filter with --unread, --from, --since, --limit, --offset; add --long for MAP handles |
get <handle> |
Fetch full message body; --mark-read to mark it read |
delete <handle> |
Delete a message; --undelete to restore |
contacts |
Pull contacts via PBAP; --list handles, --get <handle>, --lookup <number>, --limit/--page for pagination, --raw to skip E.164 normalisation |
threads |
Group inbox and sent into per-contact conversations |
watch |
Stream live MAP notification events |
folders |
List the MAP folder tree on the device |
config show |
Print the resolved configuration |
config set-device <MAC> |
Persist the paired device address |
Run imsg <command> --help for the full flag reference.
If your iPhone is paired to a different machine β a Raspberry Pi, a server, a desktop in
another room β you can run imsg from any machine on the internet without re-pairing.
On the machine with the paired phone:
imsg hub
# prints: node key: <KEY>On your laptop (or anywhere else):
imsg spoke add <KEY>
imsg --hub list
imsg --hub send +15550001234 "hello from anywhere"
imsg --hub watchThe hub and spoke connect over QUIC via iroh β no port forwarding or VPN required.
imsg watch streams MAP notification events directly from the paired phone over RFCOMM.
Add --hub to receive events forwarded from a remote hub instead.
For a scrollable TUI panel (local watch only), build with the tui feature:
cargo install imsg --features tui
imsg watch # launches the ratatui panel automaticallyUse β/β to scroll the event log, q / Esc / Ctrl+C to exit.
Config is layered in ascending priority:
compiled-in defaults
/etc/imsg.toml
~/.config/imsg/imsg.toml
./imsg.toml
--config <path>
IMSG_ environment variables (e.g. IMSG_DEVICE__MAP_CHANNEL=15)
Full key reference:
[device]
address = "A1:B2:C3:D4:E5:F6" # required; set via `imsg config set-device`
map_channel = 2 # RFCOMM channel for MAP MAS [1β30], default 2
pbap_channel = 13 # RFCOMM channel for PBAP PSE [1β30], default 13
[hub]
node_key = "..." # set via `imsg spoke add <KEY>`; absent until thengit clone https://github.com/gnufood/imsg
cd imsg
cargo build --release # standard build
cargo build --release --features tui # include ratatui watch panelSee CONTRIBUTING.md for the full development workflow.
MIT β see LICENSE.