emailservicehub
v0.1.20
Published
CLI client for Email Service Hub — manage SES and NameCheap from the terminal
Maintainers
Readme
emailservicehub
CLI client for Email Service Hub. Manage AWS SES and NameCheap DNS from the terminal.
Website: https://www.emailservicehub.com
Install
# Run without installing
npx esh --help
npx emailservicehub --help
# Or install globally
npm install -g emailservicehub
esh --helpThe binary is available as both esh (short) and emailservicehub (long).
Quick start
# 1. Authenticate — opens your browser to authorize the CLI
esh login
esh whoami
# 2. Store your NameCheap API credentials on your ESH account
esh nc key set --api-key <key> --api-user <user>
# 3a. Minimal: just register the domain identity in SES so SMTP can use it
# (writes only the _amazonses verification TXT — safe alongside NameCheap
# email forwarding / Private Email)
esh ses domain register example.com
# 3b. Full setup: verification + DKIM + SPF + DMARC, written to NameCheap DNS,
# then blocks until SES reports the domain as Verified (pass --no-wait
# for fire-and-forget). MAIL FROM subdomain is opt-in (--mail-from)
# because it submits an MX that disables NameCheap email forwarding on
# the apex.
esh ses domain add example.com
# 4. Send a test email once verification completes
esh ses send --from [email protected] --to [email protected] \
--subject "Hi" --message "Hello from esh"Local development against the dev server
If you're hacking on the Next.js app and the CLI at the same time, run the CLI
via pnpm cli:dev from the repo root — it builds the CLI in watch mode and
automatically targets http://localhost:3000 without needing --dev:
# Run any esh command against the local dev server
pnpm cli:dev ses identities
pnpm cli:dev ses domain add example.comThe auto---dev behavior triggers whenever the CLI is invoked under the
cli:dev script; pass --prod to override it, or --port <n> to point at a
dev server on a non-default port.
Not logged in? Use local credentials instead
By default the CLI talks to the Email Service Hub API, which holds your AWS
and NameCheap credentials server-side — esh login is the normal happy path.
If you'd rather not sign up or store credentials on a hosted service, pass
--local to skip the ESH API entirely and drive AWS and NameCheap directly
from credentials on your own machine:
# AWS SES calls use ~/.aws/credentials (standard AWS SDK resolution)
# NameCheap calls use NAMECHEAP_API_KEY + NAMECHEAP_API_USER env vars
export NAMECHEAP_API_KEY=abc123...
export NAMECHEAP_API_USER=myuser
esh --local ses identities
esh --local nc domains list
esh --local ses domain add example.comWhen you run a command without being logged in, the CLI will remind you of this option before it errors out. See Local mode below for the full list of env vars and flags.
Global flags
These flags work on every command:
| Flag | Description |
| --- | --- |
| --json | Emit raw JSON instead of formatted tables (good for scripting) |
| --no-color | Disable ANSI colors |
| --verbose | Show HTTP request/response details |
| --profile <name> | Use a named profile from ~/.esh/config.json |
| --dev | Target the local Next.js dev server (http://localhost:3000) instead of production |
| --prod | Force the production ESH API (https://emailservicehub.com) — useful to override the auto---dev triggered by pnpm cli:dev |
| --port <number> | Override the dev-server port (implies --dev) |
| --local | Skip the ESH API entirely and call AWS + NameCheap directly from your machine using local credentials (see Local mode) |
| --aws-profile <name> | AWS named profile to load from ~/.aws/credentials when using --local. Defaults to $AWS_PROFILE or default. |
| --aws-region <region> | AWS region for SES calls in --local mode. Defaults to $AWS_REGION, then $AWS_DEFAULT_REGION, then us-east-1. |
| -V, --version | Print the CLI version |
| -h, --help | Print help for any command (works on every subcommand) |
Authentication
| Command | Description |
| --- | --- |
| esh login | Authenticate via the browser. Opens https://emailservicehub.com/cli/auth in your default browser, waits for you to approve, then stores a per-user API key in ~/.esh/config.json. |
| esh login --token <key> | Non-interactive login for CI/scripts. Stores the supplied API key directly and verifies it against the server. |
| esh logout | Remove stored credentials for the active profile. |
| esh whoami | Show the currently authenticated user's email and role. |
| esh status | Show config file location, active profile, API URL, and auth state. |
The browser flow spins up an ephemeral HTTP server on a random localhost port, prints the authorization URL it's about to open, and waits for you to press Enter or Space before actually opening the browser (Ctrl-C cancels). Once you approve in the browser, the page delivers a freshly-minted API key back to the local server and the CLI stores it. The key is hashed server-side (SHA-256) before storage; only the plaintext copy in your ~/.esh/config.json exists anywhere in the clear. When stdin isn't a TTY (piped input, CI), the keypress gate is skipped and the browser opens immediately.
esh ses — AWS SES
| Command | Description |
| --- | --- |
| esh ses stats | Show SES quotas, 24h send counts, and delivery rate. |
| esh ses identities | List all verified SES identities (domains and email addresses) with DKIM state. |
| esh ses activity [-l, --limit <n>] | Show recent email activity. Default limit: 10. |
| esh ses domain register <domain> | Minimally register a domain with SES so it can be used as the From: address on the AWS SMTP endpoint. Writes only the _amazonses verification TXT — no DKIM, SPF, DMARC, or MAIL FROM. Re-runs are safe: the output reports whether the domain was already verified, still pending, previously failed, or freshly initiated. Use --no-dns to print the record for manual entry. |
| esh ses domain add <domain> | Add a domain to SES end-to-end: registers the identity, enables DKIM, configures NameCheap DNS (verification TXT + 3 DKIM CNAMEs + SPF + DMARC), then waits for SES to report verification + DKIM as Success. MAIL FROM subdomain is opt-in — pass --mail-from to enable it (it adds an apex-level MX that disables NameCheap email forwarding). Pass --no-wait to skip the verification poll. See flags below. |
| esh ses email add <address> | Request SES verification for an email address. SES sends a confirmation link to the address; the recipient must click it to finish. Re-runs are safe — the output reports whether the address was already verified, still pending, previously failed, or freshly requested. |
| esh ses send | Send a test email. See required flags below. |
esh ses domain register <domain> flags
| Flag | Description |
| --- | --- |
| --no-dns | Skip the NameCheap write — call SES VerifyDomainIdentity only and print the TXT record for manual entry. |
Use register when you only need to send mail through the AWS SMTP endpoint and want minimal blast radius: it adds only the _amazonses TXT and never submits an MX, so it is safe alongside NameCheap email forwarding, Private Email, or any other apex mail product. For full deliverability hardening (DKIM/SPF/DMARC), follow up with esh ses domain add once you've confirmed nothing else on the domain depends on the existing apex MX configuration.
esh ses domain add <domain> flags
| Flag | Description |
| --- | --- |
| --no-dns | Skip NameCheap DNS setup — only initiate SES verification and print the records for manual entry. |
| --no-spf | Do not add an SPF (v=spf1 include:amazonses.com ~all) TXT record. |
| --no-dmarc | Do not add a DMARC (p=none, with rua=) TXT record. |
| --mail-from | Opt in to a custom mail.<domain> MAIL FROM subdomain (MX + SPF TXT). Off by default because the MX submission flips NameCheap's zone-level EmailType from FWD (or OX) to MX, which disables NameCheap email forwarding and Private Email on the apex. Enable only on domains where you don't use NameCheap-hosted inbound mail. |
| --no-wait | Skip the verification poll. By default the command blocks for up to 2 minutes waiting for SES to mark domain verification + DKIM (and MAIL FROM, if --mail-from was passed) as Success. |
The command preserves existing NameCheap records, merging only where host+type collides. Existing TXT records that would be replaced by SPF/DMARC are surfaced as warnings before the write. MX records are submitted to NameCheap with the priority split from the host (the CLI auto-parses zone-file format like 10 feedback-smtp.us-west-2.amazonses.com).
Re-runs are safe: the output distinguishes "already verified", "already pending", and freshly-initiated states based on what SES reported before this invocation, and the wait phase exits early if SES already considers everything verified.
Coexistence with NameCheap email products. NameCheap stores a zone-level EmailType (FWD for Email Forwarding, OX for Private Email, MX for custom mail servers) that drives the apex MX records server-side — those MX records do not appear in nc dns list output. The CLI flips EmailType to MX only when the records it submits include an MX, so DKIM/SPF/DMARC are safe to add to a forwarding-enabled domain. --mail-from does submit an MX (on mail.<domain>) and will switch EmailType to MX, disabling NameCheap forwarding/Private Email on the apex — that is why MAIL FROM is opt-in. esh ses domain add --mail-from is the only domain flow that touches MX; the rest are MX-free and forwarding-safe.
esh ses send flags
| Flag | Description |
| --- | --- |
| --from <email> | Required. Sender address (must be a verified SES identity). |
| --to <email> | Required. Recipient address. |
| --subject <text> | Required. Email subject. |
| --message <text> | Required. Plain-text body. |
| --html <html> | Optional HTML body. |
esh nc — NameCheap
By default, NameCheap commands read your API credentials from your ESH account (set them once via esh nc key set). When invoked with --local, they instead read from environment variables — see Local mode.
Key management
| Command | Description |
| --- | --- |
| esh nc key show (default) | Show the masked NameCheap API key stored in your ESH account. Also runs as esh nc key. |
| esh nc key set --api-key <key> --api-user <user> [--client-ip <ip>] | Store your NameCheap API credentials. --client-ip defaults to the ESH server's public IP (the one NameCheap whitelists). |
| esh nc key test | Test the currently-stored NameCheap credentials by making a read-only API call and reporting pass/fail with an actionable hint on failure. |
| esh nc key test --api-key <key> --api-user <user> [--user-name <name>] [--client-ip <ip>] | Test candidate credentials without storing them. Useful before esh nc key set to verify a key is valid, API access is enabled, and the source IP is whitelisted. Exits non-zero on failure for scripting. |
Domains
| Command | Description |
| --- | --- |
| esh nc domains list (default) | List all domains on your NameCheap account. Also runs as esh nc domains. |
| esh nc domains check <domain> | Check whether a domain is available for registration. |
DNS
| Command | Description |
| --- | --- |
| esh nc dns list <domain> | List all DNS records for a domain. |
| esh nc dns set <domain> --type <type> --host <host> --value <value> [--ttl <ttl>] | Add or update a DNS record. Replaces any existing record with the same host+type; preserves all others. TTL defaults to 1800. |
| esh nc dns delete <domain> --type <type> --host <host> | Delete a DNS record by host+type. |
esh config — CLI configuration
| Command | Description |
| --- | --- |
| esh config show | Print the full config file contents. |
| esh config get <key> | Get a single config value. Valid keys: api-url, token, email. |
| esh config set <key> <value> | Set a config value. Valid keys: api-url, token, email. |
| esh config reset | Reset the config file to defaults (default profile pointing at https://emailservicehub.com). |
Credentials are stored in ~/.esh/config.json (permissions 0600). Each profile keeps its own apiUrl, token, and email, switchable with the global --profile flag.
Local mode
The CLI has two operating modes:
- Remote mode (default) — commands call the Email Service Hub API, which holds your AWS and NameCheap credentials server-side. This is the recommended path and is what
esh loginsets up. Everything in theesh sesandesh nccommand trees works out of the box once you're logged in. - Local mode (
--local, opt-in) — the CLI skips the ESH API entirely and talks to AWS SES and the NameCheap XML API directly from your machine, using credentials it finds on your local system. No ESH login is required;--localworks even when you're logged out.
Local mode is the right fit when you want to run the CLI against credentials you already manage yourself — e.g., on a workstation with ~/.aws/credentials already configured, or in CI where secrets come in as environment variables — without round-tripping through the hosted API.
You don't need to think about local mode unless you want to. When you run a command without being logged in, the CLI will print a one-line hint pointing you at both options (esh login or esh --local …) so you can pick the one that fits your setup. Remote mode remains the default in every other case.
AWS credentials (SES commands)
In --local mode, AWS calls use the standard AWS SDK credential-provider chain, in this order:
AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY/AWS_SESSION_TOKENenvironment variables- A named profile from
~/.aws/credentials(and~/.aws/config) - AWS SSO / IAM role profiles configured in
~/.aws/config
| Setting | Source | Default |
| --- | --- | --- |
| AWS profile | --aws-profile <name>, then $AWS_PROFILE | default |
| AWS region | --aws-region <region>, then $AWS_REGION, then $AWS_DEFAULT_REGION | us-east-1 |
Example:
# Use the 'staging' profile from ~/.aws/credentials
esh --local --aws-profile staging --aws-region us-west-2 ses identities
# Or via env vars
AWS_PROFILE=staging AWS_REGION=us-west-2 esh --local ses identitiesNameCheap credentials (nc commands)
In --local mode, NameCheap commands read credentials from environment variables:
| Env var | Required | Description |
| --- | --- | --- |
| NAMECHEAP_API_KEY | yes | Your NameCheap API key (Profile → Tools → API Access) |
| NAMECHEAP_API_USER | yes | Your NameCheap API user — usually your NameCheap account username |
| NAMECHEAP_USERNAME | no | NameCheap UserName parameter. Defaults to $NAMECHEAP_API_USER. |
| NAMECHEAP_CLIENT_IP | no | IP address whitelisted in NameCheap's API settings. If unset, the CLI auto-detects your public IP via a public echo service and falls back to 127.0.0.1. Override per-invocation with --client-ip. |
NameCheap's API requires that the caller's IP is explicitly whitelisted in your account settings. If local-mode calls fail with Invalid request IP, set NAMECHEAP_CLIENT_IP to the IP you whitelisted (usually your workstation's public IP).
Example:
export NAMECHEAP_API_KEY=abc123...
export NAMECHEAP_API_USER=myuser
esh --local nc domains list
esh --local nc dns list example.com
esh --local nc dns set example.com --type TXT --host @ --value "v=spf1 include:amazonses.com ~all"Mixed commands
esh ses domain add touches both AWS and NameCheap. In --local mode, both credential sources must be available: AWS for the SES calls, NameCheap env vars for the DNS writes. Pass --no-dns to skip the NameCheap side entirely if you only have AWS credentials locally.
export NAMECHEAP_API_KEY=abc123...
export NAMECHEAP_API_USER=myuser
esh --local ses domain add example.comJSON mode
Every command honors --json for machine-readable output, making the CLI scriptable:
# Pipe identities into jq
esh --json ses identities | jq '.identities[] | select(.verificationStatus == "Success") | .identity'
# Grab just the verification token when registering a domain without touching DNS
esh --json ses domain register example.com --no-dns | jq -r .verificationTokenHelp
Every command and subcommand supports --help:
esh --help
esh ses --help
esh ses domain register --help
esh ses domain add --help
esh nc dns set --help