@@ -217,6 +217,62 @@ of message numbers (``'2:4'``), or a group of non-contiguous ranges separated by
217217commas (``'1:3,6:9' ``). A range can contain an asterisk to indicate an infinite
218218upper bound (``'3:*' ``).
219219
220+ It may also be given in a structured form:
221+ an integer,
222+ or a sequence whose items are integers,
223+ ``(start, stop) `` range tuples (where ``None `` or ``'*' `` stands for the last
224+ message),
225+ or :class: `range ` objects.
226+ For example, ``[1, (3, 5), 8] `` and ``[range(1, 6), 8] `` are both equivalent to
227+ ``'1,3:5,8' ``.
228+
229+ .. versionchanged :: next
230+ Added support for the structured *message_set *.
231+
232+ Arguments that are parenthesized lists of atoms ---
233+ such as the *flag_list * argument of :meth: `~IMAP4.store ` and the *flags *
234+ argument of :meth: `~IMAP4.append `,
235+ the *names * argument of :meth: `~IMAP4.status `,
236+ the *sort_criteria * argument of :meth: `~IMAP4.sort `,
237+ or the *message_parts * argument of :meth: `~IMAP4.fetch ` ---
238+ can be passed as a sequence of strings instead of a preformatted string.
239+ For example, ``[r'\Seen', r'\Answered'] `` is sent as ``(\Seen \Answered) ``.
240+
241+ .. versionchanged :: next
242+ Added support for passing these arguments as a sequence.
243+
244+ .. _imap4-params :
245+
246+ The value-bearing arguments of the search and fetch commands must otherwise be
247+ quoted by hand.
248+ Instead, they may contain ``? `` placeholders that are substituted, and quoted
249+ as required, from a *params * keyword argument,
250+ in the manner of :mod: `sqlite3 ` parameter substitution::
251+
252+ # SEARCH FROM me@example.com SUBJECT "trip report"
253+ M.search(None, 'FROM ? SUBJECT ?', params=['me@example.com', 'trip report'])
254+
255+ # FETCH 1:5 (FLAGS BODY[HEADER.FIELDS (DATE FROM)])
256+ M.fetch('1:5', 'FLAGS BODY[HEADER.FIELDS ?]', params=[['DATE', 'FROM']])
257+
258+ The placeholders are:
259+
260+ * ``? `` --- an astring: a string (quoted if necessary), an integer, or a
261+ list of them (sent as a parenthesized list);
262+ * ``?f `` --- a flag or a list of flags, sent verbatim without quoting;
263+ * ``?s `` --- a *message_set * in the structured form described above.
264+
265+ ``?? `` stands for a literal ``? ``.
266+
267+ Substitution is only performed when *params * is given,
268+ so an existing call that contains a literal ``? `` is unaffected.
269+ The *params * keyword is accepted by :meth: `~IMAP4.search `,
270+ :meth: `~IMAP4.fetch `, :meth: `~IMAP4.sort `, :meth: `~IMAP4.thread ` and
271+ :meth: `~IMAP4.uid `.
272+
273+ .. versionadded :: next
274+ The *params * keyword argument.
275+
220276An :class: `IMAP4 ` instance has the following methods:
221277
222278
@@ -324,7 +380,7 @@ An :class:`IMAP4` instance has the following methods:
324380 Added the *message_set * and *uid * parameters.
325381
326382
327- .. method :: IMAP4.fetch(message_set, message_parts, *, uid=False)
383+ .. method :: IMAP4.fetch(message_set, message_parts, *, uid=False, params=None )
328384
329385 Fetch (parts of) messages. *message_parts * should be a string of message part
330386 names enclosed within parentheses, eg: ``"(UID BODY[TEXT])" ``. Returned data
@@ -333,8 +389,11 @@ An :class:`IMAP4` instance has the following methods:
333389 If *uid * is true, *message_set * is a set of UIDs and the message numbers in
334390 the response are UIDs (``UID FETCH ``).
335391
392+ If *params * is given, ``? `` placeholders in *message_parts * are substituted
393+ with the quoted parameters (see :ref: `the placeholders <imap4-params >`).
394+
336395 .. versionchanged :: next
337- Added the *uid * parameter .
396+ Added the *params * and * uid * parameters .
338397
339398
340399.. method :: IMAP4.getacl(mailbox)
@@ -598,7 +657,7 @@ An :class:`IMAP4` instance has the following methods:
598657 code, instead of the usual type.
599658
600659
601- .. method :: IMAP4.search(charset, criterion[, ...], *, uid=False)
660+ .. method :: IMAP4.search(charset, criterion[, ...], *, uid=False, params=None )
602661
603662 Search mailbox for matching messages. *charset * may be ``None ``, in which case
604663 no ``CHARSET `` will be specified in the request to the server. The IMAP
@@ -617,18 +676,22 @@ An :class:`IMAP4` instance has the following methods:
617676 When *charset * is ``None `` (as it must be under ``UTF8=ACCEPT ``),
618677 the criterion is sent using the connection's encoding instead.
619678
679+ If *params * is given, ``? `` placeholders in the criteria are substituted
680+ with the quoted parameters (see :ref: `the placeholders <imap4-params >`).
681+
620682 Example::
621683
622684 # M is a connected IMAP4 instance...
623- typ, msgnums = M.search(None, 'FROM', '"LDJ "')
685+ typ, msgnums = M.search(None, 'FROM', '"John Smith "')
624686
625687 # or:
626- typ, msgnums = M.search(None, '(FROM "LDJ ")')
688+ typ, msgnums = M.search(None, '(FROM "John Smith ")')
627689
628- .. versionchanged :: next
629- Added the * uid * parameter.
690+ # or, letting the module quote the value:
691+ typ, msgnums = M.search(None, 'FROM ?', params=['John Smith'])
630692
631693 .. versionchanged :: next
694+ Added the *params * and *uid * parameters.
632695 ``str `` search criteria are encoded to *charset *.
633696
634697
@@ -675,7 +738,7 @@ An :class:`IMAP4` instance has the following methods:
675738 Returns socket instance used to connect to server.
676739
677740
678- .. method :: IMAP4.sort(sort_criteria, charset, search_criterion[, ...], *, uid=False)
741+ .. method :: IMAP4.sort(sort_criteria, charset, search_criterion[, ...], *, uid=False, params=None )
679742
680743 The ``sort `` command is a variant of ``search `` with sorting semantics for the
681744 results. Returned data contains a space separated list of matching message
@@ -696,12 +759,13 @@ An :class:`IMAP4` instance has the following methods:
696759 a *search_criterion * passed as :class: `str ` is encoded to *charset *;
697760 pass :class: `bytes ` to send one already encoded.
698761
699- This is an ``IMAP4rev1 `` extension command.
762+ If *params * is given, ``? `` placeholders in the search criteria are
763+ substituted with the quoted parameters (see :ref: `the placeholders <imap4-params >`).
700764
701- .. versionchanged :: next
702- Added the *uid * parameter.
765+ This is an ``IMAP4rev1 `` extension command.
703766
704767 .. versionchanged :: next
768+ Added the *params * and *uid * parameters.
705769 ``str `` search criteria are encoded to *charset *.
706770
707771
@@ -745,7 +809,7 @@ An :class:`IMAP4` instance has the following methods:
745809
746810 typ, data = M.search(None, 'ALL')
747811 for num in data[0].split():
748- M.store(num, '+FLAGS', '\ \Deleted')
812+ M.store(num, '+FLAGS', r' \Deleted')
749813 M.expunge()
750814
751815 .. note ::
@@ -768,7 +832,7 @@ An :class:`IMAP4` instance has the following methods:
768832 Subscribe to new mailbox.
769833
770834
771- .. method :: IMAP4.thread(threading_algorithm, charset, search_criterion[, ...], *, uid=False)
835+ .. method :: IMAP4.thread(threading_algorithm, charset, search_criterion[, ...], *, uid=False, params=None )
772836
773837 The ``thread `` command is a variant of ``search `` with threading semantics for
774838 the results. Returned data contains a space separated list of thread members.
@@ -793,22 +857,30 @@ An :class:`IMAP4` instance has the following methods:
793857 a *search_criterion * passed as :class: `str ` is encoded to *charset *;
794858 pass :class: `bytes ` to send one already encoded.
795859
796- This is an ``IMAP4rev1 `` extension command.
860+ If *params * is given, ``? `` placeholders in the search criteria are
861+ substituted with the quoted parameters (see :ref: `the placeholders <imap4-params >`).
797862
798- .. versionchanged :: next
799- Added the *uid * parameter.
863+ This is an ``IMAP4rev1 `` extension command.
800864
801865 .. versionchanged :: next
866+ Added the *params * and *uid * parameters.
802867 ``str `` search criteria are encoded to *charset *.
803868
804869
805- .. method :: IMAP4.uid(command, arg[, ...])
870+ .. method :: IMAP4.uid(command, arg[, ...], *, params=None )
806871
807872 Execute command args with messages identified by UID, rather than message
808873 number. Returns response appropriate to command. At least one argument must be
809874 supplied; if none are provided, the server will return an error and an exception
810875 will be raised.
811876
877+ If *params * is given, ``? `` placeholders in the ``SEARCH ``, ``SORT `` and
878+ ``THREAD `` criteria or in the ``FETCH `` parts are substituted with the quoted
879+ parameters (see :ref: `the placeholders <imap4-params >`).
880+
881+ .. versionchanged :: next
882+ Added the *params * parameter.
883+
812884
813885.. method :: IMAP4.unsubscribe(mailbox)
814886
0 commit comments