Official CLI for the Paubox encrypted email API. Send HIPAA-compliant email, check delivery status, and manage your credentials from the terminal.
npm install -g paubox-clibrew tap paubox/paubox
brew install paubox-cliwinget install Paubox.CLIOr via npm:
npm install -g paubox-cliKeytar (optional): The CLI uses the Windows Credential Vault for secure credential storage via the
keytarnative module. Ifkeytarfails to build during install, credentials fall back to a config file automatically — no action required. To enable native keychain support, install Visual C++ Build Tools before runningnpm install -g paubox-cli.
- Node.js ≥ 20.12.0
- On Linux:
libsecret-1-devis required for OS keychain supportWithout it, credentials fall back to a local config file automatically (sudo apt-get install libsecret-1-dev
~/.config/paubox/config.jsonon Linux/macOS,%APPDATA%\paubox\config.jsonon Windows).
# Authenticate with your Paubox API credentials
paubox auth login
# Send an email
paubox send --to recipient@example.com --from you@yourdomain.com --subject "Hello" --text "Hi there!"
# Check delivery status
paubox status <trackingId>Manage Paubox API credentials.
paubox auth login # Prompt for API username and key; validate and store
paubox auth logout # Remove stored credentials
paubox auth status # Show current authentication stateCredentials are stored in the OS keychain (macOS Keychain, Windows Credential Vault, Linux Secret Service) when available. If the keychain is unavailable, they fall back to a local config file (~/.config/paubox/config.json on Linux/macOS, %APPDATA%\paubox\config.json on Windows).
Send a secure email.
paubox send \
--to recipient@example.com \
--from sender@yourdomain.com \
--subject "Your subject" \
--text "Plain text body" \
--html "<p>HTML body</p>" \
--attachment /path/to/file.pdf| Flag | Required | Description |
|---|---|---|
--to <email...> |
Yes | Recipient(s). Repeat for multiple: --to a@b.com --to c@d.com |
--from <email> |
No* | Sender address. Defaults to defaultFrom config value |
--subject <text> |
Yes | Email subject |
--text <body> |
No† | Plain text body |
--html <body> |
No† | HTML body |
--attachment <file...> |
No | File path(s) to attach |
† At least one of --text or --html is required.
On success, prints the source tracking ID:
✓ Email sent. Tracking ID: abc123-def456
Check the delivery status of a sent email.
paubox status <trackingId>Outputs a table of recipients with delivery status and timestamps:
recipient status delivered at opened opened at
--------------------- --------- ------------------------ ------ ---------
to@example.com delivered 2026-01-01T12:00:00Z opened 2026-01-01T13:00:00Z
Retrieve form metadata and submit responses to Paubox forms. These commands do not require authentication.
paubox forms get <formId>
paubox --json forms get <formId>Prints the form's title, description, active status, submission count, and timestamps. With --json, returns the raw API response object.
# Inline key=value pairs (repeatable)
paubox forms submit <formId> \
--data "first_name=Jane" \
--data "last_name=Doe" \
--data "email=jane@example.com"
# Read form fields from a JSON file
paubox forms submit <formId> --data-file ./fields.json
# Mix file and inline overrides (--data wins on matching keys)
paubox forms submit <formId> \
--data-file ./base.json \
--data "field=override"
# Attach a file with the submission
paubox forms submit <formId> \
--data "name=Jane" \
--attach /path/to/signed-consent.pdf| Flag | Description |
|---|---|
--data <key=value> |
Form field as a key=value pair. Repeatable. Values may contain =. |
--data-file <path> |
Path to a JSON file whose top-level string values are used as form_data. Merged with --data; --data takes precedence on matching keys. |
--attach <file> |
File to include as an attachment. Repeatable. Total request size must not exceed 250 MB. |
On success:
✓ Form submitted successfully.
With --json:
{ "status": "ok", "formId": "<formId>" }Manage CLI configuration stored in ~/.config/paubox/config.json (Linux/macOS) or %APPDATA%\paubox\config.json (Windows).
paubox config set defaultFrom sender@yourdomain.com
paubox config get defaultFrom
paubox config list
paubox config reset| Key | Description |
|---|---|
defaultFrom |
Default sender address used when --from is omitted |
These flags work with any command:
| Flag | Description |
|---|---|
--json |
Output result as JSON (useful for scripting) |
-q, --quiet |
Suppress non-essential output |
-v, --version |
Print version |
--help |
Show help |
paubox --json send --to to@example.com --from from@example.com --subject Hi --text Hello
# {"sourceTrackingId":"abc123-def456"}After publishing to npm, create the Homebrew tap in a separate repository named homebrew-paubox:
homebrew-paubox/
└── Formula/
└── paubox-cli.rb
class PauboxCli < Formula
desc "Official CLI for the Paubox encrypted email API"
homepage "https://github.com/Paubox/paubox-cli"
url "https://registry.npmjs.org/paubox-cli/-/paubox-cli-0.1.0.tgz"
sha256 "<sha256 of the npm tarball>"
license "Apache-2.0"
depends_on "node"
def install
system "npm", "install", *std_npm_args
bin.install_symlink libexec/"bin/paubox"
end
test do
assert_match "paubox", shell_output("#{bin}/paubox --version")
end
endTo get the SHA256: curl -s https://registry.npmjs.org/paubox-cli/0.1.0 | jq -r .dist.shasum
git clone https://github.com/Paubox/paubox-cli.git
cd paubox-cli
npm install
npm test # Run tests
npm run lint # Lint
npm run build # Compile TypeScript
npm run dev -- auth status # Run without buildingsrc/
commands/ auth, send, status, config, forms command handlers
lib/ api client, forms API client, credential storage, config store, output helpers
index.ts Library entry — exports createProgram() and run()
cli.ts Runtime entry — invokes run() (used by bin/ and `npm run dev`)
bin/
paubox.js Shebang wrapper (ships in npm package)
test/ Jest unit tests mirroring src/ structure
Releases are fully automated through Release Please and npm Trusted Publishers. No local commands, no tokens, no manual tagging.
- Land changes on
masterusing Conventional Commits:fix: ...→ patch bump (e.g. 0.1.0 → 0.1.1)feat: ...→ minor bump (e.g. 0.1.0 → 0.2.0)feat!: ...orBREAKING CHANGE:in the body → minor bump pre-1.0, major bump after 1.0chore: ...,docs: ...,refactor: ...,test: ...→ no version bump
- The release-please workflow opens (or updates) a PR titled
chore(master): release <next-version>with a generatedCHANGELOG.mdentry and the version bump inpackage.jsonand.release-please-manifest.json. - When that PR is merged, the same workflow creates the
paubox-cli-v<version>git tag + GitHub Release, then immediately runs a dependentpublishjob that validates the build and publishes to npm with provenance via OIDC.
Release-please and the publish job live in the same workflow file (release-please.yml) on purpose: a separate workflow listening for tag pushes would never fire, because tags created by GITHUB_TOKEN deliberately don't trigger downstream workflows. Chaining the jobs via needs: keeps the entire release in one run, no PAT required.
If the publish job ever fails for a transient reason (registry hiccup, OIDC rotation, etc.), recover by re-running just the failed job from the Actions UI — the release-please job already created the tag and Release, so re-running the publish job picks them up unchanged.
- Repository setting: Settings → Actions → General → Workflow permissions → Allow GitHub Actions to create and approve pull requests (so release-please can open the release PR).
- npm package setting: a trusted publisher must be configured at
npmjs.com/package/paubox-cli/access, pointing at this repo andrelease-please.yml.
Apache 2.0 — see LICENSE