Recipe

Weekly newsletter

List-based campaign. One send to many recipients, with one-click unsubscribe, send-time optimisation, and bulk-sender header compliance baked in.

Pattern

  1. Collect opt-in subscribers in your app DB (with a timestamp + an explicit consent flag)
  2. Sync subscribers to a SendBolt list (via POST /api/v1/contacts/import or the bulk-paste UI)
  3. Build the template once at /dashboard/templates/new
  4. Create a campaign via POST /api/v1/campaigns with list_id + template_id
  5. Schedule with POST /api/v1/campaigns/{id}/schedule — optionally per-recipient send-time

Code

# 1. Make sure your contacts are in SendBolt
curl -X POST "$API/api/v1/contacts/import" \
  -H "Authorization: Bearer $KEY" \
  -F "file=@subscribers.csv" \
  -F "list_id=newsletter-weekly"

# 2. Create the campaign
CAMPAIGN=$(curl -s -X POST "$API/api/v1/campaigns" \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Weekly digest 2026-W19",
    "template_id": "tpl_xxx",
    "list_id": "list_newsletter_weekly",
    "from_email": "weekly@acme.com",
    "from_name": "Alice from Acme"
  }' | jq -r .id)

# 3. Schedule for tomorrow 9am-recipient-local
curl -X POST "$API/api/v1/campaigns/$CAMPAIGN/schedule" \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "send_at": "2026-05-14T03:30:00Z",
    "send_time_optimization_enabled": true
  }'

Bulk-sender compliance (Gmail Feb 2024)

Gmail requires senders of > 5,000 messages/day to:

  • SPF + DKIM + DMARC aligned (handled automatically — see DNS)
  • One-click List-Unsubscribe header (RFC 8058) — SendBolt adds this on every campaign send
  • Visible unsubscribe link in the body — your template should include {{ unsubscribe_url }} at the bottom; the engine replaces it with a tenant-scoped token URL
  • Complaint rate < 0.3% rolling (0.1% is "spam-folder zone") — SendBolt auto-pauses at 0.1% to keep you safe

All four are handled platform-side. You just need to ship a real unsubscribe footer in your template (use the variable, don't fake it).

Per-recipient send-time (W132-A)

When you pass send_time_optimization_enabled: true to /campaigns/{id}/schedule, SendBolt queries each recipient's past open history and defers their copy of the send to their best-engagement hour. A subscriber who always opens at 7am local time gets it then; one who opens at 9pm gets it then.

Recipients with < 5 historical opens fall back to the tenant'sdefault_send_hour_utc setting (or 14:00 UTC if unset).

Pre-send quality check

Before launching a 50k blast, run the subject + body through POST /api/v1/send-quality/preview to combine the spam-score predictor + bounce-risk into one gauge. Target ≥ 8.

curl -X POST "$API/api/v1/send-quality/preview" \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "Your Acme weekly digest",
    "body_text": "Hi {{first_name}}, this week we shipped …",
    "body_html": "<p>Hi {{first_name}},</p>…",
    "from_domain": "acme.com",
    "has_list_unsub": true
  }'

Common pitfalls

  • Don't skip warmup — sending 50k on a 14-day-old domain torches it. See warm-up
  • Don't mix transactional and marketing on one domain — split into tx.acme.com + news.acme.com sub-domains
  • Don't buy lists — purchased lists are 30-60% bounce; your domain dies before the second send
  • Honour unsubscribe within 10 business days — required by CAN-SPAM. SendBolt does this automatically; just don't override

Monitoring