cmail

Reference · cmail 0.4.0

Command-line docs

Every command, setting and output format. New here? Start with the setup guide.

Install

curl -fsSL https://raw.githubusercontent.com/luongnv89/cmail/main/install.sh | bash
export PATH="$HOME/.local/bin:$PATH"
cmail --version

With Homebrew (also installs shell completions):

brew install luongnv89/tap/cmail

To build a clone you reviewed instead (needs Rust and cargo):

git clone https://github.com/luongnv89/cmail
cd cmail
bash install.sh --local      # or: cargo install --path .
WhatWhereOverride
Binary~/.local/bin/cmailCMAIL_BIN_DIR at install
Config~/.config/cmail/.env (or $XDG_CONFIG_HOME/cmail/.env)--config, CMAIL_CONFIG or ENV_FILE
  • cmail is one self-contained binary for macOS and Linux (x86_64 and arm64). The one-line command downloads the release build for your system from GitHub and checks its SHA-256 checksum before installing it. --local builds the checkout you cloned.
  • The installer says whether ~/.local/bin is on your PATH and prints the export PATH line to add to your shell profile if it is not.
  • No runtime dependencies: no Bash, curl or jq needed to run cmail. gddy is needed only for GoDaddy mode. No sudo. Installing never runs setup or edits your shell profile.
  • Proxies: cmail does not use HTTPS_PROXY or ALL_PROXY yet. It connects directly to api.cloudflare.com over HTTPS, so it needs direct internet access. The installer's download does follow your proxy settings.
  • To update, run the installer again, brew upgrade cmail, or pull and rerun --local. Your config is kept.

Commands

CommandWhat it doesChanges things?
cmail setupGuided receiving setup in a terminalYes, asks first
cmail setup --dry-runFull plan and blockersNo
cmail statusZone, routing, destinations and rulesNo
cmail list [--domain D]Every address and where it forwardsNo
cmail forward ADDRESS --destination EMAILChange where an existing address forwardsYes, asks first
cmail doctorCheck config, gddy (GoDaddy mode) and tokenNo
cmail doctor --offlineSame, without network requestsNo
cmail send-asOptional Gmail sending guideNo (manual)
cmail config initCreate a private config fileLocal file
cmail config showShow settings, secrets redactedNo
cmail config checkValidate settingsNo
cmail config set KEY VALUEUpdate one settingLocal file
cmail config pathPrint the config path in useNo
cmail completion SHELLPrint bash, zsh or fish completionsNo
cmail help [COMMAND]Help for any commandNo
$ cmail list
╭─┐example.com addresses┌──────────────────────────────────────────╮
│ [email protected]  →  [email protected] (verified)  ✗ disabled │
│ [email protected]    →  [email protected] (verified)  ● enabled  │
├──────────────────────────────────────────────────────────────────┤
│ catch-all → drop  ✗ disabled                                     │
╰─┘2 addresses└────────────────────────────────────────────────────╯

$ cmail doctor --offline
╭─┐cmail doctor┌──────────────────────────────────────────────╮
│ ● pass  config     configuration ready                      │
│ ● pass  registrar  manual registrar mode; gddy not required │
╰─┘2 checks · 2 ok└───────────────────────────────────────────╯

Destinations are marked verified, unverified (click the Cloudflare link) or unregistered.

On a terminal, reports are drawn as boxes. Piped into another program they become plain tab-separated records, one per line with no header (for example [email protected]→[email protected] (verified)→enabled, where → is a tab). For scripts, prefer --format json.

To move an existing address to a new inbox, run cmail forward hello --destination [email protected] in a terminal. The address and its rule stay; only the destination changes. If Cloudflare has not verified the new inbox, nothing changes: cmail offers to send the verification email, and you rerun the command after clicking the link. DEST_EMAIL is updated only when every configured address then forwards to the new inbox.

Configuration

Settings live in one private file (mode 600). cmail setup fills it for you; set values ahead of time if you prefer:

cmail config set DOMAIN example.com
cmail config set DEST_EMAIL [email protected]
cmail config set ADDRESSES hello,contact
cmail config set CLOUDFLARE_API_TOKEN --stdin < /path/to/private/token
cmail config check
KeyMeaning
DOMAINYour domain, e.g. example.com
DEST_EMAILInbox that receives the mail
ADDRESSESComma-separated names: hello,contact
CLOUDFLARE_API_TOKENScoped API token (secret; set via --stdin or setup’s hidden prompt)
REGISTRARmanual (default) or godaddy
CF_ACCOUNT_IDOptional. Pick a Cloudflare account when you have several
CF_ZONE_IDSaved by setup. No need to set
GDDY_ENV, GDDY_PATGoDaddy mode only: environment and optional token
DRY_RUN1 = same as setup --dry-run

Precedence: command option → environment variable → config file → default. Pick another file with --config PATH or CMAIL_CONFIG.

Values are plain literals. Shell commands and $(…) expansions are rejected. Secrets never go on the command line.

Registrar modes

manual · default

Any registrar. cmail prints the Cloudflare nameservers; you set them at your registrar while cmail waits. It never changes delegation and never buys a domain.

godaddy · opt-in

Uses the gddy CLI to pick a GoDaddy domain and switch nameservers after you confirm. The only mode that can offer a purchase, which needs the domain typed at a terminal.

cmail setup --domain example.com      # any registrar
cmail setup --registrar godaddy       # opt in once
cmail config set REGISTRAR godaddy    # opt in permanently

Preview & JSON

setup --dry-run previews the whole workflow: no provider changes, purchases, config writes or browser launches. It exits 0 even with blockers, so read data.blockers.

cmail setup --dry-run --format json
cmail status --format json | jq '.data.rules'
cmail doctor --offline --format json

JSON is available for status, list, doctor, config show/check and previews:

{"schema_version":1,"command":"status","data":{"zone":{},"routing":{},"destinations":[],"rules":[]}}

Setup, forward and send-as need a real terminal. In scripts, use --dry-run.

Global options

-c, --config PATHUse a specific config file
-f, --format text|jsonReport format
-v, --verbose / -q, --quietMore (redacted) detail / less progress
--no-colorNo color (also NO_COLOR); FORCE_COLOR=1 styles output that is not a terminal
--no-browserPrint links instead of opening them
--timeout SECONDSHTTP timeout, default 30
setup --wait-timeout SECONDSEach activation/verification wait, default 1200
-h, --help · -V, --versionHelp and version

Results go to stdout; progress, prompts and errors to stderr.

Exit codes

CodeMeaning
0Success, or report generated
1Runtime or check failure
2Invalid arguments, or no terminal available
3Invalid or incomplete input/config
130Interrupted (Ctrl+C)
143Terminated (SIGTERM)

Shell completions

Homebrew installs completions automatically. Otherwise:

# bash
cmail completion bash > ~/.cmail-completion.bash
echo 'source ~/.cmail-completion.bash' >> ~/.bashrc

# zsh (put fpath before compinit in .zshrc)
mkdir -p ~/.zfunc && cmail completion zsh > ~/.zfunc/_cmail

# fish
cmail completion fish > ~/.config/fish/completions/cmail.fish

Full details: docs/cli.md on GitHub.