#+TITLE: MU QUERY #+MAN_CLASS_OPTIONS: :section-id "@SECTION_ID@" :date "@MAN_DATE@" * NAME mu query language -- a language for finding messages in *mu* databases. * DESCRIPTION The mu query language is a language used by *mu find* and *mu4e* to find messages in *mu*'s Xapian databases. The language is quite similar to Xapian's default query-parser, but is an independent implementation that is customized for the mu/mu4e use-case. In this article, we give a structured but informal overview of the query language and provide examples. As a companion to this, we recommend the *mu fields* and *mu flags* commands to get an up-to-date list of the available fields and flags. *NOTE:* if you use queries on the command-line (say, for *mu find*), you need to quote any characters that would otherwise be interpreted by the shell, such as *""*, *(* and *)* and whitespace. * TERMS The basic building blocks of a query are *terms*; these are just normal words like 'banana' or 'hello', or words prefixed with a field-name which make them apply to just that field. See *mu find* for all the available fields. Some example queries: #+begin_example vacation subject:capybara maildir:/inbox #+end_example Terms without an explicit field-prefix, (like 'vacation' above) are interpreted like: #+begin_example to:vacation or subject:vacation or body:vacation or ... #+end_example The language is case-insensitive for terms and attempts to 'flatten' any diacritics, so =angtrom= matches =Ångström=. If terms contain whitespace, they need to be quoted: #+begin_example subject:"hi there" #+end_example This is a so-called =phrase query=, which means that we match against subjects that contain the literal phrase "hi there". Remember that you need to escape those quotes when using this from the command-line: #+begin_example mu find subject:\\"hi there\\" #+end_example * LOGICAL OPERATORS We can combine terms with logical operators -- binary ones: *and*, *or*, *xor* and the unary *not*, with the conventional rules for precedence and association, and are case-insensitive. You can also group things with *(* and *)*, so you can do things like: #+begin_example (subject:beethoven or subject:bach) and not body:elvis #+end_example If you do not explicitly specify an operator between terms, *and* is implied, so the queries #+begin_example subject:chip subject:dale #+end_example #+begin_example subject:chip AND subject:dale #+end_example are equivalent. For readability, we recommend the second version. Note that a =pure not= - e.g. searching for *not apples* is quite a 'heavy' query. * REGULAR EXPRESSIONS AND WILDCARDS The language supports matching basic PCRE regular expressions, see *pcre(3)*. Regular expressions are enclosed in *//*. Some examples: #+begin_example subject:/h.llo/ # match hallo, hello, ... subject:/ #+end_example Note the difference between 'maildir:/foo' and 'maildir:/foo/'; the former matches messages in the '/foo' maildir, while the latter matches all messages in all maildirs that match 'foo', such as '/foo', '/bar/cuux/foo', '/fooishbar' etc. Wildcards are an older mechanism for matching where a term with a rightmost *** (and =only= in that position) matches any term that starts with the part before the ***; they are supported for backward compatibility and *mu* translates them to regular expressions internally: #+begin_example foo* #+end_example is equivalent to #+begin_example /foo.*/ #+end_example As a note of caution, certain wild-cards and regular expression can take quite a bit longer than 'normal' queries. * FIELDS We already saw a number of search fields, such as *subject:* and *body:*. For the full table with all details, including single-char shortcuts, try the command: ~mu info fields~. |------------+-----------+--------------------------------| | field-name | alias | description | | bcc | | Blind carbon-copy recipient | | body | | Message plain-text body | | cc | | Carbon-copy recipient | | changed | | Last change time | | date | | Message date | | embed | | Embedded text | | file | | Attachment file name | | flags | flag | Message properties | | from | | Message sender | | language | lang | ISO 639-1 language code (*) | | maildir | | Maildir path for message | | list | | Mailing list (List-Id:) | | message-id | msgid | Message-Id | | mime | mime-type | Attachment MIME-type | | path | | File system path to message | | priority | prio | Priority | | references | | References to related messages | | size | | Message size in bytes | | subject | | Message subject | | tags | tag | Message tags | | thread | | Thread a message belongs to | | to | | Message recipient | |------------+-----------+--------------------------------| (*) The language code for the text-body if found. This works only if ~mu~ was built with CLD2 support. There are also the special fields *contact:*, which matches all contact-fields (=from=, =to=, =cc= and =bcc=), and *recip*, which matches all recipient-fields (=to=, =cc= and =bcc=). Hence, for instance, #+begin_example contact:fnorb@example.com #+end_example is equivalent to #+begin_example (from:fnorb@example.com or to:fnorb@example.com or cc:from:fnorb@example.com or bcc:fnorb@example.com) #+end_example * DATE RANGES The *date:* field takes a date-range, expressed as the lower and upper bound, separated by *..*. Either lower or upper (but not both) can be omitted to create an open range. Dates are expressed in local time and using ISO-8601 format (YYYY-MM-DD HH:MM:SS); you can leave out the right part, and *mu* adds the rest, depending on whether this is the beginning or end of the range (e.g., as a lower bound, '2015' would be interpreted as the start of that year; as an upper bound as the end of the year). You can use '/' , '.', '-' and 'T' to make dates more human readable. Some examples: #+begin_example date:20170505..20170602 date:2017-05-05..2017-06-02 date:..2017-10-01T12:00 date:2015-06-01.. date:2016..2016 #+end_example You can also use the special 'dates' *now* and *today*: #+begin_example date:20170505..now date:today.. #+end_example Finally, you can use relative 'ago' times which express some time before now and consist of a number followed by a unit, with units *s* for seconds, *M* for minutes, *h* for hours, *d* for days, *w* for week, *m* for months and *y* for years. Some examples: #+begin_example date:3m.. date:2017.01.01..5w #+end_example * SIZE RANGES The *size* or *z* field allows you to match =size ranges= -- that is, match messages that have a byte-size within a certain range. Units (b (for bytes), K (for 1000 bytes) and M (for 1000 * 1000 bytes) are supported). Some examples: #+begin_example size:10k..2m size:10m.. #+end_example * FLAG FIELD The *flag/g* field allows you to match message flags. The following fields are available: #+begin_example a,attach Message with attachment d,draft Draft Message f,flagged Flagged l,list Mailing-list message n,new New message (in new/ Maildir) p,passed Passed ('Handled') r,replied Replied s,seen Seen t,trashed Marked for deletion u,unread new OR NOT seen x,encrypted Encrypted message z,signed Signed message #+end_example Some examples: #+begin_example flag:attach flag:replied g:x #+end_example Encrypted messages may be signed as well, but this is only visible after decrypting and thus invisible to *mu*. * PRIORITY FIELD The message priority field (*prio:*) has three possible values: *low*, *normal* or *high*. For instance, to match high-priority messages: #+begin_example prio:high #+end_example * MAILDIR The Maildir field describes the directory path starting *after* the Maildir-base path, and before the =/cur/= or =/new/= part. So for example, if there's a message with the file name =~/Maildir/lists/running/cur/1234.213:2,=, you could find it (and all the other messages in the same maildir) with: #+begin_example maildir:/lists/running #+end_example Note the starting '/'. If you want to match mails in the 'root' maildir, you can do with a single '/': #+begin_example maildir:/ #+end_example If you have maildirs (or any fields) that include spaces, you need to quote them, ie. #+begin_example maildir:"/Sent Items" #+end_example Note that from the command-line, such queries must be quoted: #+begin_example mu find 'maildir:"/Sent Items"' #+end_example * MORE EXAMPLES Here are some simple examples of *mu* queries; you can make many more complicated queries using various logical operators, parentheses and so on, but in the author's experience, it's usually faster to find a message with a simple query just searching for some words. Find all messages with both 'bee' and 'bird' (in any field) #+begin_example bee AND bird #+end_example Find all messages with either Frodo or Sam: #+begin_example Frodo OR Sam #+end_example Find all messages with the 'wombat' as subject, and 'capybara' anywhere: #+begin_example subject:wombat and capybara #+end_example Find all messages in the 'Archive' folder from Fred: #+begin_example from:fred and maildir:/Archive #+end_example Find all unread messages with attachments: #+begin_example flag:attach and flag:unread #+end_example Find all messages with PDF-attachments: #+begin_example mime:application/pdf #+end_example Find all messages with attached images: #+begin_example mime:image/* #+end_example Find all messages written in Dutch or German with the word 'hallo': #+begin_example hallo and (lang:nl or lang:de) #+end_example * CAVEATS With current Xapian versions, the apostroph character is considered part of a word. Thus, you cannot find =D'Artagnan= by searching for =Artagnan=. So, include the apostrophe in search or use a regexp search. Matching on spaces has changed compared to the old query-parser; this applies e.g. to Maildirs that have spaces in their name, such as =Sent Items=. See *MAILDIR* above. #+include: "prefooter.inc" :minlevel 1 * SEE ALSO *mu-find(1)*, *mu-info(1), *pcre(3)*