Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 54 additions & 8 deletions Doc/library/imaplib.rst
Original file line number Diff line number Diff line change
Expand Up @@ -273,10 +273,16 @@ An :class:`IMAP4` instance has the following methods:
mailbox. This is the recommended command before ``LOGOUT``.


.. method:: IMAP4.copy(message_set, new_mailbox)
.. method:: IMAP4.copy(message_set, new_mailbox, *, uid=False)

Copy *message_set* messages onto end of *new_mailbox*.

If *uid* is true, *message_set* is a set of UIDs and the ``UID COPY``
command is used instead of ``COPY``.

.. versionchanged:: next
Added the *uid* parameter.


.. method:: IMAP4.create(mailbox)

Expand All @@ -303,19 +309,33 @@ An :class:`IMAP4` instance has the following methods:
The :meth:`enable` method itself, and :RFC:`6855` support.


.. method:: IMAP4.expunge()
.. method:: IMAP4.expunge(message_set=None, *, uid=False)

Permanently remove deleted items from selected mailbox. Generates an ``EXPUNGE``
response for each deleted message. Returned data contains a list of ``EXPUNGE``
message numbers in order received.

If *uid* is true, the ``UID EXPUNGE`` command (:rfc:`4315`) is used to remove
only the messages that both are marked as deleted and have a UID in
*message_set*. *message_set* is required in this case, and must be omitted
otherwise.

.. versionchanged:: next
Added the *message_set* and *uid* parameters.


.. method:: IMAP4.fetch(message_set, message_parts)
.. method:: IMAP4.fetch(message_set, message_parts, *, uid=False)

Fetch (parts of) messages. *message_parts* should be a string of message part
names enclosed within parentheses, eg: ``"(UID BODY[TEXT])"``. Returned data
are tuples of message part envelope and data.

If *uid* is true, *message_set* is a set of UIDs and the message numbers in
the response are UIDs (``UID FETCH``).

.. versionchanged:: next
Added the *uid* parameter.


.. method:: IMAP4.getacl(mailbox)

Expand Down Expand Up @@ -495,12 +515,15 @@ An :class:`IMAP4` instance has the following methods:
Returned data are tuples of message part envelope and data.


.. method:: IMAP4.move(message_set, new_mailbox)
.. method:: IMAP4.move(message_set, new_mailbox, *, uid=False)

Move *message_set* messages onto end of *new_mailbox*.

The server must support the ``MOVE`` capability (:rfc:`6851`).

If *uid* is true, *message_set* is a set of UIDs and the ``UID MOVE``
command is used instead of ``MOVE``.

.. versionadded:: next


Expand Down Expand Up @@ -575,7 +598,7 @@ An :class:`IMAP4` instance has the following methods:
code, instead of the usual type.


.. method:: IMAP4.search(charset, criterion[, ...])
.. method:: IMAP4.search(charset, criterion[, ...], *, uid=False)

Search mailbox for matching messages. *charset* may be ``None``, in which case
no ``CHARSET`` will be specified in the request to the server. The IMAP
Expand All @@ -584,6 +607,9 @@ An :class:`IMAP4` instance has the following methods:
the ``UTF8=ACCEPT`` capability was enabled using the :meth:`enable`
command.

If *uid* is true, the message numbers in the response are UIDs
(``UID SEARCH``).

Example::

# M is a connected IMAP4 instance...
Expand All @@ -592,6 +618,9 @@ An :class:`IMAP4` instance has the following methods:
# or:
typ, msgnums = M.search(None, '(FROM "LDJ")')

.. versionchanged:: next
Added the *uid* parameter.


.. method:: IMAP4.select(mailbox='INBOX', readonly=False)

Expand Down Expand Up @@ -636,7 +665,7 @@ An :class:`IMAP4` instance has the following methods:
Returns socket instance used to connect to server.


.. method:: IMAP4.sort(sort_criteria, charset, search_criterion[, ...])
.. method:: IMAP4.sort(sort_criteria, charset, search_criterion[, ...], *, uid=False)

The ``sort`` command is a variant of ``search`` with sorting semantics for the
results. Returned data contains a space separated list of matching message
Expand All @@ -651,8 +680,13 @@ An :class:`IMAP4` instance has the following methods:
the interpretation of strings in the searching criteria. It then returns the
numbers of matching messages.

If *uid* is true, the message numbers in the response are UIDs (``UID SORT``).

This is an ``IMAP4rev1`` extension command.

.. versionchanged:: next
Added the *uid* parameter.


.. method:: IMAP4.starttls(ssl_context=None)

Expand Down Expand Up @@ -681,12 +715,15 @@ An :class:`IMAP4` instance has the following methods:
Request named status conditions for *mailbox*.


.. method:: IMAP4.store(message_set, command, flag_list)
.. method:: IMAP4.store(message_set, command, flag_list, *, uid=False)

Alters flag dispositions for messages in mailbox. *command* is specified by
section 6.4.6 of :rfc:`3501` as being one of "FLAGS", "+FLAGS", or "-FLAGS",
optionally with a suffix of ".SILENT".

If *uid* is true, *message_set* is a set of UIDs and the ``UID STORE``
command is used instead of ``STORE``.

For example, to set the delete flag on all messages::

typ, data = M.search(None, 'ALL')
Expand All @@ -706,12 +743,15 @@ An :class:`IMAP4` instance has the following methods:
Python 3.6, handles them if they are sent from the server, since this
improves real-world compatibility.

.. versionchanged:: next
Added the *uid* parameter.

.. method:: IMAP4.subscribe(mailbox)

Subscribe to new mailbox.


.. method:: IMAP4.thread(threading_algorithm, charset, search_criterion[, ...])
.. method:: IMAP4.thread(threading_algorithm, charset, search_criterion[, ...], *, uid=False)

The ``thread`` command is a variant of ``search`` with threading semantics for
the results. Returned data contains a space separated list of thread members.
Expand All @@ -729,8 +769,14 @@ An :class:`IMAP4` instance has the following methods:
returns the matching messages threaded according to the specified threading
algorithm.

If *uid* is true, the message numbers in the response are UIDs
(``UID THREAD``).

This is an ``IMAP4rev1`` extension command.

.. versionchanged:: next
Added the *uid* parameter.


.. method:: IMAP4.uid(command, arg[, ...])

Expand Down
9 changes: 9 additions & 0 deletions Doc/whatsnew/3.16.rst
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,15 @@ imaplib
as ordinary :class:`str`.
(Contributed by Serhiy Storchaka in :gh:`49555`.)

* The :meth:`~imaplib.IMAP4.copy`, :meth:`~imaplib.IMAP4.move`,
:meth:`~imaplib.IMAP4.fetch`, :meth:`~imaplib.IMAP4.store`,
:meth:`~imaplib.IMAP4.search`, :meth:`~imaplib.IMAP4.sort`,
:meth:`~imaplib.IMAP4.thread` and :meth:`~imaplib.IMAP4.expunge` methods
now accept a keyword-only *uid* argument that selects the corresponding
``UID`` command, as a more convenient alternative to
:meth:`~imaplib.IMAP4.uid`.
(Contributed by Serhiy Storchaka in :gh:`153502`.)


ipaddress
---------
Expand Down
100 changes: 76 additions & 24 deletions Lib/imaplib.py
Original file line number Diff line number Diff line change
Expand Up @@ -590,13 +590,17 @@ def close(self):
return typ, dat


def copy(self, message_set, new_mailbox):
def copy(self, message_set, new_mailbox, *, uid=False):
"""Copy 'message_set' messages onto end of 'new_mailbox'.

(typ, [data]) = <instance>.copy(message_set, new_mailbox)

If 'uid' is true, 'message_set' is a set of UIDs (UID COPY).
"""
return self._simple_command('COPY', self._sequence_set(message_set),
self._mailbox(new_mailbox))
args = (self._sequence_set(message_set), self._mailbox(new_mailbox))
if uid:
return self._simple_command('UID', self._atom('COPY'), *args)
return self._simple_command('COPY', *args)


def create(self, mailbox):
Expand Down Expand Up @@ -634,21 +638,34 @@ def enable(self, capability):
self._mode_utf8()
return typ, data

def expunge(self):
def expunge(self, message_set=None, *, uid=False):
"""Permanently remove deleted items from selected mailbox.

Generates 'EXPUNGE' response for each deleted message.

(typ, [data]) = <instance>.expunge()

'data' is list of 'EXPUNGE'd message numbers in order received.

If 'uid' is true, only messages with a UID in 'message_set' are
removed (UID EXPUNGE, RFC 4315); 'message_set' is then required and
must be omitted otherwise.
"""
name = 'EXPUNGE'
typ, dat = self._simple_command(name)
if uid:
if message_set is None:
raise self.error('UID EXPUNGE requires a message set')
typ, dat = self._simple_command('UID', self._atom(name),
self._sequence_set(message_set))
else:
if message_set is not None:
raise self.error('EXPUNGE takes no message set; '
'use uid=True for UID EXPUNGE')
typ, dat = self._simple_command(name)
return self._untagged_response(typ, dat, name)


def fetch(self, message_set, message_parts):
def fetch(self, message_set, message_parts, *, uid=False):
"""Fetch (parts of) messages.

(typ, [data, ...]) = <instance>.fetch(message_set, message_parts)
Expand All @@ -657,10 +674,17 @@ def fetch(self, message_set, message_parts):
enclosed in parentheses, eg: "(UID BODY[TEXT])".

'data' are tuples of message part envelope and data.

If 'uid' is true, 'message_set' is a set of UIDs and the message
numbers in the response are UIDs (UID FETCH).
"""
name = 'FETCH'
typ, dat = self._simple_command(name, self._sequence_set(message_set),
self._fetch_parts(message_parts))
args = (self._sequence_set(message_set),
self._fetch_parts(message_parts))
if uid:
typ, dat = self._simple_command('UID', self._atom(name), *args)
else:
typ, dat = self._simple_command(name, *args)
return self._untagged_response(typ, dat, name)


Expand Down Expand Up @@ -842,13 +866,17 @@ def lsub(self, directory='', pattern='*'):
self._list_mailbox(pattern))
return self._untagged_response(typ, dat, name)

def move(self, message_set, new_mailbox):
def move(self, message_set, new_mailbox, *, uid=False):
"""Move 'message_set' messages onto end of 'new_mailbox'.

(typ, [data]) = <instance>.move(message_set, new_mailbox)

If 'uid' is true, 'message_set' is a set of UIDs (UID MOVE).
"""
return self._simple_command('MOVE', self._sequence_set(message_set),
self._mailbox(new_mailbox))
args = (self._sequence_set(message_set), self._mailbox(new_mailbox))
if uid:
return self._simple_command('UID', self._atom('MOVE'), *args)
return self._simple_command('MOVE', *args)

def myrights(self, mailbox):
"""Show my ACLs for a mailbox (i.e. the rights that I have on mailbox).
Expand Down Expand Up @@ -913,22 +941,27 @@ def rename(self, oldmailbox, newmailbox):
self._mailbox(newmailbox))


def search(self, charset, *criteria):
def search(self, charset, *criteria, uid=False):
"""Search mailbox for matching messages.

(typ, [data]) = <instance>.search(charset, criterion, ...)

'data' is space separated list of matching message numbers.
If UTF8 is enabled, charset MUST be None.
If 'uid' is true, the message numbers in the response are UIDs
(UID SEARCH).
"""
name = 'SEARCH'
if charset is not None:
if self.utf8_enabled:
raise IMAP4.error("Non-None charset not valid in UTF8 mode")
typ, dat = self._simple_command(name,
'CHARSET', self._astring(charset), *criteria)
args = ('CHARSET', self._astring(charset), *criteria)
else:
typ, dat = self._simple_command(name, *criteria)
args = criteria
if uid:
typ, dat = self._simple_command('UID', self._atom(name), *args)
else:
typ, dat = self._simple_command(name, *args)
return self._untagged_response(typ, dat, name)


Expand Down Expand Up @@ -991,18 +1024,25 @@ def setquota(self, root, limits):
return self._untagged_response(typ, dat, 'QUOTA')


def sort(self, sort_criteria, charset, *search_criteria):
def sort(self, sort_criteria, charset, *search_criteria, uid=False):
"""IMAP4rev1 extension SORT command.

(typ, [data]) = <instance>.sort(sort_criteria, charset, search_criteria, ...)

If 'uid' is true, the message numbers in the response are UIDs
(UID SORT).
"""
name = 'SORT'
#if not name in self.capabilities: # Let the server decide!
# raise self.error('unimplemented extension command: %s' % name)
sort_criteria = self._set_quote(sort_criteria)
if charset is not None:
charset = self._astring(charset)
typ, dat = self._simple_command(name, sort_criteria, charset, *search_criteria)
args = (sort_criteria, charset, *search_criteria)
if uid:
typ, dat = self._simple_command('UID', self._atom(name), *args)
else:
typ, dat = self._simple_command(name, *args)
return self._untagged_response(typ, dat, name)


Expand Down Expand Up @@ -1043,14 +1083,20 @@ def status(self, mailbox, names):
return self._untagged_response(typ, dat, name)


def store(self, message_set, command, flags):
def store(self, message_set, command, flags, *, uid=False):
"""Alters flag dispositions for messages in mailbox.

(typ, [data]) = <instance>.store(message_set, command, flags)

If 'uid' is true, 'message_set' is a set of UIDs (UID STORE).
"""
flags = self._set_quote(flags)
typ, dat = self._simple_command('STORE', self._sequence_set(message_set),
command, flags)
name = 'STORE'
args = (self._sequence_set(message_set), command,
self._set_quote(flags))
if uid:
typ, dat = self._simple_command('UID', self._atom(name), *args)
else:
typ, dat = self._simple_command(name, *args)
return self._untagged_response(typ, dat, 'FETCH')


Expand All @@ -1062,16 +1108,22 @@ def subscribe(self, mailbox):
return self._simple_command('SUBSCRIBE', self._mailbox(mailbox))


def thread(self, threading_algorithm, charset, *search_criteria):
def thread(self, threading_algorithm, charset, *search_criteria, uid=False):
"""IMAPrev1 extension THREAD command.

(type, [data]) = <instance>.thread(threading_algorithm, charset, search_criteria, ...)

If 'uid' is true, the message numbers in the response are UIDs
(UID THREAD).
"""
name = 'THREAD'
if charset is not None:
charset = self._astring(charset)
typ, dat = self._simple_command(name, self._atom(threading_algorithm),
charset, *search_criteria)
args = (self._atom(threading_algorithm), charset, *search_criteria)
if uid:
typ, dat = self._simple_command('UID', self._atom(name), *args)
else:
typ, dat = self._simple_command(name, *args)
return self._untagged_response(typ, dat, name)


Expand Down
Loading
Loading