mirror of https://github.com/djcb/mu.git
335 lines
9.6 KiB
Org Mode
335 lines
9.6 KiB
Org Mode
|
#+title: MU QUERY
|
||
|
|
||
|
* 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 regular expressions that follow ECMAScript; for
|
||
|
details, see http://www.cplusplus.com/reference/regex/ECMAScript/
|
||
|
|
||
|
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, see *mu-fields(1)*.
|
||
|
#+begin_example
|
||
|
bcc,h Bcc (blind-carbon-copy) recipient(s)
|
||
|
body,b Message body
|
||
|
cc,c Cc (carbon-copy) recipient(s)
|
||
|
changed,k Last change to message file (range)
|
||
|
date,d Send date (range)
|
||
|
embed,e Search inside embedded text parts
|
||
|
file,j Attachment filename
|
||
|
flag,g Message Flags
|
||
|
from,f Message sender
|
||
|
list,v Mailing list (e.g. the List-Id value)
|
||
|
maildir,m Maildir
|
||
|
mime,y MIME-type of one or more message parts
|
||
|
msgid,i Message-ID
|
||
|
prio,p Message priority (=low=, =normal= or =high=)
|
||
|
size,z Message size range
|
||
|
subject,s Message subject
|
||
|
tag,x Tags for the message
|
||
|
thread,w Thread a message belongs to
|
||
|
to,t To: recipient(s)
|
||
|
#+end_example
|
||
|
|
||
|
The shortcut character can be used instead of the full name:
|
||
|
#+begin_example
|
||
|
f:foo@bar
|
||
|
#+end_example
|
||
|
is the same as
|
||
|
#+begin_example
|
||
|
from:foo@bar
|
||
|
#+end_example
|
||
|
For queries that are not one-off, we would recommend the longer name
|
||
|
for readability.
|
||
|
|
||
|
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
|
||
|
|
||
|
* 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 apostroph 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-fields(1)*
|