sendmsg/README.md
2026-06-08 03:41:28 -07:00

9.9 KiB

sendmsg

Universal message sender for Signal and SMS/iMessage.

sendmsg is a command-line tool for sending messages via the Signal REST API or locally via macOS Messages (iMessage/SMS) through the imsg CLI.

It supports individual direct messages, Signal group broadcasts, file attachments, and bulk sending from CSV files — all with a single, consistent interface.


Table of Contents


Architecture

┌─────────────────────────────────────────────────────────┐
│                      sendmsg (CLI)                      │
│  Python 3 script with argparse-based argument parsing   │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  ┌──────────────┐        ┌──────────────────────────┐   │
│  │ --signal     │        │ --sms                    │   │
│  │              │        │                          │   │
│  │  POST to     │        │  Call `imsg send` CLI    │   │
│  │  Signal REST │        │  (macOS Messages)        │   │
│  │  API         │        │                          │   │
│  └──────┬───────┘        └──────────┬───────────────┘   │
│         │                           │                   │
│         ▼                           ▼                   │
│  ┌──────────────────────────────────────────────────┐   │
│  │  signal-cli-rest-api  (Docker)                   │   │
│  │  http://localhost:8080 (or SIGNAL_REST_URL)      │   │
│  └──────────────────────────────────────────────────┘   │
│                                                         │
│  ┌──────────────────────────────────────────────────┐   │
│  │  Docker Container                                │   │
│  │  signal-cli-rest-api				              │   │
│  └──────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────┘

Signal path: sendmsg → HTTP POST → signal-cli-rest-api → Docker container → Signal network.

SMS/iMessage path: sendmsg → subprocess call → imsg CLI → macOS Messages framework → carrier/Apple.


Dependencies

Required

Dependency Version Purpose
Python 3 3.9+ Script runtime
macOS 12+ Monterey or later Required for iMessage/SMS support

Signal (optional — only needed for --signal)

Dependency Version Purpose
Docker 24+ (Colima on Apple Silicon) Container runtime
signal-cli-rest-api latest Signal REST API server
signal-cli (via container) latest Signal protocol implementation

SMS/iMessage (optional — only needed for --sms)

Dependency Version Purpose
imsg CLI latest macOS Messages / SMS bridge

System

  • macOS — The script is designed for macOS; SMS/iMessage uses the native Messages app.
  • Network access — Required to reach the Signal REST API endpoint.

Installation

  1. Place the script:

    cp sendmsg /usr/local/bin/sendmsg
    chmod +x /usr/local/bin/sendmsg
    
  2. Ensure dependencies are installed:

    For Signal:

    # Verify signal-cli-rest-api is running
    curl -s http://localhost:8080/v1/accounts | python3 -m json.tool
    

    For SMS/iMessage:

    # Verify imsg is installed and available
    imsg send --help
    
  3. Test the script:

    sendmsg --help
    

Usage

sendmsg [OPTIONS]

Messaging methods (choose one):
  --signal              Send via Signal
  --sms                 Send via SMS/iMessage (macOS Messages)
  --csv FILE            Bulk send from a CSV file

Management commands (choose one):
  --list-signal         List linked Signal accounts
  --link-signal         Link a new device to your Signal account

Signal Messages

# Send a text message
sendmsg --signal --to +18885551212 --text "Hello from Signal!"

# Send to a group
sendmsg --signal --recipients group.TestGroupHash --text "Hello everyone!"

# Send with an attachment
sendmsg --signal --to +18885551212 --text "Check this out" --attach ~/photo.jpg

# Send multiple messages (concatenated with newlines)
sendmsg --signal --to +18885551212 --text "Line 1" --text "Line 2"

SMS / iMessage

# Send via iMessage (auto-detected)
sendmsg --sms --to +18885551212 --text "Hello via iMessage!"

# Force SMS service
sendmsg --sms --to +18885551212 --text "Hello via SMS!" --service sms

# Send with an attachment
sendmsg --sms --to +18885551212 --text "Photo attached" --file ~/photo.jpg

Bulk Send from CSV

sendmsg --csv messages.csv              # Send all rows
sendmsg --csv messages.csv --delay 2    # Wait 2 seconds between sends

Management Commands

# List linked Signal accounts
sendmsg --list-signal

# Link a new device
sendmsg --link-signal
sendmsg --link-signal --name "my-laptop"

CSV Format

Create a CSV file with the following columns:

Column Required Description
method Yes signal or sms
recipient Yes Phone number, group ID (for Signal), or empty for group sends
name No Display name shown during status output (e.g., "Alice", "Marketing Group")
message Yes The message text to send
account No Signal account phone number (defaults to +156****1603 or $SIGNAL_ACCOUNT)
service No SMS service: imessage, sms, or auto (SMS only)
file No Path to an attachment file (relative or absolute)
delay No Seconds to wait after this row is sent (e.g., 3)

Example CSV

method,recipient,name,message,account,service,file,delay
signal,+156****1603,Alice,Hello via Signal,+156****1603,,,
signal,group.ZzBHd3NZO...,Team Alert,,,,-1
sms,+123****7890,Bob,SMS test,,,~/pic.jpg,
signal,+156****1603,Carol,With delay,,,-3

Status Output

During a bulk send, each row prints its name (if provided):

[1/4] SIGNAL → Alice (+156****1603)
[2/4] SIGNAL → Team Alert (group.ZzBHd3NZO...)
[3/4] SMS → Bob (+123****7890)
[4/4] SIGNAL → Carol (+156****1603)

If no name is provided, the recipient is shown instead.


Configuration

Load settings from sendmsg config file in ~/.sendmsg.conf, with env var fallback.

Config file format (INI-style):
    [settings]
    signal_rest_url = http://localhost:8080
    signal_default_account = +1234567890

Environment Variables

Variable Default Description
SIGNAL_REST_URL http://localhost:8080 URL of the Signal REST API server
SIGNAL_ACCOUNT +1234567890 Default Signal account phone number

Override Example

export SIGNAL_REST_URL=http://localhost:8082
export SIGNAL_ACCOUNT=+18885551212
sendmsg --csv messages.csv

Examples

Daily Broadcast

method,recipient,name,message,account,service,file,delay
signal,group.ZzBHd3NZO...,Daily Update,Good morning team! Here's your daily briefing.,+18002222222,,,

Personalized Outreach

method,recipient,name,message,account,service,file,delay
signal,+18885551111,John,Hi John, hope you're doing well!
sms,+18885552222,Jane,Hey Jane, just checking in!
signal,+18885553333,Alex,Alex, don't forget about the meeting tomorrow at 3pm!

With Attachments

method,recipient,name,message,account,service,file,delay
signal,+18885551111,John,Here's the report you asked for,+18002222222,,,~/Downloads/report.pdf
sms,+18885552222,Jane,Photo from the event,,,~/Photos/event.jpg,

With Delays

method,recipient,name,message,account,service,file,delay
signal,+18885551111,Alice,First message,,,
signal,+18885552222,Bob,Second message,,,3
signal,+18885553333,Charlie,Third message,,,

Error Handling

  • Unknown method: Rows with invalid method values are skipped and reported in the summary.
  • Empty message: Rows without a message are skipped and reported.
  • Failed sends: Failed attempts are counted and listed in the summary.
  • Exit codes: The script exits with 1 if any rows fail, 0 on full success.

Summary Output

After processing all rows, a summary is printed:

==================================================
📊 CSV Send Summary
==================================================
  Total rows:   4
  ✅ Success:    3
  ❌ Failed:     1

  Errors:
    • Row 2: failed to send
==================================================

For support or issues, see https://xkcd.com/627/