Skip to content

Sequences (Drip Campaigns) Feature

Overview

Sequences (/sequences) is a multi-channel drip-campaign builder for automated, time-delayed outreach across Email, WhatsApp Lite (free-form dynamic messages), WhatsApp Cloud (Meta-approved templates), and SMS. It handles contact enrollment, per-step delays, sending windows, daily send caps, opt-out/unsubscribe compliance, reply-pause, deal-based exit conditions, and analytics — all scoped to your organization.

Drip sequences with their steps and enrolment counts Drip sequences with their steps and enrolment counts Drip sequences with their steps and enrolment counts.

Contents:

  1. Sequence Builder
  2. Contact Enrollment
  3. How sending works
  4. Channels & Sending
  5. Compliance & Unsubscribe
  6. Analytics & Reporting
  7. Test Sends
  8. How-To Guide · Use Cases · Test Cases

1. Sequence Builder

Sequence: - Name + description - channels (JSONB flags): email, sms, whatsapp_lite, whatsapp_cloud - Status: draft, active, paused, archived — only active sequences are processed by the executor - Optional sending window: sending_window_start / sending_window_end (HH:MM) resolved in sending_window_timezone → org settings.timezone → UTC - Optional exit conditions: exit_on_deal_created, exit_on_deal_stages[]

Steps (in order): - channel — email | sms | whatsapp_lite | whatsapp_cloud (legacy whatsapp treated as Lite) - delay_minutes — wait after the previous step before this step fires - Message body (required), subject (email), and which connected account sends it - WhatsApp Cloud: template_name, template_language, and optional template_variables[] (ordered map for placeholder resolution)

Variable substitution (message bodies / subject) is replaced at send time from the contact. The builder inserts the single-brace form; the double-brace form ({{First Name}}) is accepted too, in any case and with spaces, underscores or hyphens ({{ first_name }}, {{firstName}}):

Token Value
{first_name} contact first name
{last_name} contact last name
{name} full name
{email} primary email (emails[0])
{phone} primary phone (phones[0])

Only the tokens above are replaced; anything else (unknown names, CSS braces in an HTML email) is left exactly as written. A token whose contact field is empty renders as empty text.

WhatsApp Cloud templates use Meta's positional {{1}}, {{2}} placeholders instead. Each placeholder is filled from the step's template_variables map when configured (a token like {first_name} is resolved from the contact); otherwise it falls back to the contact's name so the send still succeeds.


2. Contact Enrollment

Paths: - Single contact — SequenceEnrollmentMenu (contact profile / dropdown toggle) - Bulk — BulkSequenceEnrollmentMenu (multi-select on the contacts list) - From a deal — DealSequenceEnrollmentMenu (enrolls the deal's linked contacts) - By tag — enrollByTag (all contacts carrying the selected tag) - Test send — TestSequenceDialog (runs the steps immediately against one contact; see §7)

What is written to sequence_enrollments: status='active', current_step_index=0, enrolled_by, and next_step_at = now + firstStep.delay_minutes. A UNIQUE(sequence_id, contact_id) constraint guarantees one enrollment per contact per sequence.

Entry validation (bulk / dialog / tag paths): - Contacts with opt_in_status = false are excluded. - Contacts with no email and no phone are excluded (nothing could ever be sent). - Contacts already enrolled are left untouched — re-enrolling never restarts, resurrects, or resets a completed, removed, unsubscribed, bounced, or in-progress contact. The UI reports how many were newly enrolled vs skipped.

Enrollment status lifecycle:

Status Meaning Set by
active receiving steps enrollment
completed all steps sent executor (no more steps)
paused contact replied → held reply trigger
removed manually removed UI (removeEnrollments / toggle)
failed step failed 3× or contact permanently unreachable (no email/phone) executor
exited deal exit condition met deal-exit trigger + executor
bounced hard-bounced email address executor
unsubscribed opted out / used unsubscribe link unsubscribe fn + executor

active is the only status the executor processes; every other status stops sending.


3. How sending works

Sequences are processed automatically every few minutes. Each run:

  1. Dequeue — picks up to 50 active enrollments whose next step is due.
  2. Claim — each enrollment is claimed atomically, so overlapping runs can never double-send.
  3. Guards (in order), each reschedules or stops without sending:
  4. Parent sequence still active? else skip.
  5. Exit conditions — if the contact has a deal (created / in an exit stage), enrollment → exited.
  6. Sending window — if outside the window (in the resolved timezone), next_step_at is moved to the next window open.
  7. WhatsApp Lite pacing — a random 10–45 minute gap is enforced between consecutive sends per WhatsApp Lite account, guaranteed even across runs. When an account is still cooling down, the enrollment is deferred to the reserved time; only one send per account is released per window, so messages are never blasted.
  8. Send — dispatch by channel (see §4), then record the result (sent | failed | skipped) with a per-step executed_at timestamp and the rendered content.
  9. Progress the enrollment based on the result:
  10. sent → advance to the next step (or completed if last).
  11. failed → retry with exponential backoff (5 → 10 → 20 min); after 3 failures → failed.
  12. skipped (retry) — e.g. a daily send cap was hit → reschedule the same step to the next day. The message is not dropped or skipped past.
  13. skipped (terminal) — opt-out, unsubscribed, hard-bounced, or no email/phone → stop the enrollment with the matching status (unsubscribed / bounced / failed).
  14. skipped (advance) — recoverable config gaps (e.g. no channel account / no template on this step) → move to the next step.

Every outbound send is also mirrored to the inbox as a message from the sequence.


4. Channels & Sending

Channel Send path Notes
Email SMTP or AWS SES Auto-selects provider from the step's channel account. Injects a CAN-SPAM unsubscribe footer. Hard-bounce detection pauses the contact's active enrollments. Daily cap per sender (SMTP default 150, SES from account config).
WhatsApp Lite Appgain Free-form text + variables. Links are removed — on save, on AI generation and again at send time — because links in WhatsApp Lite outreach trigger spam filters. The step editor says so, and warns as soon as a link is typed. Need a clickable link? Use an email step or a WhatsApp Cloud template. Optional video or audio attachment per step (see below). Daily cap 200/account/day. Enforced random 10–45 min gap between sends per account (§3).
WhatsApp Cloud Meta Cloud API Requires a Meta-approved template_name; components/parameters built from the template definition + template_variables.
SMS Appgain notify scheduler Text + variables; uses org or channel Appgain credentials.

Daily send caps are enforced per account per day. If a send is reserved against the cap but then fails, the reserved slot is returned, so failures and retries don't leak quota.

Opt-out is checked on every channel at send time; email additionally checks the unsubscribe-token table and the bounce-suppression list.


5. Compliance & Unsubscribe

  • Unsubscribe link is appended to every sequence email, pointing at /sequence-unsubscribe?token=….
  • Tokens are issued one per email address per organization. Each is a 256-bit random opaque value — unguessable; looked up server-side when the link is opened.
  • On unsubscribe the function: marks the token unsubscribed_at, sets the contact opt_in_status = false, sets that contact's active enrollments to unsubscribed, and logs an activity entry on the contact.
  • Global opt-out: because opt_in_status is honored by all channels, unsubscribing stops Email, WhatsApp, and SMS for that contact — not just the current sequence.
  • Unsubscribes are not silently reversed. An internal opt-in flip / import does not auto-clear a prior unsubscribe; re-subscription requires an explicit, deliberate action.

6. Analytics & Reporting

Backed by the send log (statuses sent / failed / skipped), enrollment states, and the bounce-suppression list. The dashboard reads a 30-day window by default, paginated past the 1000-row page size.

Headline metrics: - Messages Sent = executions with status sent only (skipped/failed excluded). - Success Rate = sent / (sent + failed) — over delivery attempts, not skips. - Unsubscribes — count + rate over enrollments in the range.

Breakdowns: - Channel performance — sent / failed / rate per channel (rate over attempts). - Enrollment status — active, completed, paused, removed, unsubscribed, bounced, exited (goal met), failed (all terminal states are surfaced so the breakdown reflects reality). - Per-step — executions, successes, failures, skips, and grouped error reasons per step. - Deliverability — per-recipient email failures, with bounces reclassified from the suppression list. - Recent activity — latest executions with rendered subject/content.

Reply-pause rows (Auto-paused: contact replied) are logged as skipped but represent a good outcome, so they are excluded from all error/deliverability aggregations.

Known reporting gaps (roadmap): email opens/clicks are tracked in email_tracking_events but not yet joined into sequence reports; reply-rate and a true enrolled→step cohort funnel are not yet surfaced.


7. Test Sends

TestSequenceDialog invokes the executor in test mode against a single contact. It: - Verifies the caller's organization — the JWT must belong to the organization_id, and all lookups are org-scoped (no cross-tenant sends). - Runs every step immediately (skips daily-cap accounting). The dialog sends one step per request, shows each result as it lands ("Running step 4 of 36…"), and waits ~3 s after a WhatsApp Lite step so consecutive messages arrive in order. If a step's request itself fails, the run stops there and keeps the results so far; closing the dialog stops the run. - Results are shown in the dialog only — a test has no enrollment, so nothing is written to the send log or the sequence report. - Sends real messages to the target contact (it is a live test, not a dry run) — still honoring opt-out, unsubscribe, and bounce checks.


How-To Guide

All tasks start at Sidebar → Sequences (/sequences). The page has two tabs: Sequences (list + builder) and Analytics.

A. Create a sequence

  1. Click Create Sequence (top-right).
  2. Enter a Sequence Name (required) and an optional Description.
  3. (Optional) configure a Sending Window and Exit Conditions — see B and C.
  4. Under Steps, click one of the channel buttons to add a step: Email, SMS, WA Lite, or WA Cloud. Add as many steps as you need; drag the handle to reorder.
  5. For each step set:
  6. Delay — how long to wait after the previous step before this one fires (Immediately, 5 minutes, … 1 hour, 1 day, 1 week).
  7. Send via — the connected channel account that will send it. For an email step this can be a normal mailbox or a Bulk Email (AWS SES) sender; bulk senders show their address, for example Sales <sales@example.com> (Bulk Email (AWS SES)). Any team member can pick a bulk sender, as long as they have access to that channel (ask an admin under Settings → Team if it is missing). If you leave Send via empty, the email goes from your first connected mailbox, so choose the bulk sender explicitly when you want it. If the sender you chose is later turned off or removed, that step is skipped with a clear message instead of being sent from a different address.
  8. Subject (email only) and Message (see D for personalization). For WA Cloud, pick an approved Template instead of free text (see E).
  9. Save. The sequence is created as Draft.
  10. When ready, Activate it (see H) — the executor only processes active sequences.

The first step usually uses Immediately so enrolled contacts are picked up on the next executor tick.

B. Configure a sending window (quiet hours)

  1. In the builder, enable Sending Window.
  2. Set From / To (e.g. 09:00–17:00) and the Timezone.
  3. Steps that come due outside the window are held and automatically sent when the window next opens. Overnight windows (e.g. 20:00–06:00) are supported.

C. Configure exit conditions (stop on conversion)

  1. In the builder, open Exit Conditions.
  2. Toggle Exit when any deal is created for the contact, and/or select deal stages that should end the sequence.
  3. When a contact matches, their enrollment moves to exited and no further steps are sent. This fires both instantly (DB trigger) and as a safety check on every executor run.

D. Personalize messages with variables

Insert single-brace tokens into a subject or message body; they're replaced per contact at send time:

{first_name} · {last_name} · {name} · {email} · {phone}

Example: Hi {first_name}, thanks for your interest! Missing values render as empty (or a safe fallback), so the send never breaks.

E. Set up a WhatsApp Cloud template step

  1. Add a WA Cloud step and pick the connected WhatsApp Cloud account under Send via.
  2. Choose an approved Template (name + language) from the picker — WhatsApp Cloud does not allow free text outside the 24-hour service window.
  3. If the template has positional placeholders ({{1}}, {{2}}, …), provide an ordered variable map so each placeholder is filled correctly (a token like {first_name} is resolved from the contact). Without a map, placeholders fall back to the contact's name.

E2. Attach a video or audio file to a WhatsApp Lite step

  1. In a WA Lite step, under the message box, choose Upload video or Upload audio.
  2. Video: MP4 or 3GP, up to 15 MB (H.264 video with AAC audio). Audio: MP3, M4A, OGG, OPUS, WAV or AMR, up to 16 MB. One attachment per step; use Replace or the bin icon to change or remove it.
  3. A video carries the step's text as its caption. WhatsApp shows no text with an audio message, so for an audio step with text the text goes out first and the audio follows a second or two later. A step with an attachment and no text is fine.
  4. The file is stored in the attachments bucket (sequence-media/) and is not registered for the 4-week storage cleanup, since a sequence reuses it for as long as it runs.

Only WhatsApp Lite steps carry an attachment; the other channels do not offer one. WhatsApp Lite decides whether a file is sent as video or audio from the file's extension, so use one of the formats above.

If the audio fails to send after the text has already gone out, the step is retried with the audio only; the text is not sent twice.

F. Enroll contacts

There are four ways to enroll (all skip opted-out contacts, contacts with no email/phone, and contacts already enrolled):

  • From the sequence — on the Sequences tab, click the Enroll (person+) action, then pick contacts or a tag.
  • From the contacts list — select contacts → Enroll in Sequence → choose the sequence.
  • From a deal — use the deal's Enroll in Sequence menu to enroll the deal's linked contacts.
  • By tag — enroll everyone carrying a tag in one action.

The confirmation reports how many were newly enrolled vs skipped (already enrolled / not eligible). Re-enrolling never restarts someone who already completed, unsubscribed, bounced, or is mid-sequence.

G. Test before launching

  1. On the Sequences tab, open the sequence's Test action.
  2. Search for and pick one contact.
  3. Run it — every step executes immediately against that contact. This sends real messages (it is a live test, not a preview) and still respects opt-out/unsubscribe/bounce checks. You can only test sequences in your own organization.

H. Activate, pause, archive, delete

  • Activate / Pause — the play/pause action toggles the sequence between active and paused. Pausing holds all its enrollments (no steps sent) until reactivated.
  • Edit — change steps/settings anytime; changes apply to future sends.
  • Delete / Archive — removes it from processing.

I. Monitor performance

Open the Analytics tab (default window: last 30 days; adjustable):

  • Overview — Messages Sent (actual sends), Success Rate (sent ÷ delivery attempts), Unsubscribes.
  • Enrollment Status — active / completed / paused / removed / unsubscribed / bounced / exited (goal met) / failed.
  • Channel Performance — sent / failed / rate per channel.
  • Per-step — executions, successes, failures, skips, and grouped error reasons.
  • Deliverability — per-recipient email failures with bounces flagged.
  • Activity — the most recent executions with the rendered content.

To see who is where in a sequence, open its enrollments panel from the list.

J. Handle unsubscribes & opt-outs

  • Every sequence email includes an unsubscribe footer. When a recipient clicks it, their contact is marked opted-out, active enrollments become unsubscribed, and they're excluded from all future sends on every channel.
  • A contact replying (inbound message) auto-pauses their active enrollments so you don't message over a live conversation.
  • Honored unsubscribes are not silently reversed by imports or edits — re-subscribing requires a deliberate action.

K. Troubleshooting (why a contact didn't receive a step)

Check the Per-step / Deliverability analytics — the error_message explains each skip/failure:

Symptom Cause Resolution
Enrollment unsubscribed right away Contact opted out / unsubscribed Expected — respect the opt-out
Enrollment failed, "no phone/email" Contact missing the channel's address Add the contact's email/phone
Step skipped, "Daily … limit reached" Sender hit its daily cap It auto-retries the next day; raise the cap or add a sender
Step skipped, "No template selected" WA Cloud step without a template Edit the step and pick an approved template
Nothing sends at all Sequence is Draft/Paused, or outside the sending window Activate it / wait for the window
Enrollment bounced Email hard-bounced previously Address is suppressed; fix or remove it

Use Cases

Welcome Email Sequence

5-email onboarding series (immediate → +1d → +3d → +5d → +7d), auto-enrolled when a contact is tagged "Subscriber" via an automation.

WhatsApp Follow-Up

3 WhatsApp Lite nudges (+2h → +2d → +5d) manually enrolled after a quote is sent; replies auto-pause the sequence.

Re-Engagement Campaign

2-email win-back (We miss you, {first_name} → last-chance) bulk-enrolled on contacts tagged "Inactive 90 Days".

Post-Purchase WhatsApp Cloud

Order confirmation → shipping → delivery → feedback using Meta-approved templates, auto-enrolled when a deal closes.


Test Cases

  1. Create sequence with steps — create, add 3 steps with delays, save, confirm it appears active.
  2. Enroll contacts — enroll 5; opted-out / no-channel contacts are skipped; already-enrolled are skipped; the rest become active.
  3. Step execution — 1-step sequence, enroll, wait for the next run, confirm message sent, the send log shows sent, enrollment completed.
  4. Daily cap deferral — exceed a sender's daily cap; confirm the step is rescheduled to the next day (not dropped) and the message goes out then.
  5. Unsubscribe — click the unsubscribe link; confirm token unsubscribed_at set, contact opt_in_status=false, active enrollments become unsubscribed, and re-enrollment is skipped.
  6. Reply-pause — send an inbound message from an enrolled contact; confirm active enrollments become paused and the pause does not appear as a delivery error in analytics.
  7. WhatsApp Cloud template — select an approved template, map template_variables, enroll a valid number, confirm the template is delivered.


Document Version: 2.1.0 Last Updated: July 2026


ConnectGain — omnichannel inbox, CRM & automation for WhatsApp, Messenger, Instagram, Telegram and more. Open the app · Docs home