A command-line interface for the SMS Gateway for Android API. Ships two binaries: smsgate (messages, webhooks, logs) and smsgate-ca (certificates for private deployments). Part of the SMSGate ecosystem - see the CLI docs for the full reference.
The CLI lets you automate SMS Gateway for Android without writing code: send messages (including batch operations from CSV and Excel files), manage webhooks, retrieve logs, and - via smsgate-ca - issue certificates for private server deployments. It can be used interactively or embedded in CI/CD pipelines, shell scripts, and cron jobs.
- ⌨️ SMSGate CLI
- Send SMS to one or multiple recipients with delivery options: device and SIM selection, priority, TTL, scheduled delivery, delivery reports
- Send MMS with subject and multiple attachments, and data messages with base64 payloads and custom destination ports
- Batch sending from CSV and XLSX files with column mapping, dry-run and validate-only modes
- Webhook management (register, list, delete) for event notifications
- Log retrieval for arbitrary time ranges
- Multiple output formats:
text,json,raw,table - Certificate issuing for private server deployments via
smsgate-ca
- Go to the Releases page of this repository.
- Download the appropriate binary archive for your operating system and architecture. Each archive contains both
smsgateandsmsgate-ca. - Extract the archive to a directory of your choice.
- Move the binaries to a directory in your system's PATH.
curl -LO https://github.com/android-sms-gateway/cli/releases/latest/download/smsgate_Linux_x86_64.tar.gz
tar -xzf smsgate_Linux_x86_64.tar.gz
chmod +x smsgate smsgate-ca
sudo mv smsgate smsgate-ca /usr/local/bin/Requires Go 1.26+ (for building from source). Make sure $(go env GOPATH)/bin is in your PATH.
go install github.com/android-sms-gateway/cli/cmd/smsgate@latest
go install github.com/android-sms-gateway/cli/cmd/smsgate-ca@latestDocker (optional, for containerized execution).
docker run -it --rm --env-file .env ghcr.io/android-sms-gateway/smsgate \
send --phones '+12025550123' 'Hello, Dr. Turk!'smsgate [global options] command [command options] [arguments...]| Group | Commands | Description |
|---|---|---|
| Messages | send, status (alias: state), batch send |
Send and track messages, bulk from CSV/XLSX |
| Webhooks | webhooks register, webhooks list, webhooks delete |
Register, audit, and remove webhook endpoints |
| Logs | logs (alias: log) |
Retrieve logs for a specific time range |
For a complete list of available commands, you can:
- Run
smsgate helporsmsgate --helpin your terminal. - Visit the official documentation at docs.sms-gate.app.
Credentials are read from environment variables (see Configuration); never put them on the command line.
The send command supports various options to customize message delivery:
# Send a message
smsgate send --phones '+12025550123' 'Hello, Dr. Turk!'
# Send to multiple numbers
smsgate send --phones '+12025550123' --phones '+12025550124' 'Hello, doctors!'
# or
smsgate send --phones '+12025550123,+12025550124' 'Hello, doctors!'
# Send with explicit device selection
smsgate send --phones '+12025550123' --device-id device123 'Message'
# Send with SIM number selection (1-based)
smsgate send --phones '+12025550123' --sim-number 2 'Message'
# Send with priority (>=100 bypasses limits)
smsgate send --phones '+12025550123' --priority 100 'Urgent message'
# Send with time-to-live (TTL)
smsgate send --phones '+12025550123' --ttl 1h30m 'Expiring message'
# Send with expiration date (RFC3339 format)
smsgate send --phones '+12025550123' --valid-until '2026-12-31T23:59:59Z' 'Message'
# Disable delivery report
smsgate send --phones '+12025550123' --delivery-report=false 'Message'
# Skip phone number validation
smsgate send --phones '+12025550123' --skip-phone-validation 'Message'
# Filter by device activity (devices active within last 12 hours)
smsgate send --phones '+12025550123' --device-active-within 12 'Message'
# Schedule delivery (RFC3339 format)
smsgate send --phones '+12025550123' --schedule-at '2026-12-31T23:59:59Z' 'Message'
# Send data message (base64 encoded)
echo -n 'hello world' | base64
smsgate send --phones '+12025550123' --data --data-port 12345 'aGVsbG8gd29ybGQ='
# Send MMS with subject and multiple attachments
smsgate send --mms --subject 'Project update' --phones '+12025550123' \
--attachment /path/to/report.pdf \
--attachment /path/to/chart.png \
'Here are the latest documents'
# Send MMS with attachments only (no text)
smsgate send --mms --phones '+12025550123' \
--attachment /path/to/photo.jpg
# Send MMS to multiple recipients
smsgate send --mms --phones '+12025550123' --phones '+12025550124' \
--subject 'Team update' --attachment /path/to/screenshot.png \
'Please review'Notes:
--dataand--mmsare mutually exclusive.- At least one of text or an attachment is required for MMS.
- MIME type is detected from the file extension (falls back to
application/octet-stream).
Send command options:
| Option | Description | Default Value | Example |
|---|---|---|---|
--id |
A unique message ID. If not provided, one will be automatically generated. | empty | zXDYfTmTVf3iMd16zzdBj |
--device-id, --device |
Optional device ID for explicit selection. If not provided, a random device will be selected. | empty | oi2i20J8xVP1ct5neqGZt |
--phones, --phone, -p |
Specifies the recipient's phone number(s). This option can be used multiple times or accepts comma-separated values. Numbers must be in E.164 format. | required | +12025550123 |
--sim-number, --sim |
The one-based SIM card slot number. If not specified, the device's SIM rotation feature will be used. | empty | 2 |
--delivery-report |
Enables delivery report for the message. | true |
true / false |
--priority |
Sets the priority of the message. Messages with priority >= 100 bypass all limits and delays. Range: -128 to 127. | 0 |
100 |
| Data Message | |||
--data |
Send data message instead of text (content must be base64 encoded). | false |
true |
--data-port |
Destination port for data message (1 to 65535). | 53739 |
12345 |
| MMS Message | |||
--mms |
Send MMS message instead of text; text is optional when at least one attachment is provided. | false |
true |
--subject |
MMS subject line. Requires --mms. |
empty | Photo update |
--attachment |
Path to an attachment file. Repeatable; MIME type is detected from the file extension. Requires --mms. |
empty | /path/to/image.jpg |
| Options | |||
--ttl |
Time-to-live (TTL) for the message. Duration format (e.g., 1h30m). If not provided, the message will not expire.Conflicts with --valid-until. |
empty | 1h30m |
--valid-until |
The expiration date and time for the message. RFC3339 format (e.g., 2006-01-02T15:04:05Z07:00).Conflicts with --ttl. |
empty | 2026-12-31T23:59:59Z |
--skip-phone-validation |
Skip phone number validation. | false |
true |
--device-active-within |
Time window in hours for device activity filtering. 0 means no filtering. |
0 |
12 |
--schedule-at |
Schedule delivery time (RFC3339 format). If not provided, the message is sent immediately. Example: 2026-12-31T23:59:59Z. |
immediate | 2026-12-31T23:59:59Z |
The CLI supports sending messages in bulk from CSV and Excel files. The batch send command also supports the shared delivery/device options from send (such as --device-id, --sim-number, --priority, --ttl, --valid-until, --delivery-report, --skip-phone-validation, --device-active-within), allowing fine-grained control over each message in the batch.
Supported file formats:
- CSV (Comma-Separated Values)
- XLSX (Excel files)
Basic usage:
# Batch send from a CSV file with column mapping
smsgate batch send --map phone=Phone,text=Message contacts.csv
# Send messages from an Excel file with specific sheet
smsgate batch send campaign.xlsx --sheet Sheet1 --map phone=Phone,text=Message
# Send with custom delimiter and no header
smsgate batch send data.csv --delimiter ';' --header=false --map phone=col_1,text=col_2Batch-specific options:
| Option | Description | Default Value | Example |
|---|---|---|---|
--sheet |
Sheet name (defaults to first sheet) | empty | Sheet1 |
--delimiter |
CSV delimiter character | , |
; |
--header |
Treat first row as header | true |
false |
--map |
Column mapping (required) | required | phone=Phone,text=Message |
--dry-run |
Validate and print normalized rows without sending | false |
true |
--validate-only |
Validate input only (no preview, no sending) | false |
true |
--concurrency |
Number of concurrent send workers | CPU cores | 5 |
--continue-on-error |
Continue sending after per-row failures | false |
true |
Inherited message options:
The shared delivery/device options from the send command are also available (e.g., --device-id, --sim-number, --priority, --ttl, --valid-until, --delivery-report, --skip-phone-validation, --device-active-within). These apply to every message sent in the batch.
Column mapping:
The --map option defines how columns in your file map to message fields:
| Field | Required | Description |
|---|---|---|
phone |
✅ | Phone number column |
text |
✅ | Message text column |
id |
❌ | Message ID column (UUID generated when empty) |
device_id |
❌ | Device identifier column |
sim_number |
❌ | SIM number column (1-255) |
priority |
❌ | Message priority column (-128 to 127) |
Mapping examples:
# Basic mapping with headers
smsgate batch send --map phone=Phone,text=Message contacts.csv
# Excel file with specific sheet
smsgate batch send --sheet Sheet1 --map phone=Phone,text=Message campaign.xlsx
# No headers, column positions
smsgate batch send --header=false --map phone=col_1,text=col_2 data.csv
# Full mapping with optional fields
smsgate batch send --map phone=Phone,text=Message,device_id=Device,sim_number=SIM,priority=Priority contacts.csvWorkflow modes:
-
Validation Only - Validates file format and column mapping, checks required fields, exits without sending:
smsgate batch send --map phone=Phone,text=Message --validate-only contacts.csv
-
Dry Run - Validates and processes all rows, shows what would be sent without actually sending:
smsgate batch send --map phone=Phone,text=Message --dry-run contacts.csv
-
Full Send - Sends all messages with real-time progress:
smsgate batch send --map phone=Phone,text=Message --concurrency=5 contacts.csv
Output and error handling:
- Summary:
Batch send summary: total=100 enqueued=95 failed=3 skipped=2 - Real-time progress: Shows each message's UUID and state during sending
- Error handling: By default stops on first error; use
--continue-on-errorto send all rows even if some fail
Best practices:
- Always use
--dry-runor--validate-onlyfirst to test your configuration - Ensure phone numbers are in E.164 format
- Start with lower concurrency values and increase as needed
- Use
--continue-on-errorfor non-critical bulk sends - Combine with inherited message options (e.g.,
--device-id,--priority) for advanced scenarios
# Check delivery status
smsgate status zXDYfTmTVf3iMd16zzdBj# Register a webhook for SMS received events
smsgate webhooks register -e sms:received https://example.com/webhook
# Register a device-specific webhook
smsgate webhooks register -e sms:sent --device-id device123 https://example.com/webhook
# List all registered webhooks
smsgate webhooks list
# Delete a webhook by ID
smsgate webhooks delete <webhook-id>Supported webhook events: sms:received, sms:sent, sms:failed, device:connected, device:disconnected
The logs command retrieves logs for a specific time range. Dates should be in RFC3339 format (e.g., 2024-01-15T10:30:00Z).
# Get logs for the last 24 hours (default)
smsgate logs
# Fetch logs for a specific time range
smsgate logs --from '2024-01-15T00:00:00Z' --to '2024-01-15T23:59:59Z'
# Get logs with custom time range and output format
smsgate --format json logs --from '2024-01-15T10:00:00+07:00' --to '2024-01-15T18:00:00+07:00'Text (human-readable, default)
ID: zXDYfTmTVf3iMd16zzdBj
State: Pending
IsHashed: false
IsEncrypted: false
Recipients:
+12025550123 Pending
+12025550124 Pending
JSON (pretty-printed)
{
"id": "zXDYfTmTVf3iMd16zzdBj",
"state": "Pending",
"isHashed": false,
"isEncrypted": false,
"recipients": [
{
"phoneNumber": "+12025550123",
"state": "Pending"
},
{
"phoneNumber": "+12025550124",
"state": "Pending"
}
],
"states": {}
}Raw (one-line JSON)
{"id":"zXDYfTmTVf3iMd16zzdBj","state":"Pending","isHashed":false,"isEncrypted":false,"recipients":[{"phoneNumber":"+12025550123","state":"Pending"},{"phoneNumber":"+12025550124","state":"Pending"}],"states":{}}Table (tab-aligned columnar output for lists)
ID EVENT URL DEVICE ID
123e4567-e89b-12d3-a456-426614174000 sms:received https://example.com/webhook dev-abc
def45678-e89b-12d3-a456-426614174000 sms:sent https://example.com/other
# Issue a certificate for a private server
smsgate-ca private --out server.crt --keyout server.key 192.168.1.10The IP address must be a private one (RFC 1918, e.g. 10.x.x.x, 172.16.x.x, 192.168.x.x).
| Code | Meaning |
|---|---|
0 |
Success |
1 |
Invalid options/arguments |
2 |
Server request error |
3 |
Output formatting error |
4 |
Internal error |
Errors are printed to stderr without formatting. Full command reference: CLI docs.
The CLI can be configured using environment variables or command-line flags. You can also use a .env file in the working directory to set these variables (loaded automatically via godotenv).
| Flag | Env Var | Applies to | Description | Default value |
|---|---|---|---|---|
--endpoint, -e |
ASG_ENDPOINT |
smsgate |
The endpoint URL | https://api.sms-gate.app/3rdparty/v1 |
--username, -u |
ASG_USERNAME |
smsgate |
Your username | required |
--password, -p |
ASG_PASSWORD |
smsgate |
Your password | required |
--format, -f |
n/a | smsgate |
Output format | text |
--timeout, -t |
ASG_CA_TIMEOUT |
smsgate-ca |
Certificate polling deadline, checked between status requests | 30s |
Output formats: text (human-readable, default), json (pretty-printed), raw (one-line JSON), table (columnar output for lists).
smsgate-ca talks to the certificate authority at https://ca.sms-gate.app/api/v1 and accepts no credentials; its configurable options are --timeout (env ASG_CA_TIMEOUT), --out, and --keyout.
Contributions are welcome. Open an issue or pull request; follow the repo's make fmt / make lint / make test checks and the contributing guidelines.
Apache-2.0. See LICENSE.
Android is a trademark of Google LLC.