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:
| Category | Consent Gate | Unsubscribe Header | Tracking |
|---|---|---|---|
| Marketing (default) | ✅ is_subscribed must be true | ✅ Required | Configurable (on by default) |
| Transactional | ❌ Bypasses consent | ❌ Omitted | Always 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
| Status | Description |
|---|---|
draft | Being composed. Nothing is sent. |
scheduled | Locked in with a future send date. The sweeper will pick it up when the time arrives. |
sending | The user clicked "Send Now". The sweeper will process it on its next run. |
processing | Currently being sent by the sweeper (locked to prevent double-sends). |
sent | Successfully dispatched. The sent_count and sent_at fields are populated. |
failed | A 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:
- Build the base audience from include filters (tags, events, or all contacts)
- Remove excluded contacts based on exclude tags and events
- Remove unsubscribed contacts (
unsubscribed_atis set) - Remove suppressed contacts (any active
contact_suppressionrecord) - Apply marketing consent gate — For
category = 'marketing'broadcasts, contacts withis_subscribed = falseare removed from the audience. The number of contacts filtered by this check is tracked on the broadcast row asskipped_unsubscribed. Transactional broadcasts bypass this check entirely. - Remove duplicates (a contact matching multiple include filters is only sent one email)
Suppressed contacts are still logged in the
email_sendstable with statussuppressedfor transparency and reporting.
Sending Process
The broadcast sweeper runs as a CRON job and:
- Finds ready broadcasts — either
sending(user clicked "Send Now") orscheduledwithscheduled_for ≤ NOW(). - Locks — Atomically sets status to
processingto prevent double-sends from concurrent workers. - Resolves the sender identity — Uses the broadcast's configured sender, or falls back to the workspace default.
- Calculates the audience — Applies all include/exclude filters and suppression checks.
- Personalizes — Resolves merge fields for each recipient's email.
- Pre-inserts — Creates
email_sendsrows withstatus = 'pending'before dispatching. This provides theemail_send_idneeded by the link wrapper to generate tracking URLs. - 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.
- Updates — On success, updates pre-inserted rows to
status = 'sent'with Resend message IDs. On failure, updates tostatus = 'failed'. - Finalizes — Updates the broadcast status to
sentwithsent_countandsent_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
failedwith a diagnosticerror_messageso it doesn't get stuck inprocessingforever. A notification is created with the error details and links to the broadcast and sender settings.
Scheduling
To schedule a broadcast for future delivery:
- Compose your email and select your audience
- Set the Scheduled For date and time
- 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 → clickedClick 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.