cd /news/developer-tools/sendlang-a-dsl-for-email-automation · home topics developer-tools article
[ARTICLE · art-60813] src=sendlang.com ↗ pub= topic=developer-tools verified=true sentiment=↑ positive

SendLang: A DSL for Email Automation

SendLang, a new domain-specific language for email automation, lets developers define email segments with SendQL and lifecycle workflows with SendFlow as plain-text files that live in version control. The language is designed for coding agents, with machine-readable docs, a published EBNF grammar, and a type checker that catches errors before sending. SendLang aims to replace visual editors by making campaigns reviewable, diffable, and agent-friendly.

read6 min views44 publishedJul 15, 2026
SendLang: A DSL for Email Automation
Image: source

SendLang is the home of two small, focused languages. SendQL describes who a message is for. SendFlow describes what happens to them over time — and speaks SendQL natively.

Written by people and by coding agents — a published grammar, a type checker to iterate against, and a diff you approve. See how.

SendLang

One family, two languages #

SendQL is the noun. SendFlow is the verb. Together they turn contact data and event streams into campaigns you can read in a diff.

SendQL

the whoA segment-definition query language. Every query is a single boolean expression describing which contacts a segment matches.

SendFlow

the whatA drip-workflow language stored in .flow

files. It reads top to bottom and embeds SendQL for every condition.

Why a language

Your lifecycle email, in version control #

Every other tool locks your cohorts and lifecycle campaigns inside a visual editor. Make them a language instead, and they become text you can diff, review, and hand to a coding agent.

  • It lives in version control
  • Every segment and workflow is a plain text file. Diff it, review it in a pull request, roll it back. Your targeting and your drip logic earn the same rigor as the rest of your code.
  • It fails before it sends
  • A misspelled attribute is a type error with a line and a column — not a campaign that quietly sends to nobody for a week.
  • A coding agent can write it
  • This is the big one. A canvas is a dead end for an agent; a language is the loop it already works in. Describe the outcome, let it draft the file, merge it once it passes review.

Coding agents

Hand the campaign to an agent #

A canvas is a dead end for a coding agent — it cannot read it, change it, or tell you what it changed. A language is the loop an agent already works in: read the file, write the file, run the checker, open a pull request. That is not a side effect of the design. It is a reason for it.

“Three days before a trial ends, email them. If they have not clicked within three days, send the upgrade offer.”

  • The docs are machine-readable
  • Every page has a Markdown twin, and llms.txt / llms-full.txt hand an agent the whole of both languages in a single fetch. Nothing to scrape, nothing to guess at.
  • A grammar, not a guess
  • The normative EBNF and the reserved-word list are emitted by the parsers themselves, so the spec an agent reads cannot drift from the code that judges what it writes.
  • The type checker is the feedback loop
  • Every parse and type error carries a line, a column, and a message that names the fix. The agent iterates against the checker until the run is clean — and nothing sends until it is.
  • You are still the approver
  • No goto, no unbounded loops, nothing to evaluate. The worst an agent can hand you is a workflow that terminates — and you read it as a diff before it ever reaches a contact.

The shortest useful thing you can do: put /llms-full.txt in your agent's context. That is both languages, complete, in one fetch.

Writing SendLang with a coding agent SendQL

Describe exactly who you mean #

SendQL reads events as a first-class source alongside contact attributes — the gap left by engines that see only precomputed rollups, never the raw stream.

  • Attributes and lists
  • Match on contact data with operators, in [...] sets, contains / starts with / ends with, and list or segment membership.
  • Events as a first-class source
  • Query the raw event stream directly — count, exists, sum, avg, last, first — not just precomputed engagement rollups.
  • Consent and suppression
  • Express deliverability rules inline: subscribed to "topic", opted out of "topic", unsubscribed from all, not suppressed.
  • Windows and recency
  • Bind a time window to any event source with within 30d or between two dates, and reason about recency with now - 14d.

The same file, rendered as a canvas

  • Entercart_updated
  • Wait1 hour
  • Sendcart-reminder
  • repeat up to 2 · every 24h · until orderSendcart-nudge
  • Exitpurchased

SendFlow

Structure, no goto #

A workflow reads top to bottom and maps losslessly to a flowchart — sequence, waits, branches, weighted splits, and one bounded repeat. Never a goto, never an unbounded loop.

  • One trigger, many exits
  • Enter on a segment, an activity, an email event, or a duration before a contact's own date. Named exits report conversions the moment they happen.
  • Timed steps
  • wait 2d, wait until a date or attribute, or wait up to 7d until a condition — with an optional timeout arm.
  • Branch, split, hold out
  • Fall-through if / else if / else, weighted split { 30%: ... 70%: ... } that must sum to 100, and hold out 10%.
  • Bounded loops only
  • The single loop is repeat up to N every duration until a condition. No goto, no unbounded loops, ever.

How they fit

SendFlow speaks SendQL #

The predicate you write to define a segment is the very same syntax that drives every condition inside a workflow.

A SendQL segment

The same predicate, inside a workflow

  • A strict superset

  • One shared token stream

  • One type-checker and diagnostics Design

Built like languages, not config #

Both languages are versioned by a profile number, split cleanly from their execution engines, and specified down to a machine-checked grammar.

  • Structured by design
  • Sequence, branch, bounded repeat, timed waits, named exits — a control-flow subset that maps losslessly to a flowchart.
  • Events as first class
  • Selection over the raw event stream sits alongside contact attributes, so you can segment on behavior, not just state.
  • Golden-pinned grammar
  • A normative EBNF is generated from the parser and pinned by tests, so the spec can never silently drift from the code.
  • Precise diagnostics
  • Parsing and type-checking are separate stages, and every error carries a line and column pointing at the exact token.
  • A canonical formatter
  • SendFlow ships a one-true-layout printer — gofmt for flows — so every workflow in your repository reads the same way.
  • A canvas, losslessly
  • The control flow is restricted enough that a workflow maps onto a flowchart and back with nothing lost — comments included. Text and canvas are two views of one thing.

Documentation

The whole language, written down #

Every construct in both languages, every diagnostic they can produce, and a normative grammar generated from the parsers themselves — so the spec can never quietly drift from the code.

── more in #developer-tools 4 stories · sorted by recency
── more on @sendlang 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/sendlang-a-dsl-for-e…] indexed:0 read:6min 2026-07-15 ·