Posthawk CLI

The Posthawk CLI ships inside the same npm package as the Node.js SDK. A single global install gives you commands to scaffold new projects, preview React Email templates with hot reload, and send templates directly from the terminal — no dashboard, no wrapper scripts.

SDKnpm i -g posthawk

Install once globally. You get the `posthawk` binary plus all the SDK types. The CLI works on macOS, Linux, and Windows with Node.js 18 or newer.

Example

bash
npm i -g posthawk

# verify install
posthawk --version
SDKposthawk login

Store your API key locally in ~/.posthawk/config.json (file mode 0600). The CLI verifies the key against /v1/domains before saving. You can also set POSTHAWK_API_KEY as an env var to override the stored key.

Example

bash
# Interactive login (masked prompt)
posthawk login

# Or via environment variable
export POSTHAWK_API_KEY=ck_live_...

# Check the active key
posthawk whoami

# Remove the stored key
posthawk logout
SDKposthawk init [dir]

Scaffold a new project with a React Email starter template, package.json, .env.local, and .gitignore. Run it in an existing directory to add the files without overwriting anything.

Example

bash
# New folder
posthawk init my-emails
cd my-emails
npm install

# Or scaffold into the current folder
posthawk init .

# Output:
#   created  emails/welcome.tsx
#   created  .env.local
#   created  .gitignore
#   created  package.json
#   ✓ Project ready.
SDKposthawk preview <file.tsx>

Start a local dev server with hot reload for a React Email template. Edit the file and the rendered preview updates instantly via SSE. The preview server has an HTML view and a Plain Text view so you can check both variants of the email.

ParameterTypeDescription
filerequiredstringPath to a .tsx/.jsx email template with a default export
--portnumberOverride the default port (7321)
--propsjsonJSON string passed as props to the component

Example

bash
# Start the preview server
posthawk preview emails/welcome.tsx

# Custom port
posthawk preview emails/welcome.tsx --port 8000

# Pass props to the component
posthawk preview emails/welcome.tsx \
  --props '{"name":"Alex","actionUrl":"https://example.com"}'

# Output:
#   ▸ starting dev server at http://localhost:7321
#   ✓ ready in 182ms
#     watching for changes · press Ctrl+C to stop
SDKposthawk send <file.tsx> --to <email> --from <email>

Compile a React Email template, render it to HTML + plain text, and send it via the Posthawk API. The send command honours the same --props flag as preview, so the exact same template renders in both commands.

ParameterTypeDescription
filerequiredstringPath to a .tsx/.jsx email template
--torequiredstringRecipient(s), comma-separated
--fromrequiredstringSender (must be from a verified domain)
--subjectstringOverrides the template's default subject
--ccstringCC recipients, comma-separated
--bccstringBCC recipients, comma-separated
--propsjsonJSON string passed as props to the component
--dry-runflagCompile and render without sending

Example

bash
# Minimal send
posthawk send emails/welcome.tsx \
  --to alex@acme.io \
  --from hello@yourdomain.dev

# With props, custom subject, and cc
posthawk send emails/welcome.tsx \
  --to alex@acme.io,sam@acme.io \
  --cc noreply@yourdomain.dev \
  --from hello@yourdomain.dev \
  --subject "Welcome to Acme" \
  --props '{"name":"Alex"}'

# Dry-run: compile and render without hitting the API
posthawk send emails/welcome.tsx \
  --to test@example.com \
  --from hi@example.dev \
  --dry-run

# Output:
#   ▸ compiling welcome.tsx
#     compiled in 195ms
#   ▸ sending via api.posthawk.dev
#   ✓ sent in 140ms
#     id       em_01HQT3...
#     to       alex@acme.io
SDKexport default Component; export const subject

The CLI expects each template to default-export a React component. Optionally, you can export a `subject` string or function — the CLI uses it as the default subject when --subject is not passed. The `subject` function receives the same props as the component.

Example

typescript
// emails/welcome.tsx
import { Body, Container, Heading, Html, Text } from '@react-email/components';

interface WelcomeEmailProps {
  name?: string;
}

// Optional subject export — receives the same props as the component
export const subject = ({ name }: WelcomeEmailProps) =>
  `Welcome to Posthawk${name ? `, ${name}` : ''}!`;

// Default export is the component
export default function WelcomeEmail({ name = 'there' }: WelcomeEmailProps) {
  return (
    <Html>
      <Body>
        <Container>
          <Heading>Hi {name},</Heading>
          <Text>Welcome to Posthawk!</Text>
        </Container>
      </Body>
    </Html>
  );
}
SDKposthawk domains

List all domains in your workspace with their verification status. Useful for checking which from addresses you can use with `posthawk send`.

Example

bash
posthawk domains

# Output:
#   Domains (3)
#
#     ● yourdomain.dev     — verified  · eu-north-1
#     ● notify.acme.io     — verified  · us-east-1
#     ○ staging.acme.io    — pending   · eu-north-1
SDKPOSTHAWK_API_KEY / POSTHAWK_BASE_URL

All CLI commands respect the same environment variables as the SDK. Env vars take precedence over the stored config file.

ParameterTypeDescription
POSTHAWK_API_KEYstringOverrides the stored API key — essential for CI/CD
POSTHAWK_BASE_URLstringOverrides the API URL — use this for self-hosted instances
NO_COLORflagDisables colored terminal output

Example

bash
# Run in CI without interactive login
export POSTHAWK_API_KEY=ck_live_...

posthawk send emails/release-notes.tsx \
  --to announcements@acme.io \
  --from release-bot@acme.dev \
  --props "{\"version\":\"${GITHUB_REF_NAME}\"}"

# Self-hosted instance
export POSTHAWK_BASE_URL=https://api.yourdomain.com
posthawk whoami
SDKGitHub Actions workflow

Ship release notes automatically when a git tag is pushed. The CLI works in any CI environment that has Node.js 18+ and can install global npm packages.

Example

yaml
# .github/workflows/release-notes.yml
name: Send Release Notes
on:
  push:
    tags: ['v*']

jobs:
  send:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm ci
      - run: npm i -g posthawk

      - name: Send release notes
        env:
          POSTHAWK_API_KEY: ${{ secrets.POSTHAWK_API_KEY }}
        run: |
          posthawk send emails/release-notes.tsx \
            --to changelog@acme.io \
            --from release-bot@acme.dev \
            --subject "Acme ${{ github.ref_name }} shipped" \
            --props "{\"version\":\"${{ github.ref_name }}\"}"
SDKesbuild + React Email

The CLI compiles your .tsx file at runtime using esbuild, then dynamic-imports the result to render with @react-email/render. Compiled output is cached in node_modules/.posthawk-cache/ so subsequent runs start faster. React and @react-email/* are kept external during compilation so they resolve from your project's own node_modules — meaning you always get the exact same React Email version your templates were authored against.

Example

bash
# What the CLI does when you run 'posthawk send welcome.tsx':
#
#   1. esbuild bundles welcome.tsx → ESM with react/@react-email/*
#      left as external imports
#   2. Writes the output to node_modules/.posthawk-cache/<hash>.mjs
#   3. Dynamic-imports that file with a cache-busting ?t=timestamp
#   4. Pulls the default export as the component
#   5. Calls render() from @react-email/render to get HTML + text
#   6. Sends the rendered payload via the SDK
#
# First compile: ~500ms cold. Subsequent compiles: ~200ms warm.