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
- Collect opt-in subscribers in your app DB (with a timestamp + an explicit consent flag)
- Sync subscribers to a SendBolt list (via
POST /api/v1/contacts/importor the bulk-paste UI) - Build the template once at /dashboard/templates/new
- Create a campaign via
POST /api/v1/campaignswithlist_id+template_id - 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.comsub-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
- /dashboard/campaigns — per-campaign opens / clicks / bounces / unsubs
- /dashboard/analytics — funnel + sparklines + top-domain breakdown
- Bounces & suppressions — what to do when delivery drops