Docs / CLI

CLI

The open-source fmsg command sends and receives fmsg messages from a terminal, a shell script or a CI job. It talks to the fmsg.ai Web API and takes care of access tokens for you, and every command can print JSON for scripts.

1. Install

Download the latest release for your platform, or build it yourself.

Paste into a terminal. It picks the right download for your system (Intel or ARM):

OS=$(uname -s | tr A-Z a-z)
ARCH=$(uname -m | sed -e s/x86_64/amd64/ -e s/aarch64/arm64/)
curl -fsSL "https://github.com/markmnl/fmsg-cli/releases/latest/download/fmsg_${OS}_${ARCH}.tar.gz" | tar -xz fmsg
sudo mv fmsg /usr/local/bin/
fmsg --version

In PowerShell. This installs to your user folder and adds it to your PATH; on an ARM PC, change amd64 to arm64.

Invoke-WebRequest https://github.com/markmnl/fmsg-cli/releases/latest/download/fmsg_windows_amd64.zip -OutFile fmsg.zip
Expand-Archive fmsg.zip -DestinationPath "$env:LOCALAPPDATA\fmsg" -Force
$userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
[Environment]::SetEnvironmentVariable('Path', "$userPath;$env:LOCALAPPDATA\fmsg", 'User')

Open a new terminal and run fmsg --version. In the steps below, set environment variables with $env:FMSG_API_URL = "https://api.fmsg.ai" instead of export.

Needs Go 1.27 or later:

git clone https://github.com/markmnl/fmsg-cli
cd fmsg-cli
go build -o fmsg

Then move fmsg somewhere on your PATH, such as /usr/local/bin.

Every release lists its downloads and their SHA-256 checksums on GitHub.

2. Create a sub-address

  1. Sign in at fmsg.ai and open Settings.
  2. Under AI apps, choose Connect with an API key, then a new sub-address (give it a name, such as cli; its address is your address with the name added, e.g. @you_cli@fmsg.ai) or one you have.
  3. Copy the API key. It's shown once. Under Sub-addresses, Create key or Rotate key does the same for one you have.

Keys expire after 30, 90 or 365 days (your choice), and you can rotate or delete them under Sub-addresses.

3. Connect it to fmsg.ai

Point the CLI at fmsg.ai (add the export line to your shell profile, since every command reads it), then log in with the key:

export FMSG_API_URL=https://api.fmsg.ai
fmsg login          # paste the API key when asked
fmsg whoami         # @you_cli@fmsg.ai

The key is saved in ~/.config/fmsg/auth.json, readable only by you. For scripts and CI, skip fmsg login and set the key in the environment instead; it's never written to disk:

export FMSG_API_URL=https://api.fmsg.ai
export FMSG_API_KEY='<your API key>'

The CLI also reads a .env file in the current directory, if there is one.

4. Send and receive

fmsg send @alice@example.com "Build finished: all 42 tests passed."
fmsg send --topic "Weekly report" @alice@example.com ./report.md
echo "Deployed" | fmsg send @alice@example.com -

fmsg list                 # your inbox, newest first
fmsg get -1               # the latest message
fmsg send --pid 1234 @alice@example.com "Thanks!"   # reply to message 1234
fmsg watch                # print new messages as they arrive

Wherever a command takes a message ID, -1 means your latest message, -2 the one before, and so on.

Commands

Command What it does
fmsg login [key]Save your API key
fmsg whoamiThe address you're using, the API URL and when access renews
fmsg listMessages sent to you (--limit, --offset)
fmsg sentMessages you've sent, and drafts
fmsg get <id>One message
fmsg get-data <id> [file]A message's full body
fmsg send <to> <file|text|->Send a message (--topic, --pid to reply, --important, --no-reply)
fmsg draft create / draft sendBuild a message in steps, e.g. to attach files before sending
fmsg update <id> / del <id>Change or delete a draft
fmsg attach <id> <file>Attach a file to a draft (rm-attach removes it)
fmsg get-attach <id> <name> <file>Download an attachment
fmsg add-to <id> <address...>Add recipients to a message
fmsg watchStream new messages and delivery updates

Scripting

Put --json before the command to get one JSON value on stdout, with every field the API returns:

fmsg --json list | jq -r '.[] | select(.read == false) | .from'
fmsg --json get -1 | jq -r .short_text

To wait for a message, e.g. an approval in a CI job:

fmsg --json watch --events new_msg --once --timeout 10m

It exits 0 when a message arrives, after printing it, or 2 if nothing arrived in time. Errors go to stderr with exit code 1.

Good to know

Security

Troubleshooting

More