Email Marketing
Broadcasts

Broadcasts

Broadcasts are one-time mass emails sent to a targeted audience. Use them for newsletters, announcements, promotions, or any communication that should go out to a group of contacts at once.

Broadcast Lifecycle

StatusDescription
draftBeing composed. Nothing is sent.
scheduledLocked in with a future send date. The sweeper will pick it up when the time arrives.
sendingThe user clicked "Send Now". The sweeper will process it on its next run.
processingCurrently being sent by the sweeper (locked to prevent double-sends).
sentSuccessfully dispatched. The sent_count and sent_at fields are populated.
failedA fatal error occurred during processing. The error_message field contains diagnostics.

Audience Targeting

Broadcasts support flexible audience selection using a combination of include and exclude filters:

Include Filters

  • Target Tags — Send to all contacts who have any of the selected tags.
  • Target Events — Send to all contacts registered for any of the selected events.
  • Target All Contacts — Send to every subscribed contact in the workspace (ignores tag/event filters).

Exclude Filters

  • Exclude Tags — Remove contacts who have any of the excluded tags.
  • Exclude Events — Remove contacts registered for any of the excluded events.

Audience Calculation Pipeline

The sweeper calculates the final recipient list in this order:

  1. Build the base audience from include filters (tags, events, or all contacts)
  2. Remove excluded contacts based on exclude tags and events
  3. Remove unsubscribed contacts (is_subscribed = false or unsubscribed_at is set)
  4. Remove suppressed contacts (any active contact_suppression record)
  5. Remove duplicates (a contact matching multiple include filters is only sent one email)

Suppressed contacts are still logged in the email_sends table with status suppressed for transparency and reporting.

Sending Process

The broadcast sweeper runs as a CRON job and:

  1. Finds ready broadcasts — either sending (user clicked "Send Now") or scheduled with scheduled_for ≤ NOW().
  2. Locks — Atomically sets status to processing to prevent double-sends from concurrent workers.
  3. Resolves the sender identity — Uses the broadcast's configured sender, or falls back to the workspace default.
  4. Calculates the audience — Applies all include/exclude filters and suppression checks.
  5. Personalizes — Resolves merge fields for each recipient's email.
  6. Sends in batches — Dispatches via the Resend Batch API in chunks of 100 emails.
  7. Logs — Records each send in email_sends with idempotent upserts (safe for retries).
  8. Finalizes — Updates the broadcast status to sent with sent_count and sent_at.

Error Handling

  • If a batch of 100 fails, the sweeper continues to the next batch rather than aborting the entire broadcast.
  • If a fatal error occurs after locking, the broadcast is marked as failed with a diagnostic error_message so it doesn't get stuck in processing forever.

Scheduling

To schedule a broadcast for future delivery:

  1. Compose your email and select your audience
  2. Set the Scheduled For date and time
  3. Click Schedule

The broadcast status changes to scheduled. The sweeper will automatically pick it up and send it when the scheduled time arrives. You can cancel a scheduled broadcast at any time before it's processed.

Email Tracking

Every broadcast email is individually tracked in the email_sends table. Status progression:

sent → delivered → opened → clicked

These status updates are received via Resend webhooks and stored automatically.