Prerequisites
- A SendLayer account and API key (get your API key)
- A verified sending domain (authorize your domain)
- Node.js 18 or newer, if you install with npm
Installation
- npm
- Standalone binary
Install the CLI globally from npm:
Authentication
Runsendlayer login and paste your API key when prompted. The CLI checks the key against the SendLayer API before saving it.
SENDLAYER_API_KEY environment variable instead. Every command reads it.
- The
--api-keyflag - The
SENDLAYER_API_KEYenvironment variable - Credentials saved by
sendlayer login
whoami. The CLI always masks the key:
Profiles
Save keys for several accounts or environments under named profiles. Then pass--profile to any command to use that key:
--profile uses the default profile. If you log out of the default profile, the CLI promotes another saved profile and tells you which one.
0600 at:
- macOS and Linux:
~/.config/sendlayer/credentials.json(or$XDG_CONFIG_HOME/sendlayer/credentials.json) - Windows:
%APPDATA%\sendlayer\credentials.json
Send an email
Pass the sender, recipients, subject, and body as flags:--from address must use a domain you’ve authorized in SendLayer. Use a plain email address, or Name <email> to set a display name.
HTML and plain text
Pass the body inline with--html and --text, or read it from a file with --html-file and --text-file. When you send both, email clients that don’t render HTML show the plain-text version.
Recipients, attachments, and headers
--to,--cc,--bcc, and--reply-totake a comma-separated list. Pass each of these flags once.- Repeat
--attachment,--header, and--tagto add more than one. --attachmenttakespath[:mime[:disposition[:filename]]]. If you leave out the MIME type, the CLI guesses it from the file extension. The disposition isattachment(the default) orinline.--headertakesKey=Value.
Send from a JSON file
For complex emails, put the full payload in a JSON file and pass it with--file. The file uses the same fields as the Node.js SDK.
email.json
Query events
List delivery and engagement events, with optional filters:Manage webhooks
bounce, click, open, unsubscribe, complaint, and delivery. For the payload each one sends, see Managing Webhooks.
Test webhooks locally
webhooks listen receives webhook events on your machine while you develop. It needs a public HTTPS URL that tunnels to a local port, such as one from ngrok.
1
Start a tunnel
Expose a local port. The CLI listens on port
4000 by default. Use --port to change it.2
Start the listener
In another terminal, pass the tunnel URL. Add The CLI creates one webhook per event type and prints each event as it arrives. To listen for specific types only, add
--forward-to to send each event on to your local app.--events bounce,click.3
Stop the listener
Press
Ctrl+C. The CLI deletes every webhook it created. If a previous run crashed, the next run offers to clean up the leftover webhooks.Use the CLI with AI agents and scripts
In a terminal, the CLI prints readable output. When its output goes to a pipe, a CI job, or an AI coding agent such as Claude Code, Cursor, or Codex, it switches to JSON automatically. Add--json to any command to force JSON output.
JSON output works with tools like jq. This command lists the recipients of failed emails:
details.response.Errors, see Error Codes.
Exit codes
Scripts and agents branch on the exit code without parsing the error message:GitHub Actions example
Store your API key as a repository secret namedSENDLAYER_API_KEY. Then install and run the CLI in a workflow step:
.github/workflows/release.yml
Get help
Add--help to any command to see its flags and examples:
FAQ
What's the difference between the CLI and the MCP server?
What's the difference between the CLI and the MCP server?
Both give AI tools access to SendLayer. The MCP server adds SendLayer tools to any app that supports MCP, including chat apps such as Claude Desktop. The CLI runs as a shell command, so it also works in scripts, cron jobs, and CI pipelines.
Why does the CLI print JSON instead of text?
Why does the CLI print JSON instead of text?
The CLI switches to JSON when its output isn’t a terminal, such as when you pipe it to another command. Run the command directly in a terminal to see readable output.
How do I switch between SendLayer accounts?
How do I switch between SendLayer accounts?
Save each account’s key under its own profile with
sendlayer login --profile <name>. Then pass --profile <name> to any command. Run sendlayer whoami to check which profile is active.