DarDev outreach runs on a simple split: Twenty CRM orchestrates—who gets mail, when, human approval, follow-up tasks—while platform-bus executes tracked sends, syncs Listmonk engagement, scans reply inboxes, and writes timeline Notes on every stage transition. The bus is not a bulk brain that blasts thousands of CSV rows. CRM owns decisions; HTTP endpoints on mail.dardev.net carry them out with idempotent, auditable side effects.
This hub article generalizes the pattern used for 20.tn school outreach and DarDev Services Tunisia SMB pipeline. Product-specific field names differ; the layers do not. Read inside-unified-mailer-stack for mail topology, deployed-realities-explained for honest shipped status, and multi-product-saas-one-core for why CRM and bus stay separate services on shared dardev-vps infrastructure.
Architecture layers
- Twenty workflows — triggers, filters, delays, human approval gates, task creation
- Person or Company record — outreach status fields, approval booleans, personalization text
- Timeline Notes — Queued, Sent, Opened, Clicked, Replied; one Note per transition from bus
- Platform-bus — send-one, sync-engagement, sync-replies, product-specific job runners
- Listmonk — tracked transactional and campaign delivery; not cold-import audience store
- Stalwart — SMTP from send.dardev.net or sales.dardev.net per product rules
State machine both products share
A contact starts at NOT_SENT. Preview workflow with dryRun queues a timeline Note without delivery. Approved live send moves to SENT via send-one. Scheduled sync-engagement polls Listmonk for opens and clicks, updating OPENED and CLICKED. sync-replies scans the product reply inbox and sets REPLIED. Listmonk unsubscribe maps to OPT_OUT. Validation failures land in ERROR with last error on the Person record.
Every transition creates a visible Note on the Person timeline so sales and ops audit the same story without reading server logs. That audit trail pattern is shared between 20tn-crm-workflow-orchestration detail and DarDev Services playbooks—only field names and templates change.
20.tn school outreach
Twenty owns roughly 970 imported schools as People with outreachStatus, outreachApproved, outreachPersonalLine, and outreachCustomSubject. Workflows use Manual and Record updated triggers—not dumb bulk POST to legacy preview endpoints. Intro and follow-up phases call platform-bus send-one with personId, phase, dryRun, requireApproved, and templateVars merged from CRM fields.
HTML lives in listmonk/templates/20tn-intro-outreach-body.html and 20tn-followup-outreach-body.html wrapped by 20tn-campaign.html for tracking pixels. Sender identity uses sales.dardev.net product rules. Human staff approve each intro after preview dry-run writes a Queued note. Follow-up fires three days after SENT via Person updated workflow.
- 20tn — preview intro — dryRun true — no SMTP
- 20tn — send intro — filter outreachApproved — live send-one
- 20tn — follow-up — SENT plus three-day delay — phase followup
- 20tn — opened or clicked or replied tasks — create linked Tasks for sales
DarDev Services Tunisia pipeline
DarDev Services cold SMB prospects import to Twenty with targetSolution DARDEV and Tunisia filters. consentEmail stays UNKNOWN until subscribe form confirm on dardev-services-marketing list at mail.dardev.net. Platform-bus services-outreach routes sync CRM to Listmonk only after opt-in webhook. First cold touch stays CRM-first Zoho contact@dardev.net one-to-one or tracked outreach paths—not Listmonk bulk campaigns.
Welcome workflow on People created fires from Zoho for booked calls after consent. Campaign templates use dardev-services-campaign.html with TrackView and TrackLink. The orchestration versus execution split is identical to 20.tn: workflows decide, bus POST handlers run, Listmonk proves delivery and engagement.
Why not bulk from the bus
Bulk endpoints remain for ops preview and migration emergencies—not production school or services outreach. Per-person workflows enforce rate limits, approval, and timeline Notes. Warm-up on send.dardev.net and sales.dardev.net cannot survive a one-click ten-thousand-row blast. CRM filters plus Manual triggers keep humans in the loop for cold segments.
When marketing needs opted-in newsletter sends, operators use Listmonk UI campaigns on the correct list. When automation needs paced batch jobs—daily digest, long warm-up drips—mail-jobs and daily route groups on platform-bus talk SMTP direct to Stalwart. Outreach sits in the middle: tracked like campaigns, paced like jobs, approved like sales calls.
HTTP contract shape workflows use
Twenty HTTP action steps POST JSON to mail.dardev.net paths with bearer auth configured in workflow credentials—never publish those values in docs or news articles. Body carries record ids, phase names, dryRun boolean, requireApproved flag, and templateVars object for subject overrides and personal lines. Bus validates, renders template, submits to Listmonk or SMTP, updates CRM via API, appends Note text.
sync-engagement and sync-replies run on schedules—hourly or custom cron—scanning Listmonk events and IMAP reply folders. They batch-update CRM statuses idempotently so duplicate polls do not duplicate Notes.
Ops and agents
DarDev Ops shows connector health and run actions but does not own SMTP From addresses or workflow graphs—that truth stays in Stalwart, Listmonk, and Twenty. AI agents may use Twenty CRM MCP at crm.dardev.net for read and write with API key auth; agents do not get bulk send shortcuts around approval fields. Agent mail for programmatic notifications uses agents.dardev.net—a separate domain from sales outreach.
Adopting the pattern elsewhere
- Model outreach status and approval on CRM objects—not spreadsheet columns
- Import cold prospects CRM-only; wire Listmonk after consent webhook
- Add Twenty workflows with dry-run preview before live send
- Implement send-one and sync handlers on platform-bus with frozen route catalog entry
- Use timeline Notes as audit trail for every transition
- Validate warm-up and deliverability before scaling sends
Hesabi OECT and SMB pipelines follow the same CRM-first import discipline with different field schemas. The hub pattern scales because platform-bus is product-agnostic HTTP; only manifest connector overlays and handler bodies change per solution.
Metrics operators watch
CRM views group People by outreachStatus for daily standup. ERROR rows surface validation failures with outreach last error text. Tasks created on OPENED or CLICKED appear in assignee inboxes inside Twenty—not email forwards. Bus job logs show SMTP accept or Listmonk API reject without exposing recipient PII in news or public docs.
Warm-up limits on Stalwart cap how fast orchestration can execute even when CRM workflows fire frequently. Orchestration without execution pacing burns domain reputation; execution without orchestration loses audit trail and consent discipline. Both layers must be designed together—see mail-warmup-send-profile and consent-unknown-crm-first-outreach companion articles in Phase E batch two.
When debugging a stuck Person at SENT with no OPENED, check Listmonk tracking on the template wrapper, spam folder at recipient, and sync-engagement schedule in workflow—not the CRM trigger alone. When REPLIED never fires, verify reply inbox IMAP credentials on the bus mail-jobs config and that the prospect replied to the correct sales or send domain address.
This hub article links the 20.tn and services implementations under one pattern name so Phase E readers find the mental model before diving into product-specific workflow catalogs. Start here, then read 20tn-crm-workflow-orchestration or internal services playbooks for field-level detail.
Does platform-bus decide who to email?
No. Twenty workflows and CRM filters decide. Bus executes approved HTTP requests and writes Notes.
When do contacts enter Listmonk?
After explicit opt-in—subscribe form confirm or webhook—not on cold CRM import.
What is the difference between 20.tn and DarDev Services?
Same orchestration pattern; different CRM fields, templates, sender domains, and consent rules.
Can workflows call bulk send endpoints?
Legacy bulk endpoints are ops preview only. Production uses per-person send-one with approval.
Where is 20.tn workflow detail documented?
See article 20tn-crm-workflow-orchestration and docs/20TN-WORKFLOW-ORCHESTRATION.md in the repo.



