How it is built
Architecture overview
A sales engagement platform lets a sales team run outbound sequences: a prospect is enrolled in a cadence of steps (an email today, a call task in two business days, a follow-up email after that), and the platform sends what can be automated, queues what a human must do, and stops the whole cadence the moment the prospect replies, bounces or opts out. Email goes out from each rep's own mailbox, connected by OAuth, so that replies land where the rep already works. Calls go out through a browser or softphone dialer. Every send, open, click, reply and call is written back to the team's CRM. The one idea that makes it work: a sequence is a long-lived state machine per prospect, whose next step is a timer that survives restarts, and whose every transition is driven by an event from outside (a reply, a bounce, a call result). The hard parts are not the sequences themselves but the three things around them: staying out of spam folders, matching replies to the right enrollment, and never sending the same step twice.
Parts:
- Mailbox connection — link a rep's Google or Microsoft mailbox, read new mail incrementally — OAuth 2 and OpenID Connect, Incremental sync cursors,
mime-parsing(no page yet),email-threading(no page yet) - Sequence engine — one durable state machine per enrollment, timers for the next step — Durable workflow execution, Hierarchical timing wheel,
calendar-date-arithmetic(no page yet),business-day-calendars(no page yet) - Sending pipeline — per-mailbox pacing, authenticated delivery, bounce handling, tracking —
email-delivery-smtp(no page yet), SPF, DKIM and DMARC sender authentication, Token bucket, Distributed rate limiting,bounce-processing(no page yet),open-and-click-tracking(no page yet) - Reply and call understanding — classify replies, transcribe calls — Text classification, RNN transducer (RNN-T)
- Dialer — place and record calls from the browser —
sip-signaling(no page yet),webrtc(no page yet),e164-number-parsing(no page yet) - CRM sync — keep contacts, activities and owners consistent with the system of record — Change data capture, Incremental sync cursors
- Experiments — compare subject lines and step orders — A/B testing (online controlled experiments)
- Operations — keeps sequences correct, recoverable and tested — Primary-backup replication, Point-in-time recovery, Process supervision, Graceful draining, Mutual TLS, hdr-histogram (no page yet), Deterministic simulation testing, Coverage-guided fuzzing
CRM ◄──── activities, contact changes (CDC / cursors) ────► sequence engine
│ one durable workflow per enrollment
rep UI ── enroll / pause / edit ───────────────────────────►│ state: step n, due at, status
│
timers (timing wheel) ── step due ─────┤
▼
┌──────────── per-mailbox queue ─────────────┐ ┌────────────┐
│ token bucket: sends/hour/day per mailbox │──send─►│ SMTP / API │──► prospect's MX
└────────────────────────────────────────────┘ └────────────┘
▲
mailbox sync (Gmail history / Graph delta) ── new mail ────►│ classify:
bounces (DSN), replies, out-of-office, unsubscribes │ reply | bounce | OOO | opt-out
│ → signal the workflow
dialer (browser WebRTC ◄─► SIP trunk) ── call result ──────►│
Scheduled load is smooth; inbound events are bursty and must be fast, because a reply that arrives while a follow-up is queued has to cancel it before it leaves.
How the parts fit together
Mailbox connection
The platform acts as the rep, so it asks for delegated access with OAuth 2 and OpenID Connect: authorization code with PKCE, a refresh token stored encrypted, scopes limited to send and read. Both big providers publish a way to read changes without rescanning the mailbox. Gmail's guide splits it into a full sync the first time and a partial sync with history.list from a stored historyId; if that id is outside the available history the API answers 404 and the client must do a full sync again (Gmail API sync guide). Microsoft offers delta queries for the same purpose (Graph delta query overview). That is exactly the pattern of Incremental sync cursors: one opaque cursor per mailbox, advanced only after the changes are durably processed. Push notifications only trigger a pull; the cursor stays the source of truth, so a lost notification costs latency, not data.
What comes out of the pull is raw RFC 5322 mail. mime-parsing (no page yet) turns it into headers, text parts and attachments, and email-threading (no page yet) decides which enrollment a message belongs to. Threading is the contract between this part and the sequence engine and is more fragile than it looks: the standard way is the Message-ID, In-Reply-To and References headers (RFC 5322), and the platform should store the Message-ID of every message it sends, because forwards, auto-replies and a recipient's mail rules can break the chain. A fallback on recipient address plus subject catches most of the rest; a reply that matches nothing goes to the rep's inbox instead of being dropped.
Sequence engine
Each enrollment is a Durable workflow execution: ordinary code ("send step 1, wait 2 business days, send step 2 unless the prospect replied") whose waits and side effects are logged, so a crash resumes mid-sequence instead of restarting it. Why a workflow engine and not a cron job over a table: a sequence has long waits, branches and external signals (a reply must interrupt a wait). A next_run_at column plus a polling job covers the simple case and small systems start there; the workflow model wins with many step types and interrupt conditions.
Timers are the other half. Millions of enrollments each wait for one deadline, and most deadlines are cancelled before they fire (the prospect replied), so cheap insert and cancel matter. A Hierarchical timing wheel keeps O(1) insert and cancel; the durable store holds the truth and the wheel only holds the next window in memory, reloaded after a restart.
"Two business days later at 9 a.m. in the prospect's time" is the date arithmetic that makes sequences feel human, and it is where the missing blocks sit: calendar-date-arithmetic (no page yet) for time zones and daylight-saving jumps, and business-day-calendars (no page yet) for weekends and holidays per country. Store the due time as an absolute instant, computed once from the prospect's zone and the sending window. Recomputing "daily at 9" on every poll is how a daylight-saving change sends a whole batch an hour early.
The contract with the sending pipeline is a send request with an idempotency key made of enrollment id and step number. The workflow may retry after a crash; the pipeline must send at most once for that key.
Sending pipeline
Delivery is the part that decides whether the product works at all. A prospect's mail server judges the sender before it reads the message, so three things carry the weight.
Authentication. Messages sent from a rep's own mailbox through the provider's API or SMTP submission (RFC 4954 describes authenticated submission) are signed by that provider. Messages sent from the platform's own infrastructure on a custom domain need the platform to publish records and sign mail itself: SPF, DKIM and DMARC sender authentication, specified in RFC 7208, RFC 6376 and RFC 7489. email-delivery-smtp (no page yet) is the hop-by-hop SMTP transfer itself (RFC 5321): connect, EHLO, STARTTLS, MAIL FROM, RCPT TO, DATA, and the reply codes that say accept, defer or reject.
Pacing. A mailbox that jumps from nothing to a large daily volume looks like a spammer. Each mailbox therefore has its own Token bucket: a daily cap that ramps up over weeks, an hourly cap, a random gap between sends and a send window in the prospect's time. When the platform runs many workers, the same limits must hold across all of them, which is Distributed rate limiting; the simplest correct form is to route all sends for one mailbox through one queue partition so a single consumer owns its bucket.
Feedback. bounce-processing (no page yet) reads the delivery status notifications and SMTP reply codes. A delivery status notification has a standard format (RFC 3464) and an enhanced status code whose first digit says permanent (5), transient (4) or success (2) (RFC 3463). A permanent failure removes the address from all sequences and from future imports; a transient one retries, then becomes permanent. Unsubscribes are the other feedback channel: mail should carry the List-Unsubscribe header (RFC 2369) and, for one-click, the List-Unsubscribe-Post form of RFC 8058, and a click on it removes the prospect everywhere, not only from one sequence. open-and-click-tracking (no page yet) adds a tiny image for opens and a redirect for link clicks. Opens are weak evidence, because mail clients and security gateways that fetch images automatically produce opens no human made, so most engines treat replies as the signal and show opens as a hint only.
Reply and call understanding
Not every inbound message from a prospect should stop a sequence: an out-of-office reply should only pause it, a bounce should end it with a reason, and "please remove me" must opt the person out. That is Text classification over a handful of labels (human reply, out-of-office, unsubscribe request, bounce, interested/not interested). The ladder in the block applies: rule checks on headers first (Auto-Submitted per RFC 3834, DSN content type), a linear model over n-grams when labelled replies exist, an LLM prompt only for the intent labels where a cheap model is not enough. The contract is that the classifier returns a label and a confidence, and low-confidence replies go to a human with the sequence paused rather than guessed.
Call recordings need speech recognition, and the streaming models used for live captions are RNN transducers. The output (words, timestamps, speaker turns) is a derived artefact that feeds search and summaries; it must never block saving the call record.
Dialer
Browser calling is two halves. The browser leg is webrtc (no page yet): the W3C WebRTC specification defines the peer connection, and the audio is encrypted and traverses NATs with ICE. The carrier leg is sip-signaling (no page yet): a SIP trunk (RFC 3261) connects the platform's media server to the phone network, which a SIP server or session border controller bridges to the WebRTC side. Numbers are normalised to the E.164 format by e164-number-parsing (no page yet) before dialling and before matching a caller to a contact; ITU-T E.164 is the numbering plan, and a library such as libphonenumber does the parsing and validation. The contract with the sequence engine is a call task: the engine creates it, the rep dials, and the dialer reports an outcome (connected, voicemail, no answer, wrong number) that the workflow turns into the next step.
CRM sync
The CRM is the system of record for accounts, contacts and deals; the platform owns sequences and activities. Contact and owner changes flow in, activities flow out. Change events from the CRM are consumed as a feed with a resume position (the Change data capture pattern when the platform has database access, or a vendor's change API with cursors when it does not), and activity logging goes out through the CRM's API with retries. Give each synced field one owner (loops start when both sides write it) and make activity writes idempotent by an external id.
Experiments
A/B testing applies to subject lines, first lines and step timing. The outcome (a reply) arrives days after the send, so log exposure at send time, wait for the reply window to close, and let a hash of the enrollment id pick the arm so a retry cannot flip it.
Operations
The enrollment state (step n, due time, status) is the only record of where each prospect is in a sequence, so the workflow store is replicated with Primary-backup replication: a failover must not forget that a step was already sent, or the prospect gets the same email again.
Point-in-time recovery covers the bad bulk action: a mass enrollment of the wrong list, or a bug that resets thousands of enrollments to step one. The store is restored to the minute before and the sends recorded in the mailbox sent folders are used to decide which steps really went out.
The mailbox sync workers, the sequence engine, the per-mailbox senders and the dialer gateway run under Process supervision; a sender that dies is restarted and picks up its mailbox queue from the durable state, with its pacing budget intact.
A deploy uses Graceful draining: a sender finishes the message it is handing to SMTP and records the result, then exits, so a send is neither lost nor repeated, and the per-mailbox pacing is not reset into a burst after the release.
The sequence engine, senders, mailbox sync, CRM connector and dialer gateway call each other over Mutual TLS, since they hold rep mailbox tokens and prospect contact data and only services with a certificate may enqueue a send from a rep's address.
The latencies that matter are the time from a reply arriving in a rep's mailbox to the enrollment stopping (a follow-up after a reply is the worst mistake in this product) and the time from a due step to the send; both are recorded as an hdr-histogram (no page yet) with percentiles, and the tail shows the mailbox sync that falls behind.
The stop-on-reply rule and the step timers are tested with Deterministic simulation testing: a simulated clock and network deliver replies, bounces and out-of-office mails at the same moment a step becomes due, delay mailbox syncs and crash senders between handing off a message and recording it, and the check is that no enrollment sends after a reply. Failures replay from their seed.
The mail parser, the bounce (DSN) and out-of-office detection and the CRM payload decoders read messages written by prospects and other systems, so they run under Coverage-guided fuzzing with mutated mails, keeping every input that reaches new code.
Data and control flow
One step of a sequence (email):
- The timer for enrollment E, step 2 fires; the workflow wakes and re-reads E's state. If E is no longer active (reply, bounce, opt-out), it stops here.
- It checks guard rules: suppression list, the sending window, the mailbox's remaining daily quota. If the quota is out, it reschedules to the next window.
- It renders the template with the contact's fields and writes a send request with the idempotency key (E, step 2) to the mailbox's queue.
- The mailbox's consumer takes a token from the bucket, adds tracking and the unsubscribe header, sends through the provider API or SMTP, and stores the
Message-ID. - The workflow records "sent" and schedules step 3; the activity goes to the CRM. Most of the wall-clock time is waiting (days); the active work per step is milliseconds to seconds.
One inbound reply:
- The mailbox's push notification or poll triggers a pull from the stored cursor.
- New messages are parsed, threaded to an enrollment and classified.
- A "reply" label sends a signal to the workflow, which cancels the pending timer, marks the enrollment finished, notifies the rep and logs the activity. An out-of-office label pauses and resumes after the stated return date if one was parsed.
- The cursor advances only after the signal is durably stored. Time budget: the reply must beat the next queued send, so the sync interval bounds how long a prospect can receive a follow-up after replying.
Scaling
In the order the limits usually bite:
- Reputation, not hardware. Daily sends per mailbox and per sending domain are bounded by what receivers tolerate. Levers: ramp-up schedules, more mailboxes per customer, separate domains for outreach, stricter list hygiene (verify addresses before enrolling, suppress after the first hard bounce).
- Provider API quotas on mailbox reads and sends. Levers: cursor-based pulls instead of full scans, push to trigger, per-provider budgets in the rate limiter, backoff on 429 and 5xx responses (Exponential backoff with jitter).
- Timer volume. A large customer base means very many pending timers; shard workflows by account id, keep only the next window in memory, batch the wakeups.
- Classification and transcription: batch call transcription; keep the reply path to rules plus a small model.
- CRM API limits are the quiet bottleneck for activity logging; batch writes and coalesce updates to the same record.
Failure modes
| Failure | Symptom | Cause | Fix |
|---|---|---|---|
| Spam-folder placement | opens and replies collapse for a whole domain | too much volume too soon, missing authentication, high complaint rate | ramp caps, publish SPF/DKIM/DMARC, one-click unsubscribe, suppress non-engaged contacts |
| Double send | a prospect gets step 2 twice | workflow retried after the send but before the "sent" record | idempotency key per (enrollment, step), checked at the sending queue |
| Follow-up after a reply | prospect replies "no thanks" and gets the next step | reply not threaded to the enrollment, or sync lag longer than the send delay | store sent Message-ID, fall back on address matching, check state again right before send |
| Out-of-office read as a reply | sequences stop for people who are away | no classification of auto-replies | header rules (Auto-Submitted, RFC 3834), classifier label, pause instead of end |
| Cursor expired | mailbox sync returns 404 or "gone" after a long outage | stored history position older than the provider keeps | catch it, run a bounded full resync, deduplicate by Message-ID |
| Time-zone slip | emails arrive at 3 a.m. or an hour off after a clock change | local times recomputed at send time, or stored without a zone | store absolute instants, compute from IANA zones once |
| Bad numbers | dialer connects to the wrong person or fails | numbers not normalised, national formats mixed | parse to E.164 with the contact's country, keep the original |
| One-way audio | the rep hears nothing on some networks | NAT or firewall blocks the media path | TURN relay, test ICE paths, keep the media server public |
| CRM write loop | fields flip back and forth | both systems write the same field | one owner per field, ignore changes made by the integration user |
Real implementations
No open-source project was found for this page that bundles sequences, a mailbox sync and a dialer; the open pieces below cover its parts. Commercial platforms such as Outreach, Salesloft and Apollo document their products publicly but not their internals, so none is listed here.
| name | what it is | repo | licence | notes |
|---|---|---|---|---|
| Twenty | open-source CRM: the system of record side of the design | twentyhq/twenty | AGPL-3.0 (some files commercial, see repo) | contact, company and activity model; integration point for sync |
| Mautic | marketing automation: segments, campaigns, email | mautic/mautic | GPL-3.0 | campaign engine over timed email steps, closest in shape to sequences |
| listmonk | newsletter and mailing-list manager, single binary | knadh/listmonk | AGPL-3.0 | bulk send, bounce handling, unsubscribe flow |
| Postal | self-hosted mail delivery server | postalserver/postal | — | sending, bounces and tracking as a service |
| Cal.com | scheduling and booking | calcom/cal.com | MIT | the "book a meeting" link inside a sequence step |
| Temporal | durable workflow engine | temporalio/temporal | MIT | one way to run the per-enrollment workflow |
| Asterisk | open-source PBX and SIP server | asterisk/asterisk | GPL-2.0 (alternative licences exist, see repo) | carrier-side telephony |
| FreeSWITCH | open-source telephony and media platform | signalwire/freeswitch | MPL-1.1 | SIP and WebRTC bridging |
| Kamailio | SIP server and proxy | kamailio/kamailio | GPL (see repo) | routing in front of media servers |
| jambonz | open-source voice platform for programmable calls | jambonz/jambonz-api-server | MIT | API layer of a CPaaS-style voice stack |
| libphonenumber | phone number parsing, validation and formatting | google/libphonenumber | Apache-2.0 | E.164 normalisation |
Sources
- Mail: RFC 5321 (SMTP) rfc, RFC 5322 (message format and threading headers) rfc, RFC 4954 (authenticated submission) rfc, RFC 3464 (delivery status notifications) rfc, RFC 3463 (enhanced status codes) rfc, RFC 3834 (auto-submitted mail) rfc.
- Sender authentication: RFC 7208 (SPF) rfc, RFC 6376 (DKIM) rfc, RFC 7489 (DMARC) rfc.
- Unsubscribe: RFC 2369 (
List-Unsubscribe) rfc, RFC 8058 (one-click) rfc. - Mailbox sync: Gmail API: synchronize clients, Gmail API push notifications, Microsoft Graph delta query.
- Telephony: RFC 3261 (SIP) rfc, W3C WebRTC, ITU-T E.164.