InboxQL Documentation

Using it

The query language

Every term, match mode and pipeline stage, with examples. · 9 min read

Everything InboxQL shows you is the answer to a query, and every query is something you can type. This page is the whole language. It is short, because most of its power comes from a few pieces that combine.

A query is a filter, optionally followed by stages after a |:

from:*@stripe.com after:2026-01-01 has:attachment
is:unread -from:*@acme.com | count by week

A query with a stage: all mail, counted by labelA query with a stage: all mail, counted by label

The same text works in the Desk’s query bar and on the command line, as iql query "…".

Filters

Terms written side by side must all match. OR gives alternatives, and parentheses group:

from:alice subject:invoice
from:alice OR from:bob
(from:alice OR from:bob) after:2026-06

People and addresses

Term Matches
from: to: cc: bcc: the sender, or any recipient in that field
anyone: any of them
has:cc somebody was copied; -has:cc means nobody was

from:me() is your own addresses — the ones on the accounts you set up — so to:me() is mail sent to you and from:me() is what you sent.

from:(alice OR bob) scopes a group to one field, which saves repeating it.

Words

Term Matches
subject: words in the subject
body: words in the body
a bare word words anywhere
"a phrase" those words, together, in that order

These match whole words: subject:invoice finds invoice, not invoiced hidden inside another word. Use subject:*invoice* for any text containing it.

Search is by words, not by meaning. invoice does not find billing. When it matters, ask more than one way: subject:(invoice OR bill OR receipt).

Where mail is

Term Matches
label: a label it carries: label:inbox, label:trash, label:Receipts, label:Work/*
folder: inbox starred sent drafts allmail archive important spam trash all
account: the InboxQL account it belongs to
mailbox: the server folder it was first read from, by name

Mail has labels, not folders, as in Gmail: the system ones — inbox, sent, drafts, important, spam, trash — and your own. A message carries any number. folder: names views over them: folder:inbox is label:inbox outside Spam and Trash, folder:archive is mail not in the inbox (outside Spam and Trash), and folder:allmail is everything but Spam and Trash. They overlap, as labels do.

Trash and Spam stay out unless you ask

A query leaves out mail in Trash and Spam unless it mentions them, as Gmail’s search does. from:bob is Bob’s mail you have kept; the newsletter of his you binned, and the spam sent in his name, are not in it. That goes for everything built on queries: counts, charts, the Dashboard, a contact card’s figures, saved queries and annotators.

Each bin comes back when the query mentions it, and only that one:

  • Trash — folder:trash, label:trash, is:deleted
  • Spam — folder:spam, label:spam, is:junk
  • Both — folder:all, which is how you say “everywhere”

A mention counts anywhere in the query: inside ( … OR … ), after a -, or in a saved: query it uses. id: names messages exactly, so a query with one finds them wherever they are.

When a list leaves something out, the Desk says so under the query bar — “3 more in Trash or Spam” — with Show them, which adds folder:all. A conversation says what it holds back, too: “4 messages · 1 in Trash”. --explain and iql query say the same.

State

Term Matches
is: unread read starred answered deleted (in Trash) draft junk (in Spam) reply
has: attachment file label reply

Time and size

Term Matches
after: before: on: 2026-08-15, 2026-08, 2026, today, or 7d for the last seven days
larger: smaller: 5mb, 500kb, or a number of bytes

Conversations

thread:<message-id> is every message in that conversation. The | thread stage, below, expands any list to whole conversations.

Files

attached:contract is mail that carried a file named contract; attached:*.pdf after:7d is mail with a PDF on it this week. Given eight or more hex characters, attached: matches a file’s content fingerprint instead, so it finds the same document whatever it was called. Files has more.

Labels and extracted values

Term Matches
label:purchased an annotator said yes
label:purchased@0.9 said yes, with a score of at least 0.9
-label:purchased looked, and said no
unlabeled:purchased has not looked yet
extract:receipts an extractor found at least one record
extract:receipts.amount>100 …with an amount over 100
extract:receipts.items.brand=DeWalt …with any item of that brand — a path through a list matches if any element does
extract:importance.level=important a levelled label picked that level
awaiting:me, awaiting:them the newest message of a conversation the waiting element judged to wait on you, or on them
importance: important normal low ignorable — every message of a conversation the importance element judged so; nothing judged is none of them
sentby: person organization system unknown — what kind of sender wrote it, as the contact records it

label: answers for both kinds of label: the ones you, Gmail or your other mail client put on, and the ones an annotator decides. A label of yours is there or it is not. An annotator’s has three states, not two, and this is the thing in the language most worth getting right. -label:x means the annotator evaluated the message and said no. It does not include mail the annotator has never seen — if it did, a label that had read a tenth of your mailbox would present the other nine tenths as a negative answer. When you do want both, ask for both: -label:x OR unlabeled:x. See Labels.

When one name is both — you made a label called purchased and an annotator has the same name — label:purchased is either one saying yes, and -label:purchased is neither.

Saved queries

saved:clients is everything the saved query clients matches, so it combines with anything: saved:clients after:7d is:unread.

Three ways to match

from:acme          contains "acme" — also notacme@x.com
from:=a@acme.com   exactly this address
from:*@acme.com    a pattern; * stands for any run of characters

They are different questions, so the language keeps them apart instead of guessing which you meant.

Leaving things out

- or NOT in front of any term or group leaves out what it matches:

-from:alice
-(from:alice after:2026-01)
from:*@acme.com -to:bob@acme.com

On recipients, -to:bob means no recipient is Bob — not “some recipient is not Bob”, which would match nearly every message with more than one recipient.

What a query is about

A query is about one kind of thing. Mail is the default; in: says otherwise:

in:mail messages — the default
in:drafts your drafts and queued mail
in:contacts the people and systems you have corresponded with
in:attachments files, each one once however many times it was sent
in:tickets cards on the board — archived ones only when the query says archived:
in:events calendar events, one row per occurrence
in:logs what InboxQL itself has been doing

A field that only one kind has implies it: due:7d is about tickets, origin:agent about drafts. Each kind adds its own fields — kind:system for contacts, filetype:pdf for files, level>warn for the log — and the guides for contacts, files and tickets list them. Message fields still work inside them and ask about the mail behind the thing: in:attachments from:*@acme.com is files that came from Acme.

Calendar events

in:events asks about the calendar. A row is one occurrence — a weekly meeting is fifty-two rows a year — because that is what “what is on” and “how many hours” are about.

Term Matches
next: from now until this far ahead: next:7d, next:2w
after: before: on: the occurrence’s own time, as for mail
during: going on at a moment (2026-10-15T14:00) or on a day
calendar: which calendar, by name
attendee: organizer: who; me() is you
status: your answer: accepted tentative declined needs-action organizer
show: busy or free
title: location:, a bare word the words
duration> length in minutes
has: conference attendees recurrence reminder location thread
is: recurring allday private invitation proposed past upcoming

A proposal an agent made is left out of lists and totals unless you ask for it with is:proposed. Group events by calendar, attendee, domain, organizer, status, title, or a time bucket, and add up their length with | sum hours or | sum minutes:

in:events after:30d | sum hours by attendee
in:events next:14d | count by day

Stages

After a |, a stage changes what comes back. A query has at most one stage that adds things up.

Stage
| count how many
| count by week how many per week — or per from, domain, label…
| top from 10 the ten largest groups
| sort date asc reorder
| limit 50 at most 50
| sample 20 twenty at random, rather than the newest twenty
| thread expand to whole conversations
| participants who appears, and how often
| sum receipts.amount by month add up an extracted value (also avg, min, max)
| series receipts.amount by week an extracted value over time

You can group by from, domain, to, cc, account, mailbox, label, thread and subject; by hour, day, week, month and year; and by any extracted value, written annotator.field — | count by receipts.merchant. A field whose name has a space in it is quoted: | count by "receipts.order number".

| count by counts messages: a message naming two merchants adds one to each. | sum and | series add up records, because a weekly digest with seven daily figures is seven of them.

Examples worth stealing

extract:importance.level=important after:7d | thread
is:unread to:me() -label:automated after:7d
from:me() after:90d | top to 20
in:contacts awaiting:me | sort last desc
awaiting:me | timeline
in:attachments filetype:pdf is:shared | count by from
extract:receipts after:2026 | sum receipts.amount by month
label:loops -from:me() after:30d | thread
in:logs level>warn after:1d | count by category

When a query is wrong

A query that does not parse says where: the position of the problem and what was expected there. An unknown field suggests the nearest real one — form: asks whether you meant from:.

On the command line, iql query "…" --explain shows the SQL a query becomes, and iql sql runs read-only SQL for anything the language cannot say. Both are covered in the command line.