Skip to content

Latest commit

 

History

History
398 lines (298 loc) · 10.7 KB

File metadata and controls

398 lines (298 loc) · 10.7 KB

mailchimp-cli

A comprehensive Rust CLI for MailChimp marketing automation, designed for scripting and AI agent integration. JSON-first output with TSV fallback for human readability.

Features

  • Full campaign lifecycle — create, content, test, schedule, send, and report
  • Audience management — lists, members, tags, segments, batch operations
  • Template browsing — list templates and export HTML
  • Campaign analytics — opens, clicks, growth reports
  • OAuth2 authentication — browser-based login with multi-account support
  • Secure token storage — system keyring (macOS Keychain, Linux Secret Service) with file fallback
  • Structured output — JSON/NDJSON (default) and TSV (--plain) for easy parsing
  • Shell completions — Bash, Zsh, Fish, PowerShell
  • AI agent skill — ships with a Claude Code / Codex skill for natural language access

Installation

Requires Rust (edition 2024).

Quick install

The install script builds the binary, copies it to ~/.local/bin, and installs the AI agent skill to any detected agents (Claude Code, Codex):

./install.sh

Manual install

# Build
cargo build --release

# Install binary
mkdir -p ~/.local/bin
cp ./target/release/mailchimp ~/.local/bin/mailchimp

# Install Claude Code skill (optional)
mkdir -p ~/.claude/skills/mailchimp
ln -sf "$(pwd)/skills/mailchimp/SKILL.md" ~/.claude/skills/mailchimp/SKILL.md
ln -sfn "$(pwd)/skills/mailchimp/docs" ~/.claude/skills/mailchimp/docs

Make sure ~/.local/bin is in your PATH:

export PATH="$HOME/.local/bin:$PATH"

Quick Start

# Authenticate (opens browser for OAuth)
mailchimp auth login

# Or use a token directly
mailchimp --token mc-XXXXXXXX audiences list

# List your audiences
mailchimp audiences list

# List subscribers
mailchimp members list <audience_id>

# Create and send a campaign
mailchimp campaigns create --audience <aud_id> --subject "Newsletter"
mailchimp campaigns content <campaign_id> --html-file email.html
mailchimp campaigns test <campaign_id> "you@example.com"
mailchimp campaigns send <campaign_id>

Commands

Auth

mailchimp auth login                     # OAuth browser flow
mailchimp auth logout                    # Remove credentials
mailchimp auth accounts                  # List authenticated accounts
mailchimp auth switch us19               # Switch default account
mailchimp auth status                    # Current auth state

Audiences (alias: a)

mailchimp audiences list                 # All audiences
mailchimp audiences list --sort-members  # Sort by subscriber count
mailchimp audiences info <id>            # Audience details
mailchimp audiences info '#My Audience'  # Lookup by name

Members (alias: m)

mailchimp members list <aud> --status subscribed --limit 100
mailchimp members add <aud> user@example.com --merge-fields '{"FNAME":"Jo"}'
mailchimp members update <aud> user@example.com --status unsubscribed
mailchimp members remove <aud> user@example.com --force
mailchimp members unsubscribe <aud> user@example.com
mailchimp members search "john" --audience <aud>

Tags (alias: t)

mailchimp tags list <aud>                        # All tags with counts
mailchimp tags add <aud> user@example.com "vip,beta"
mailchimp tags remove <aud> user@example.com "beta"
mailchimp tags members <aud> "vip"               # Members with tag

Segments (alias: seg)

mailchimp segments list <aud>
mailchimp segments info <aud> <segment_id>
mailchimp segments members <aud> <segment_id>
mailchimp segments create <aud> --name "Active" --conditions '<json>'
mailchimp segments update <aud> <seg_id> --name "New Name"
mailchimp segments delete <aud> <seg_id> --force

Campaigns (alias: c)

mailchimp campaigns list --status sent --sort-sent
mailchimp campaigns info <id>
mailchimp campaigns create --audience <aud> --subject "Newsletter"
mailchimp campaigns content <id> --html-file email.html
mailchimp campaigns test <id> "test@example.com"
mailchimp campaigns schedule <id> --time "tomorrow at 10am"
mailchimp campaigns unschedule <id>
mailchimp campaigns send <id> --force
mailchimp campaigns delete <id> --force

Templates

mailchimp templates list --type user --sort-recent
mailchimp templates info <id>
mailchimp templates info <id> --html-only          # Raw HTML to stdout
mailchimp templates info <id> --output tpl.html    # Save HTML to file

Reports (alias: r)

mailchimp reports campaign <id>                    # Full campaign stats
mailchimp reports clicks <id>                      # Click details
mailchimp reports opens <id> --limit 100           # Open details
mailchimp reports growth <aud> --period month --months 12

Shell Completions

# Add to ~/.bashrc or ~/.zshrc
eval "$(mailchimp completions bash)"
eval "$(mailchimp completions zsh)"

# Or save to file
mailchimp completions fish > ~/.config/fish/completions/mailchimp.fish

Output Modes

By default, output is JSON (single objects) or NDJSON (one JSON object per line for lists). Use --plain for TSV with a header row:

# JSON (default)
mailchimp audiences list

# TSV output
mailchimp audiences list --plain

Common patterns

# Count subscribers
mailchimp members list <aud> --plain | tail -n +2 | wc -l

# Extract a field with jq
mailchimp audiences info <id> | jq '.member_count'

# Export subscriber emails
mailchimp members list <aud> --plain | cut -f1 | tail -n +2

Global Flags

Flag Env Var Description
--plain TSV output instead of JSON
-a, --account <prefix> MAILCHIMP_ACCOUNT Use specific account (server prefix, e.g. us19)
--token <token> MAILCHIMP_TOKEN API token (bypasses keyring)
-v, --verbose Verbose logging to stderr
--help Show help
--version Show version

Environment Variables

Variable Description
MAILCHIMP_TOKEN Default API token (overrides keyring)
MAILCHIMP_ACCOUNT Default account (server prefix)
MAILCHIMP_TOKEN_STORE_PATH Use file-based token storage instead of keyring
MAILCHIMP_API_BASE_URL Override API base URL (for testing)
MAILCHIMP_CLIENT_ID OAuth app client ID
MAILCHIMP_CLIENT_SECRET OAuth app client secret

Exit Codes

Code Meaning
0 Success
1 General error
2 Authentication required
3 Invalid arguments
4 API error
5 Rate limited
6 Network error

Destructive Operations

Commands that delete or send require confirmation. Use --force to skip the prompt:

  • members remove — permanent deletion
  • segments delete — removes segment
  • campaigns send — sends to all recipients
  • campaigns delete — removes campaign

Multi-Account Usage

# List all authenticated accounts
mailchimp auth accounts

# Run a command against a specific account
mailchimp -a us19 audiences list

# Set the default account
mailchimp auth switch us19

Guides

Batch Operations

Batch commands process multiple subscribers from CSV files, making per-row API calls with immediate feedback.

CSV format

email,FNAME,LNAME,status,tags
alice@example.com,Alice,Smith,subscribed,"vip,beta"
bob@example.com,Bob,Jones,pending,
Column Required Notes
email Yes Valid email address
FNAME No First name merge field
LNAME No Last name merge field
status No subscribed (default), pending, unsubscribed
tags No Comma-separated, quoted if they contain commas

Commands

# Batch add subscribers from CSV
mailchimp members batch-add <aud> --file subscribers.csv

# Batch update existing subscribers
mailchimp members batch-update <aud> --file updates.csv

# Bulk tag from email list (one email per line)
mailchimp members batch-tag <aud> --emails emails.txt --tags "vip,premium"

Exit codes for batch commands: 0 = all succeeded, 1 = some row errors (partial success), 4 = fatal error (aborted).

Campaign Workflows

Full lifecycle for creating and sending campaigns:

# 1. Create draft
CAMPAIGN_ID=$(mailchimp campaigns create \
  --audience abc123 \
  --subject "March Newsletter" \
  --from-name "Acme Inc" \
  --reply-to news@acme.com \
  --preview-text "What's new this month..." \
  | jq -r '.id')

# 2. Set content from HTML file
mailchimp campaigns content "$CAMPAIGN_ID" --html-file ./newsletter.html

# 3. Send test
mailchimp campaigns test "$CAMPAIGN_ID" "team@acme.com"

# 4. Schedule for later
mailchimp campaigns schedule "$CAMPAIGN_ID" --time "tomorrow at 10am"

# 5. Check results after sending
mailchimp reports campaign "$CAMPAIGN_ID"

Content sources (exactly one required):

Flag Description
--html-file PATH HTML from file (most common)
--html TEXT Inline HTML string
--plain-text TEXT Plain text content
--template-id ID Use MailChimp template (optional: --template-sections JSON)

Schedule accepts ISO 8601 (2024-12-01T14:00:00Z), datetime (2024-12-01 14:00), or natural language (tomorrow at 10am).

Segments and Conditions

Create segments to target subscriber subsets:

# Active subscribers who signed up this year
mailchimp segments create <aud> \
  --name "2024 Signups" \
  --conditions '{
    "match": "all",
    "conditions": [
      {
        "condition_type": "DateMerge",
        "field": "timestamp_opt",
        "op": "greater",
        "value": "2024-01-01"
      }
    ]
  }'

Condition JSON structure:

{
  "match": "all | any",
  "conditions": [
    {
      "condition_type": "TextMerge | DateMerge | Aim | MemberRating | StaticSegment | ...",
      "field": "merge0 | merge1 | timestamp_opt | aim | member_rating | ...",
      "op": "is | not | contains | greater | less | open | click | ...",
      "value": "..."
    }
  ]
}

Common condition types:

Type Field Operations
TextMerge merge0 (email), merge1 (FNAME), merge2 (LNAME) is, not, contains, starts, ends, blank
DateMerge timestamp_opt is, not, greater, less, blank
Aim aim open, click, sent, noopen, noclick
MemberRating member_rating greater, less, is
StaticSegment static_segment static_is, static_not

Development

# Build
cargo build

# Run tests
cargo test

# Lint (must pass clean)
cargo clippy --all-targets --all-features -- -D warnings

# Format check
cargo fmt --check

# Run locally
cargo run -- audiences list --token TOKEN

All three checks (test, clippy, fmt) must pass before submitting changes.

License

MIT