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.

Email Categories

Every broadcast has a category that controls its compliance behavior:

CategoryConsent GateUnsubscribe HeaderTracking
Marketing (default)is_subscribed must be true✅ RequiredConfigurable (on by default)
Transactional❌ Bypasses consent❌ OmittedAlways off

The category is set in the broadcast composer and defaults to marketing. Transactional broadcasts should only be used for emails that recipients expect regardless of their marketing preferences.

See Email Marketing → Email Categories for the full category specification.

Tracking Toggle

Marketing broadcasts have tracking enabled by default. You can disable tracking by enabling the "Optimize for Deliverability" toggle in the broadcast composer. This removes all tracking artifacts (link wrapping and open pixel) from the email while preserving unsubscribe headers and consent enforcement.

For transactional broadcasts, tracking is always off — the toggle is not shown.

See Tracking & Analytics for details on how the tracking engine works.

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 (unsubscribed_at is set)
  4. Remove suppressed contacts (any active contact_suppression record)
  5. Apply marketing consent gate — For category = 'marketing' broadcasts, contacts with is_subscribed = false are removed from the audience. The number of contacts filtered by this check is tracked on the broadcast row as skipped_unsubscribed. Transactional broadcasts bypass this check entirely.
  6. 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. Pre-inserts — Creates email_sends rows with status = 'pending' before dispatching. This provides the email_send_id needed by the link wrapper to generate tracking URLs.
  7. Sends in batches — Dispatches via the Resend Batch API in chunks of 100 emails. If tracking is enabled, links are wrapped and an open pixel is injected for each recipient.
  8. Updates — On success, updates pre-inserted rows to status = 'sent' with Resend message IDs. On failure, updates to status = 'failed'.
  9. Finalizes — Updates the broadcast status to sent with sent_count and sent_at. A notification is created with the recipient count and number of suppressed contacts.

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. A notification is created with the error details and links to the broadcast and sender settings.

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:

pending → sent → delivered → opened → clicked

Click and open events are recorded by Gordon CRM's first-party tracking engine via branded tracking URLs on your domain (e.g., links.yourdomain.com). Delivery, bounce, and complaint events are received via Resend webhooks.