can be present on a given message with several different values.
     See :any:`notmuch-properties(7)` for more details.
 
+sexp:<subquery>
+    The **sexp:** prefix allows subqueries in the format
+    documented in :any:`notmuch-sexp-queries(7)`. Note that subqueries containing
+    spaces must be quoted, and any embedded double quotes must be escaped
+    (see :any:`quoting`).
+
 User defined prefixes are also supported, see :any:`notmuch-config(1)` for
 details.
 
 Probabilistic
   **body:**, **to:**, **attachment:**, **mimetype:**
 Special
-   **from:**, **query:**, **subject:**
+   **from:**, **query:**, **subject:**, **sexp:**
 
 Terms and phrases
 -----------------
 
 will not.
 
+.. _quoting:
+
 Quoting
 -------
 
    % notmuch search 'folder:"/^.*/(Junk|Spam)$/"'
    % notmuch search 'thread:"{from:mallory and date:2009}" and thread:{to:mallory}'
 
+Double quotes within query strings need to be doubled to escape them.
+
+::
+
+   % notmuch search 'tag:"""quoted tag"""'
+   % notmuch search 'sexp:"(or ""wizard"" ""php"")"'
+
 DATE AND TIME SEARCH
 ====================
 
 
        $(dir)/prefix.cc        \
        $(dir)/open.cc          \
        $(dir)/init.cc          \
-       $(dir)/parse-sexp.cc
+       $(dir)/parse-sexp.cc    \
+       $(dir)/sexp-fp.cc
 
 libnotmuch_modules := $(libnotmuch_c_srcs:.c=.o) $(libnotmuch_cxx_srcs:.cc=.o)
 
 
 #include "thread-fp.h"
 #include "regexp-fields.h"
 #include "parse-time-vrp.h"
+#include "sexp-fp.h"
 
 typedef struct {
     const char *name;
       NOTMUCH_FIELD_PROCESSOR },
     { "query",                  NULL,           NOTMUCH_FIELD_EXTERNAL |
       NOTMUCH_FIELD_PROCESSOR },
+    { "sexp",                  NULL,            NOTMUCH_FIELD_EXTERNAL |
+      NOTMUCH_FIELD_PROCESSOR },
     { "from",                   "XFROM",        NOTMUCH_FIELD_EXTERNAL |
       NOTMUCH_FIELD_PROBABILISTIC |
       NOTMUCH_FIELD_PROCESSOR },
            fp = (new QueryFieldProcessor (*notmuch->query_parser, notmuch))->release ();
        else if (STRNCMP_LITERAL (prefix->name, "thread") == 0)
            fp = (new ThreadFieldProcessor (*notmuch->query_parser, notmuch))->release ();
+       else if (STRNCMP_LITERAL (prefix->name, "sexp") == 0)
+           fp = (new SexpFieldProcessor (notmuch))->release ();
        else
            fp = (new RegexpFieldProcessor (prefix->name, prefix->flags,
                                            *notmuch->query_parser, notmuch))->release ();
 
--- /dev/null
+/* sexp-fp.cc - "sexp:" field processor glue
+ *
+ * This file is part of notmuch.
+ *
+ * Copyright © 2022 David Bremner
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see https://www.gnu.org/licenses/ .
+ *
+ * Author: David Bremner <david@tethera.net>
+ */
+
+#include "database-private.h"
+#include "sexp-fp.h"
+#include <iostream>
+
+Xapian::Query
+SexpFieldProcessor::operator() (const std::string & query_string)
+{
+    notmuch_status_t status;
+    Xapian::Query output;
+
+    status = _notmuch_sexp_string_to_xapian_query (notmuch, query_string.c_str (), output);
+    if (status) {
+       throw Xapian::QueryParserError ("error parsing " + query_string);
+    }
+
+    return output;
+
+}
 
--- /dev/null
+/* sexp-fp.h - sexp field processor glue
+ *
+ * This file is part of notmuch.
+ *
+ * Copyright © 2022 David Bremner
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see https://www.gnu.org/licenses/ .
+ *
+ * Author: David Bremner <david@tethera.net>
+ */
+
+#ifndef NOTMUCH_SEXP_FP_H
+#define NOTMUCH_SEXP_FP_H
+
+#include <xapian.h>
+#include "notmuch.h"
+
+class SexpFieldProcessor : public Xapian::FieldProcessor {
+protected:
+    notmuch_database_t *notmuch;
+
+public:
+    SexpFieldProcessor (notmuch_database_t *notmuch_) : notmuch (notmuch_)
+    {
+    };
+
+    Xapian::Query operator() (const std::string & query_string);
+};
+
+#endif /* NOTMUCH_SEXP_FP_H */
 
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
+test_begin_subtest "or of exact terms via field processor"
+notmuch search  'sexp:"(or ""php"" ""wizard"")"' | notmuch_search_sanitize > OUTPUT
+cat <<EOF > EXPECTED
+thread:XXX   2010-12-29 [1/1] François Boulogne; [aur-general] Guidelines: cp, mkdir vs install (inbox unread)
+thread:XXX   2009-11-18 [1/3] Carl Worth| Jan Janak; [notmuch] What a great idea! (inbox unread)
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
 test_begin_subtest "single term in body"
 notmuch search --query=sexp 'wizard' | notmuch_search_sanitize>OUTPUT
 cat <<EOF > EXPECTED
 notmuch search --query=sexp '(property (rx foo=.*))' > OUTPUT
 test_expect_equal_file EXPECTED OUTPUT
 
+test_begin_subtest "regexp 'property' search via field processor"
+notmuch search property:foo=bar > EXPECTED
+notmuch search  'sexp:"(property (rx foo=.*))"' > OUTPUT
+test_expect_equal_file EXPECTED OUTPUT
+
 test_begin_subtest "anchored 'tag' search"
 notmuch search tag:signed > EXPECTED
 notmuch search --query=sexp '(tag (rx ^si))' > OUTPUT
 EOF
 test_expect_equal_file EXPECTED OUTPUT
 
+test_begin_subtest "Compound subquery via field processor"
+notmuch search 'sexp:"(thread (of (from keithp) (subject Maildir)))"' | notmuch_search_sanitize > OUTPUT
+cat<<EOF > EXPECTED
+thread:XXX   2009-11-18 [7/7] Lars Kellogg-Stedman, Mikhail Gusarov, Keith Packard, Carl Worth; [notmuch] Working with Maildir storage? (inbox signed unread)
+EOF
+test_expect_equal_file EXPECTED OUTPUT
+
 test_begin_subtest "empty subquery"
 notmuch search --query=sexp '(thread (of))' 1>OUTPUT 2>&1
 notmuch search '*' > EXPECTED
 notmuch search --output=files --query=sexp '(List *)' | sort | notmuch_dir_sanitize > OUTPUT
 test_expect_equal_file EXPECTED OUTPUT
 
+test_begin_subtest "wildcard search for user header via field processor"
+grep -Ril List-Id ${MAIL_DIR} | sort | notmuch_dir_sanitize > EXPECTED
+notmuch search --output=files  'sexp:"(List *)"' | sort | notmuch_dir_sanitize > OUTPUT
+test_expect_equal_file EXPECTED OUTPUT
+
 test_begin_subtest "wildcard search for user header 2"
 grep -Ril List-Id ${MAIL_DIR} | sort | notmuch_dir_sanitize > EXPECTED
 notmuch search --output=files --query=sexp '(List (starts-with not))' | sort | notmuch_dir_sanitize > OUTPUT