Browse the docs

SendQL

Consent and membership

Subscriptions, opt-outs, suppression, and testing membership of a list or another segment.

Deliverability rules are not a separate system bolted onto SendQL. They are terms in the language, and they read like English.

Four forms, covering the four questions worth asking:

SendQL
subscribed to "product-updates"
SendQL
opted out of "promos"
SendQL
unsubscribed from all
SendQL
suppressed

A topic is a consent grouping — a subscription a contact can opt into or out of independently of every other. Each topic has a default, opted in or opted out, and a contact who has never stated a preference for that topic takes it. So the question each term asks is about the contact’s effective status:

TermMatches
subscribed to "marketing"Effectively opted in — by their own choice, or by the topic’s default — and not unsubscribed from all
opted out of "marketing"Effectively opted out — by their own choice, or by the topic’s default

The two are nearly, but not quite, negations of each other. A contact who is opted in to the topic but has unsubscribed from everything is in neither set: they are not mailable under the topic, yet they never opted out of it.

You write the topic’s name, and the name is not checked against your topics. A misspelt one (subscribed to "markting") is accepted and matches nobody, so copy names rather than retyping them.

unsubscribed from all is the global opt-out — the “unsubscribe from everything” link, not a per-topic preference.

suppressed is different in kind, and it is the one to understand. A suppressed contact is one you cannot mail: a hard bounce, a spam complaint, a manual block. It is not a preference, it is a deliverability fact, and ignoring it is how a sender damages its reputation.

Which is why almost every segment you write should end the same way:

SendQL
attr.plan = "trial" and not suppressed

Get in the habit. not suppressed costs six characters.

Membership

Two forms, both taking the quoted key of the list or segment:

SendQL
in list "beta-testers"
SendQL
in segment "power-users"

A list is a named bag of contacts — something you add people to, by hand or from a workflow (add to list "engaged").

A segment is a saved SendQL query. in segment "power-users" composes one segment into another, which is how you keep a complicated definition in one place instead of copy-pasting a predicate into nine campaigns:

SendQL
in segment "power-users" and not exists(activity.login within 30d)

Both compose with not:

SendQL
in list "beta-testers" and not in segment "power-users"

When you save a segment, each key is looked up and stored as the list’s or segment’s id, so the saved definition keeps pointing at the same list even if another one is later created under the old key. Reopen the segment and you will see the id where you typed the key; writing the id yourself is equally valid. A key that names nothing does not block the save: the segment is saved as invalid, with a reason that names the key:

in list "beta-tester": no List has this key or id in this organization

They are strings, so they can be anything

Topics, lists and segments are all quoted strings, never bare identifiers. That is a deliberate design decision with a pleasant consequence: their names are not constrained by the language’s grammar at all.

SendQL
subscribed to "timeout" and in list "count"

Both of those names are reserved words, and both are perfectly fine, because a quoted string can never be confused with a keyword. Hyphens, spaces and punctuation are equally unproblematic — "product-updates" needs no escaping or special handling.

A realistic deliverability preamble

Putting the consent terms together with the rest of the language, a production-grade marketing segment usually looks something like this:

SendQL
// Reachable, engaged, opted-in — and demonstrably not a lost cause.
subscribed to "marketing"
  and not suppressed
  and not unsubscribed from all
  and count(bounce within 90d) = 0
  and count(complaint) = 0
  and count(open within 60d) >= 1

The last three lines are worth stealing. Filtering out recent bouncers and anyone who has ever complained, and requiring a single open in two months, is most of what list hygiene actually is — and here it is just five more terms in the same expression, checked by the same type checker as everything else.