Skip to content

joshuaswanson/messages-cli

Repository files navigation

messages-cli

Read, search, and send messages across iMessage, SMS/RCS, Telegram, WhatsApp, and Facebook Messenger from the terminal. macOS only.

Platforms

  • Messages -- iMessage and SMS/RCS (blue and green bubbles)
  • Telegram -- Full support including sending (piggybacks on your Telegram.app session)
  • WhatsApp -- Full support including sending (requires WhatsApp Desktop and one-time QR auth for sending)
  • Messenger -- Full support including sending (requires one-time browser login for cookie extraction)

All commands work across platforms by default. Use --platform/-p to filter by a specific platform (messages, telegram, whatsapp, or messenger). Platform tags [ms]/[tg]/[wa]/[fb] appear in merged output.

Install

Requires Python 3.11+ and uv.

uv run messages --help

WhatsApp sending setup

Reading WhatsApp messages works out of the box (reads the WhatsApp Desktop database directly). To enable sending, you need to authenticate once:

# Build the auth tool (requires Go)
cd wa-auth-tool && go build -o wa-auth && cd ..

# Build the send tool
cd wa-send-tool && go build -o wa-send && cd ..

# Authenticate by scanning a QR code with your phone
messages auth whatsapp

This creates a session at ~/.whatsapp-cli/whatsapp.db. You only need to do this once.

Messenger setup

# Build the pagination tools (requires Go)
cd fb-fetch-tool && go build -o fb-fetch && cd ..
cd fb-threads-tool && go build -o fb-threads && cd ..

# Log in via browser to extract cookies
messages auth messenger

Cookies are saved to ~/.config/messages-cli/messenger_cookies.json. The Go binaries are only needed for pagination: fb-fetch loads older messages within a thread, fb-threads discovers older threads beyond the initial ~15 from the inbox sync. Basic reading and sending work without them.

On first run, fb-threads automatically registers an E2EE device with Facebook's Signal Protocol infrastructure (ICDC) to access end-to-end encrypted threads. Device keys are persisted in ~/.config/messages-cli/messenger_e2ee.db.

Usage

List recent chats

$ messages chats recent --limit 4
Alice Johnson  2026-02-28 14:30:12  [tg]  @alicej  +41 79 123 45 67
John Smith     2026-02-28 14:30:12  [ms]  +1 206-555-1234
Family Group   2026-02-27 09:15:43  [wa]
Book Club      2026-02-26 20:00:01  [ms]

$ messages chats recent --platform whatsapp --limit 3
Family Group     2026-02-27 09:15:43
Alice Johnson    2026-02-26 20:00:01  +41 79 123 45 67
Work Chat        2026-02-25 18:00:00

Find chats

$ messages chats find "Alice"
Alice Johnson  [tg]  @alicej  +41 79 123 45 67
Alice Johnson  [wa]  +41 79 123 45 67

$ messages chats find "John"
John Smith  [ms]  +1 206-555-1234
Book Club   [ms]

Read messages

Accepts contact names, group chat names, phone numbers, or Telegram usernames. Auto-detects the platform unless --platform is specified.

$ messages read "Sarah" --limit 3
2026-02-27 08:10:00  Sarah Chen  Running 5 min late
2026-02-27 08:12:30  Me          No worries, I'll grab us a table
2026-02-27 09:15:43  Sarah Chen  Thanks for breakfast! [image: IMG_2041.heic]

$ messages read "Family Group" -p whatsapp --limit 3
2026-02-27 10:00:00  Dad   Anyone free for dinner Sunday?
2026-02-27 10:05:00  Me    I'm in
2026-02-27 10:10:00  Mom   Me too!

Search messages

$ messages search "dinner" --limit 3
2026-02-27 18:30:00  John Smith    Me          Dinner at 7?           [ms]
2026-02-26 12:15:00  Family Group  Dad         Dinner plans?          [wa]
2026-02-25 09:00:00  Sarah Chen    Sarah Chen  Thanks for dinner!     [ms]

$ messages search "dinner" --chat "Family Group" -p whatsapp
2026-02-26 12:15:00  Family Group  Dad  Dinner plans?

$ messages search "dinner" --context 2
--- Family Group [wa] ---
2026-02-26 12:10:00  Mom   What should we do this weekend?
2026-02-26 12:12:00  Me    Not sure yet
2026-02-26 12:15:00  Dad   Dinner plans?  <--
2026-02-26 12:20:00  Mom   Great idea!
2026-02-26 12:25:00  Me    I'm in

Send a message

Dry-run by default. Pass --confirm to actually send.

$ messages send "Sarah" "Hey, are we still on for tomorrow?"
Would send [ms] to +1 415-555-9876: Hey, are we still on for tomorrow?
Pass --confirm to actually send.

$ messages send "Alice" "See you at 3" -p whatsapp --confirm
Message sent.

Search contacts

$ messages contacts search "John"
John Smith
  phone: +1 206 555 1234
  phone: +41 78 555 6789
  email: john.smith@example.com

Authenticate

$ messages auth whatsapp
Scan the QR code below with WhatsApp on your phone:
Open WhatsApp > Settings > Linked Devices > Link a Device
# QR code appears here

$ messages auth messenger
# Opens a browser window to log into messenger.com
# Cookies are saved to ~/.config/messages-cli/messenger_cookies.json

Statistics

$ messages stats
messages    Messages: 48,291  Chats: 142
telegram    Messages: 28,529  Chats: 207
whatsapp    Messages: 12,847  Chats: 89
messenger   Messages: 1,204   Chats: 31

Requirements

  • Full Disk Access -- Grant your terminal app Full Disk Access in System Settings > Privacy & Security. Required for reading the iMessage, Telegram, and WhatsApp databases.
  • sqlcipher -- brew install sqlcipher. Required for Telegram support.
  • Go -- Required to build the WhatsApp send/auth tools and the Messenger pagination tool. brew install go.
  • WhatsApp Desktop -- The native macOS app (not the web version). Required for WhatsApp reading.
  • Messenger cookies -- Run messages auth messenger to log in via browser. Required for Messenger support.

How it works

Messages -- Queries the Messages SQLite database (~/Library/Messages/chat.db) directly for reading. Sends via AppleScript. Resolves phone numbers to contact names, shows reactions and attachments, formats phone numbers by country code. Image attachments are returned as local file paths from ~/Library/Messages/Attachments/.

Telegram -- Decrypts the local Telegram database (SQLCipher-encrypted postbox) for reading. For sending, it extracts the persistent MTProto auth key from the local database and uses Telethon to make API calls, no separate login needed. Image attachments are resolved from the local media cache by parsing photo resource IDs from the binary message format.

WhatsApp -- Reads the WhatsApp Desktop SQLite databases (~/Library/Group Containers/group.net.whatsapp.WhatsApp.shared/) directly. Resolves contact names from the contacts database and group member tables. For sending, uses a Go binary (whatsmeow) with a one-time QR code pairing flow. Image attachments are returned as local file paths from the WhatsApp media cache.

Messenger -- Authenticates with browser cookies extracted via a one-time login flow. Reads messages by fetching thread pages from messenger.com and parsing the embedded Lightspeed payloads. Two Go binaries (using mautrix-meta) connect via Facebook's MQTT WebSocket protocol for pagination: fb-fetch pages through older messages within a thread, and fb-threads pages through the thread list itself (the initial Lightspeed sync only returns ~15 recent threads). fb-threads also registers an E2EE device via Facebook's ICDC protocol (Signal Protocol key exchange) to access end-to-end encrypted threads, which Facebook migrated most conversations to in 2023. E2EE 1-on-1 DMs are discovered by intercepting Lightspeed createOpenToE2EEThreadLink entries, and contact names are resolved via GetContactsFullTask over MQTT. Device keys are persisted locally in a SQLite database. Sends messages via Facebook's Lightspeed GraphQL API. Image attachments are downloaded from Facebook's CDN to ~/.cache/messages-cli/messenger/.

Data format

Message dicts from read_messages() include:

  • timestamp -- ISO 8601 with local timezone (e.g., 2026-03-10T11:09:49+01:00)
  • sender -- display name or "Me"
  • text -- message content with attachment tags
  • is_from_me -- boolean
  • image_paths -- list of local file paths to image attachments

Chat/thread dicts from recent_chats() include message_count (per-thread message count) on iMessage, WhatsApp, and Telegram. Messenger's all_threads() returns {"threads": [...], "has_more": bool} indicating whether pagination was exhaustive.

Support

If you find this useful, buy me a coffee.

Buy Me a Coffee QR

About

Unified CLI for reading, searching, and sending messages across all your messaging apps

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors