# SendLang > SendLang is the home of two small languages for lifecycle email. SendQL is a query language that describes WHO a message is for — one query is a single boolean expression over contact attributes, the raw event and activity stream, consent, and list membership. SendFlow is a workflow language that describes WHAT HAPPENS to a contact over time, stored in .flow files. SendFlow is a strict superset of SendQL: every where/when/if/until condition in a workflow is a real SendQL predicate. This site is the canonical syntax reference for both. Both languages are designed to be authored and refactored by coding agents: the grammar and the reserved-word list are generated from the parsers, every error carries a line, a column and a named fix, and `sendflow-lint` is the loop you should iterate against before proposing a change. Every page on this site is available as Markdown at its own URL with `.md` appended (e.g. /docs/sendql/events → /docs/sendql/events.md). The links below point at those. The full corpus in one file is at /llms-full.txt. ## Reading the code samples Samples are tagged, and the tag matters: - A `sendql` or `sendflow` block is real, valid source. Every one of them is parsed and type-checked against the actual parsers when this site is built. - A block introduced by **Rejected** is source the parser REFUSES. It is shown to explain an error. Do not copy it. - A block introduced by **Syntax form** is a shape, not a runnable program. ## If you are an agent writing a segment or a workflow Read /docs/agents.md first — it is written for you. The short version: - The registry (your account's attributes, events, activities, topics, templates and lists) is the ground truth for every name. Ask for it; do not invent names. - Run `sendflow-lint -registry registry.json ` before proposing the change. Exit 0 means the workflow is real; anything else is a positioned message to fix. - Then `sendflow-fmt -w` it, and let a human read the diff. Nothing sends until they merge. ## Two facts worth knowing before you write any SendQL 1. **Events vs activities.** The eight EVENTS are a closed set about email you sent — send, delivery, open, click, bounce, complaint, reject, delivery_delay — and are written bare. Anything the contact did in YOUR product is an ACTIVITY, written with a qualifier: `activity.order`, `activity.login`. Writing `exists(order)` is an error: `unknown event "order"`. 2. **Absence.** A missing value does not compare. `attr.plan != "pro"` does NOT match a contact with no plan, and `last(open) < now - 90d` excludes everyone who never opened at all. To include them, say so: `last(open) < now - 90d or count(open) = 0`. ## Introduction - [SendLang](https://www.sendlang.com/docs.md): Two small languages for lifecycle email — SendQL says who a message is for, SendFlow says what happens to them over time. - [Core concepts](https://www.sendlang.com/docs/concepts.md): The data model both languages sit on — contacts, attributes, events, activities, and the things a workflow can name. - [Tooling](https://www.sendlang.com/docs/tooling.md): The linter, the formatter, and the Go API — what you get to check a segment or a workflow before it ever sends an email. - [Coding agents](https://www.sendlang.com/docs/agents.md): SendLang is built so a coding agent can author and refactor your campaigns — a published grammar, a type checker to iterate against, and a diff a human approves before anything sends. ## SendQL - [SendQL](https://www.sendlang.com/docs/sendql.md): A query language for defining who a message is for. One query is one boolean expression. - [Syntax](https://www.sendlang.com/docs/sendql/syntax.md): Tokens, literals, operators, comments and precedence — the lexical surface of SendQL. - [Attributes](https://www.sendlang.com/docs/sendql/attributes.md): Matching on the contact's own data — comparison, sets, string matching, presence, and enums. - [Events and activities](https://www.sendlang.com/docs/sendql/events.md): Querying the raw stream — count, exists, aggregates, recency, property filters and time windows. - [Time](https://www.sendlang.com/docs/sendql/time.md): Durations, windows, `now`, and the age of a datetime attribute. - [Consent and membership](https://www.sendlang.com/docs/sendql/consent.md): Subscriptions, opt-outs, suppression, and testing membership of a list or another segment. - [Type rules](https://www.sendlang.com/docs/sendql/types.md): What the analyzer checks, and the exact rule behind every type error it can produce. - [The absence contract](https://www.sendlang.com/docs/sendql/absence.md): What happens when the data isn't there — why `attr.plan != "pro"` doesn't match a contact with no plan, and the lint that tells you. - [SendQL cookbook](https://www.sendlang.com/docs/sendql/cookbook.md): Segments worth stealing — engagement, lifecycle, revenue, hygiene. ## SendFlow - [SendFlow](https://www.sendlang.com/docs/sendflow.md): A workflow language for lifecycle email. One file is one campaign, read top to bottom. - [Settings](https://www.sendlang.com/docs/sendflow/settings.md): Triggers, named exits, send windows, re-entry, frequency caps and enrolment scope. - [Statements](https://www.sendlang.com/docs/sendflow/statements.md): Send, wait, branch, split, hold out, repeat, set, add to list, exit — the whole executable surface. - [Conditions](https://www.sendlang.com/docs/sendflow/conditions.md): How SendQL embeds into a workflow — the four places a predicate can go, and what each one means. - [Formatting and style](https://www.sendlang.com/docs/sendflow/formatting.md): One canonical layout, no options — what sendflow-fmt does to your file, and what it preserves. - [Lints](https://www.sendlang.com/docs/sendflow/lints.md): Every structural and semantic check the analyzer runs on a workflow, and what each one is protecting you from. - [SendFlow cookbook](https://www.sendlang.com/docs/sendflow/cookbook.md): Complete, working campaigns — onboarding, cart abandonment, winback, renewal, re-engagement. ## Reference - [Grammar](https://www.sendlang.com/docs/reference/grammar.md): The normative EBNF for both languages, generated from the parsers and pinned by tests. - [Reserved words](https://www.sendlang.com/docs/reference/reserved-words.md): The words you cannot use as a bare name — and the many places where you still can. - [Durations](https://www.sendlang.com/docs/reference/durations.md): One form, seven units, and two of them are nominal. - [Diagnostics](https://www.sendlang.com/docs/reference/errors.md): How to read an error, and the complete catalogue of what both languages can tell you. - [Versioning](https://www.sendlang.com/docs/reference/versioning.md): The version marker in a workflow header, and the compatibility promise behind it.