Skip to content
Splashify Pro
Docs

Email marketing

The email command mirrors the entire email marketing surface across the app — /email, /settings/email-domain, /email/templates, /email/audience, and /email/campaigns. From the terminal you can manage authenticated sender domains (DKIM/SPF/DMARC), template content, audience contacts and segments, and end-to-end campaigns including scheduling, sending, and cancellation.

Backed by /api/v1/app/email/*. Every call uses your stored oc_live_ token.

Quick start

bash
# 1. Verify a sender domain
splashify email domain add example.com
splashify email domain verify example.com           # checks DNS records
splashify email domains                              # see all + status

# 2. Build a template
splashify email template create \
  --name "Spring promo" \
  --subject "20% off this week" \
  --html-file ./spring-promo.html

# 3. Stage an audience
splashify email audience contact add --email [email protected] --name "Alice"
splashify email audience segment create --name "Active subscribers" \
  --filters '{"conditions":[{"field":"is_subscribed","operator":"equals","value":true}],"logic":"and"}'

# 4. Send a campaign
splashify email campaign create \
  --name "Spring launch" \
  --template <template_id> \
  --from "[email protected]" \
  --segment <segment_id>
splashify email campaign send <campaign_id>

Command tree

text
email
├── stats / dashboard            global metrics
├── domains                      list authenticated sender domains
├── domain
│   ├── add <domain>             create + return DNS records to publish
│   ├── verify <domain>          re-check DNS (DKIM/SPF/DMARC/Return-Path)
│   └── delete <domain>          remove a domain
├── templates                    list templates
├── template
│   ├── <template_id>            show one
│   ├── create                   POST a new template
│   ├── update <template_id>     PUT changes (RMW)
│   ├── delete <template_id>     remove
│   ├── preview <template_id>    render preview (HTML + plain text)
│   └── stats <template_id>      usage counts
├── audience
│   ├── contacts                 list audience contacts
│   ├── contact
│   │   ├── add                  add a contact
│   │   ├── update <contact_id>  edit
│   │   └── delete <contact_id>  remove
│   ├── segments                 list audience segments
│   └── segment
│       ├── create               new segment
│       ├── update <id>          edit
│       ├── delete <id>          remove
│       ├── add-contacts <id>    bulk-add contacts to a segment
│       └── remove-contacts <id> bulk-remove
└── campaigns                    list campaigns
    └── campaign
        ├── <campaign_id>        show one
        ├── create               draft a new campaign
        ├── send <id>            send immediately
        └── cancel <id>          cancel a scheduled / running campaign

Domain authentication

Email deliverability hinges on SPF/DKIM/DMARC alignment. Both providers (Meta and the partner backend) refuse to send from unverified domains.

bash
# Add a domain — backend returns DKIM CNAMEs + SPF/DMARC TXT records to publish
splashify email domain add example.com

# After publishing the DNS records, verify
splashify email domain verify example.com

# Re-list with verification status
splashify email domains | jq '.domains[] | {domain, dkim_verified, spf_verified, dmarc_verified}'

Verification is idempotent — re-run after each DNS edit; the backend re-resolves each record and updates the row.

Templates

bash
# Inline HTML
splashify email template create \
  --name "Welcome" --subject "Welcome to our store" \
  --html "<h1>Hi {{first_name}}</h1><p>…</p>"

# From a file
splashify email template create \
  --name "Spring promo" --subject "20% off" --html-file ./promo.html

# Update (RMW — backend's PUT replaces every column)
splashify email template update <template_id> --subject "New subject only"

# Render preview (handy for QA before sending)
splashify email template preview <template_id>

Variables. Use {{first_name}}, {{email}}, or any contact attribute as a placeholder. The backend renders them per recipient at send time.

Audience

The audience surface is distinct from the messaging surface — these are email-only contacts and segments, scoped to your domain.

bash
# Contacts
splashify email audience contacts                       # list
splashify email audience contact add --email [email protected] --name "Alice"
splashify email audience contact update <contact_id> --name "Alice Smith"
splashify email audience contact delete <contact_id>

# Segments (filter DSL same shape as messaging segments)
splashify email audience segments
splashify email audience segment create \
  --name "Active subscribers" \
  --filters '{"conditions":[{"field":"is_subscribed","operator":"equals","value":true}],"logic":"and"}'
splashify email audience segment update <id> --name "Refreshed"
splashify email audience segment delete <id>

# Bulk membership
splashify email audience segment add-contacts <id> \
  --contact-ids c1,c2,c3
splashify email audience segment remove-contacts <id> \
  --contact-ids c1

Campaigns

bash
# Draft
splashify email campaign create \
  --name "Spring launch" \
  --template <template_id> \
  --from "[email protected]" \
  --segment <segment_id> \
  [--schedule 2026-06-01T10:00:00Z]

# Lifecycle
splashify email campaigns                            # list
splashify email campaign <campaign_id>               # detail
splashify email campaign send <campaign_id>          # send now (skips/overrides schedule)
splashify email campaign cancel <campaign_id>       # cancel scheduled or in-flight

Same preflight as broadcasts — campaigns refuse if no active plan / trial or wallet balance is insufficient for the recipient count × per-email rate.

Stats and reporting

bash
splashify email stats                                # global dashboard
splashify email template stats <template_id>         # opens / clicks / bounces per template
splashify email campaign <campaign_id> | jq '.stats' # per-campaign delivery

Common workflows

Verify every domain in one go

bash
splashify email domains | jq -r '.domains[].domain' | \
  xargs -I{} splashify email domain verify {}

Bulk-import an audience from CSV

bash
# csv: email,name
while IFS=, read -r email name; do
  splashify email audience contact add --email "$email" --name "$name"
done < audience.csv

Wait for a scheduled campaign to finish

bash
CID=<campaign_id>
while : ; do
  STATUS=$(splashify email campaign "$CID" | jq -r '.campaign.status // .status')
  echo "$(date -u +%H:%M:%S)  $STATUS"
  [ "$STATUS" = "completed" ] || [ "$STATUS" = "cancelled" ] && break
  sleep 30
done

Find templates with low open rates

bash
splashify email templates | jq -r '.templates[].template_id' | \
  while read tid; do
    splashify email template stats "$tid" | \
      jq --arg t "$tid" '{template_id: $t, opens: .stats.opens, sends: .stats.sends, open_rate: (.stats.open_rate // 0)}'
  done | jq -s 'sort_by(.open_rate)'

Re-send a campaign to a fresh segment

bash
# Clone a campaign by copying its config to a new one
OLD=$(splashify email campaign <old_id>)
TPL=$(echo "$OLD" | jq -r '.campaign.template_id')
FROM=$(echo "$OLD" | jq -r '.campaign.from_email')
splashify email campaign create --name "Re-run May" \
  --template "$TPL" --from "$FROM" --segment <new_segment_id>

Troubleshooting

"Domain not verified" on campaign create — --from references a domain that hasn't passed all four DNS checks (DKIM, SPF, DMARC, Return-Path). Run splashify email domain verify <domain> after DNS propagates. dig CNAME splashifypro._domainkey.<domain> confirms DKIM locally.

"insufficient_balance" on campaign send — wallet won't cover the campaign cost (recipients × per-email rate). The error includes the shortfall.

Preview shows raw {{first_name}} — variables only resolve at send time against a real contact. The preview endpoint uses sample values when available, but missing fields print as-is.

Audience contact import is slow — the CLI sends one POST per row. For thousands of contacts, batch via the segment add-contacts endpoint: upload contacts in parallel, collect their IDs, then call add-contacts once with the full list.

See also