| :mod:`!mailbox` --- Manipulate mailboxes in various formats | |
| =========================================================== | |
| .. module:: mailbox | |
| :synopsis: Manipulate mailboxes in various formats | |
| **Source code:** :source:`Lib/mailbox.py` | |
| -------------- | |
| This module defines two classes, :class:`Mailbox` and :class:`Message`, for | |
| accessing and manipulating on-disk mailboxes and the messages they contain. | |
| :class:`!Mailbox` offers a dictionary-like mapping from keys to messages. | |
| :class:`!Message` extends the :mod:`email.message` module's | |
| :class:`~email.message.Message` class with format-specific state and behavior. | |
| Supported mailbox formats are Maildir, mbox, MH, Babyl, and MMDF. | |
| .. warning:: | |
| The :mod:`!mailbox` module is designed for use in trusted environments, | |
| where data from untrusted sources is never passed to the module's API | |
| calls and only trusted users have access to the filesystems accessible | |
| to the module. | |
| .. seealso:: | |
| Module :mod:`email` | |
| Represent and manipulate messages. | |
| .. _mailbox-objects: | |
| :class:`!Mailbox` objects | |
| ------------------------- | |
| .. class:: Mailbox | |
| A mailbox, which may be inspected and modified. | |
| The :class:`!Mailbox` class defines an interface and is not intended to be | |
| instantiated. Instead, format-specific subclasses should inherit from | |
| :class:`!Mailbox` and your code should instantiate a particular subclass. | |
| The :class:`!Mailbox` interface is dictionary-like, with small keys | |
| corresponding to messages. Keys are issued by the :class:`!Mailbox` instance | |
| with which they will be used and are only meaningful to that :class:`!Mailbox` | |
| instance. A key continues to identify a message even if the corresponding | |
| message is modified, such as by replacing it with another message. | |
| Messages may be added to a :class:`!Mailbox` instance using the set-like | |
| method :meth:`add` and removed using a ``del`` statement or the set-like | |
| methods :meth:`remove` and :meth:`discard`. | |
| :class:`!Mailbox` interface semantics differ from dictionary semantics in some | |
| noteworthy ways. Each time a message is requested, a new representation | |
| (typically a :class:`Message` instance) is generated based upon the current | |
| state of the mailbox. Similarly, when a message is added to a | |
| :class:`!Mailbox` instance, the provided message representation's contents are | |
| copied. In neither case is a reference to the message representation kept by | |
| the :class:`!Mailbox` instance. | |
| The default :class:`!Mailbox` :term:`iterator` iterates over message | |
| representations, not keys as the default :class:`dictionary <dict>` | |
| iterator does. Moreover, modification of a | |
| mailbox during iteration is safe and well-defined. Messages added to the | |
| mailbox after an iterator is created will not be seen by the | |
| iterator. Messages removed from the mailbox before the iterator yields them | |
| will be silently skipped, though using a key from an iterator may result in a | |
| :exc:`KeyError` exception if the corresponding message is subsequently | |
| removed. | |
| .. warning:: | |
| Be very cautious when modifying mailboxes that might be simultaneously | |
| changed by some other process. The safest mailbox format to use for such | |
| tasks is :class:`Maildir`; try to avoid using single-file formats such as | |
| :class:`mbox` for | |
| concurrent writing. If you're modifying a mailbox, you *must* lock it by | |
| calling the :meth:`lock` and :meth:`unlock` methods *before* reading any | |
| messages in the file or making any changes by adding or deleting a | |
| message. Failing to lock the mailbox runs the risk of losing messages or | |
| corrupting the entire mailbox. | |
| The :class:`!Mailbox` class supports the :keyword:`with` statement. When used | |
| as a context manager, :class:`!Mailbox` calls :meth:`lock` when the context is entered, | |
| returns the mailbox object as the context object, and at context end calls :meth:`close`, | |
| thereby releasing the lock. | |
| .. versionchanged:: 3.15 | |
| Support for the :keyword:`with` statement was added. | |
| :class:`!Mailbox` instances have the following methods: | |
| .. method:: add(message) | |
| Add *message* to the mailbox and return the key that has been assigned to | |
| it. | |
| Parameter *message* may be a :class:`Message` instance, an | |
| :class:`email.message.Message` instance, a string, a byte string, or a | |
| file-like object (which should be open in binary mode). If *message* is | |
| an instance of the | |
| appropriate format-specific :class:`Message` subclass (e.g., if it's an | |
| :class:`mboxMessage` instance and this is an :class:`mbox` instance), its | |
| format-specific information is used. Otherwise, reasonable defaults for | |
| format-specific information are used. | |
| .. versionchanged:: 3.2 | |
| Support for binary input was added. | |
| .. method:: remove(key) | |
| __delitem__(key) | |
| discard(key) | |
| Delete the message corresponding to *key* from the mailbox. | |
| If no such message exists, a :exc:`KeyError` exception is raised if the | |
| method was called as :meth:`remove` or :meth:`__delitem__` but no | |
| exception is raised if the method was called as :meth:`discard`. The | |
| behavior of :meth:`discard` may be preferred if the underlying mailbox | |
| format supports concurrent modification by other processes. | |
| .. method:: __setitem__(key, message) | |
| Replace the message corresponding to *key* with *message*. Raise a | |
| :exc:`KeyError` exception if no message already corresponds to *key*. | |
| As with :meth:`add`, parameter *message* may be a :class:`Message` | |
| instance, an :class:`email.message.Message` instance, a string, a byte | |
| string, or a file-like object (which should be open in binary mode). If | |
| *message* is an | |
| instance of the appropriate format-specific :class:`Message` subclass | |
| (e.g., if it's an :class:`mboxMessage` instance and this is an | |
| :class:`mbox` instance), its format-specific information is | |
| used. Otherwise, the format-specific information of the message that | |
| currently corresponds to *key* is left unchanged. | |
| .. method:: iterkeys() | |
| Return an :term:`iterator` over all keys | |
| .. method:: keys() | |
| The same as :meth:`iterkeys`, except that a :class:`list` is returned | |
| rather than an :term:`iterator` | |
| .. method:: itervalues() | |
| __iter__() | |
| Return an :term:`iterator` over representations of all messages. | |
| The messages are represented | |
| as instances of the appropriate format-specific :class:`Message` subclass | |
| unless a custom message factory was specified when the :class:`!Mailbox` | |
| instance was initialized. | |
| .. note:: | |
| The behavior of :meth:`__iter__` is unlike that of dictionaries, which | |
| iterate over keys. | |
| .. method:: values() | |
| The same as :meth:`itervalues`, except that a :class:`list` is returned | |
| rather than an :term:`iterator` | |
| .. method:: iteritems() | |
| Return an :term:`iterator` over (*key*, *message*) pairs, where *key* is | |
| a key and *message* is a message representation. The messages are | |
| represented as instances of the appropriate format-specific | |
| :class:`Message` subclass unless a custom message factory was specified | |
| when the :class:`!Mailbox` instance was initialized. | |
| .. method:: items() | |
| The same as :meth:`iteritems`, except that a :class:`list` of pairs is | |
| returned rather than an :term:`iterator` of pairs. | |
| .. method:: get(key, default=None) | |
| __getitem__(key) | |
| Return a representation of the message corresponding to *key*. If no such | |
| message exists, *default* is returned if the method was called as | |
| :meth:`get` and a :exc:`KeyError` exception is raised if the method was | |
| called as :meth:`!__getitem__`. The message is represented as an instance | |
| of the appropriate format-specific :class:`Message` subclass unless a | |
| custom message factory was specified when the :class:`!Mailbox` instance | |
| was initialized. | |
| .. method:: get_message(key) | |
| Return a representation of the message corresponding to *key* as an | |
| instance of the appropriate format-specific :class:`Message` subclass, or | |
| raise a :exc:`KeyError` exception if no such message exists. | |
| .. method:: get_bytes(key) | |
| Return a byte representation of the message corresponding to *key*, or | |
| raise a :exc:`KeyError` exception if no such message exists. | |
| .. versionadded:: 3.2 | |
| .. method:: get_string(key) | |
| Return a string representation of the message corresponding to *key*, or | |
| raise a :exc:`KeyError` exception if no such message exists. The | |
| message is processed through :class:`email.message.Message` to | |
| convert it to a 7bit clean representation. | |
| .. method:: get_file(key) | |
| Return a :term:`file-like <file-like object>` representation of the | |
| message corresponding to *key*, | |
| or raise a :exc:`KeyError` exception if no such message exists. The | |
| file-like object behaves as if open in binary mode. This file should be | |
| closed once it is no longer needed. | |
| .. versionchanged:: 3.2 | |
| The file object really is a :term:`binary file`; previously it was | |
| incorrectly returned in text mode. Also, the :term:`file-like object` | |
| now supports the :term:`context manager` protocol: you can use a | |
| :keyword:`with` statement to automatically close it. | |
| .. note:: | |
| Unlike other representations of messages, | |
| :term:`file-like <file-like object>` representations are not | |
| necessarily independent of the :class:`!Mailbox` instance that | |
| created them or of the underlying mailbox. More specific documentation | |
| is provided by each subclass. | |
| .. method:: __contains__(key) | |
| Return ``True`` if *key* corresponds to a message, ``False`` otherwise. | |
| .. method:: __len__() | |
| Return a count of messages in the mailbox. | |
| .. method:: clear() | |
| Delete all messages from the mailbox. | |
| .. method:: pop(key, default=None) | |
| Return a representation of the message corresponding to *key* and delete | |
| the message. If no such message exists, return *default*. The message is | |
| represented as an instance of the appropriate format-specific | |
| :class:`Message` subclass unless a custom message factory was specified | |
| when the :class:`!Mailbox` instance was initialized. | |
| .. method:: popitem() | |
| Return an arbitrary (*key*, *message*) pair, where *key* is a key and | |
| *message* is a message representation, and delete the corresponding | |
| message. If the mailbox is empty, raise a :exc:`KeyError` exception. The | |
| message is represented as an instance of the appropriate format-specific | |
| :class:`Message` subclass unless a custom message factory was specified | |
| when the :class:`!Mailbox` instance was initialized. | |
| .. method:: update(arg) | |
| Parameter *arg* should be a *key*-to-*message* mapping or an iterable of | |
| (*key*, *message*) pairs. Updates the mailbox so that, for each given | |
| *key* and *message*, the message corresponding to *key* is set to | |
| *message* as if by using :meth:`__setitem__`. As with :meth:`__setitem__`, | |
| each *key* must already correspond to a message in the mailbox or else a | |
| :exc:`KeyError` exception will be raised, so in general it is incorrect | |
| for *arg* to be a :class:`!Mailbox` instance. | |
| .. note:: | |
| Unlike with dictionaries, keyword arguments are not supported. | |
| .. method:: flush() | |
| Write any pending changes to the filesystem. For some :class:`Mailbox` | |
| subclasses, changes are always written immediately and :meth:`!flush` does | |
| nothing, but you should still make a habit of calling this method. | |
| .. method:: lock() | |
| Acquire an exclusive advisory lock on the mailbox so that other processes | |
| know not to modify it. An :exc:`ExternalClashError` is raised if the lock | |
| is not available. The particular locking mechanisms used depend upon the | |
| mailbox format. You should *always* lock the mailbox before making any | |
| modifications to its contents. | |
| .. method:: unlock() | |
| Release the lock on the mailbox, if any. | |
| .. method:: close() | |
| Flush the mailbox, unlock it if necessary, and close any open files. For | |
| some :class:`!Mailbox` subclasses, this method does nothing. | |
| .. _mailbox-maildir: | |
| :class:`!Maildir` objects | |
| ^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| .. class:: Maildir(dirname, factory=None, create=True) | |
| A subclass of :class:`Mailbox` for mailboxes in Maildir format. Parameter | |
| *factory* is a callable object that accepts a file-like message representation | |
| (which behaves as if opened in binary mode) and returns a custom representation. | |
| If *factory* is ``None``, :class:`MaildirMessage` is used as the default message | |
| representation. If *create* is ``True``, the mailbox is created if it does not | |
| exist. | |
| If *create* is ``True`` and the *dirname* path exists, it will be treated as | |
| an existing maildir without attempting to verify its directory layout. | |
| It is for historical reasons that *dirname* is named as such rather than *path*. | |
| Maildir is a directory-based mailbox format invented for the qmail mail | |
| transfer agent and now widely supported by other programs. Messages in a | |
| Maildir mailbox are stored in separate files within a common directory | |
| structure. This design allows Maildir mailboxes to be accessed and modified | |
| by multiple unrelated programs without data corruption, so file locking is | |
| unnecessary. | |
| Maildir mailboxes contain three subdirectories, namely: :file:`tmp`, | |
| :file:`new`, and :file:`cur`. Messages are created momentarily in the | |
| :file:`tmp` subdirectory and then moved to the :file:`new` subdirectory to | |
| finalize delivery. A mail user agent may subsequently move the message to the | |
| :file:`cur` subdirectory and store information about the state of the message | |
| in a special "info" section appended to its file name. | |
| Folders of the style introduced by the Courier mail transfer agent are also | |
| supported. Any subdirectory of the main mailbox is considered a folder if | |
| ``'.'`` is the first character in its name. Folder names are represented by | |
| :class:`!Maildir` without the leading ``'.'``. Each folder is itself a Maildir | |
| mailbox but should not contain other folders. Instead, a logical nesting is | |
| indicated using ``'.'`` to delimit levels, e.g., "Archived.2005.07". | |
| .. attribute:: Maildir.colon | |
| The Maildir specification requires the use of a colon (``':'``) in certain | |
| message file names. However, some operating systems do not permit this | |
| character in file names, If you wish to use a Maildir-like format on such | |
| an operating system, you should specify another character to use | |
| instead. The exclamation point (``'!'``) is a popular choice. For | |
| example:: | |
| import mailbox | |
| mailbox.Maildir.colon = '!' | |
| The :attr:`!colon` attribute may also be set on a per-instance basis. | |
| .. versionchanged:: 3.13 | |
| :class:`Maildir` now ignores files with a leading dot. | |
| :class:`!Maildir` instances have all of the methods of :class:`Mailbox` in | |
| addition to the following: | |
| .. method:: list_folders() | |
| Return a list of the names of all folders. | |
| .. method:: get_folder(folder) | |
| Return a :class:`!Maildir` instance representing the folder whose name is | |
| *folder*. A :exc:`NoSuchMailboxError` exception is raised if the folder | |
| does not exist. | |
| .. method:: add_folder(folder) | |
| Create a folder whose name is *folder* and return a :class:`!Maildir` | |
| instance representing it. | |
| .. method:: remove_folder(folder) | |
| Delete the folder whose name is *folder*. If the folder contains any | |
| messages, a :exc:`NotEmptyError` exception will be raised and the folder | |
| will not be deleted. | |
| .. method:: clean() | |
| Delete temporary files from the mailbox that have not been accessed in the | |
| last 36 hours. The Maildir specification says that mail-reading programs | |
| should do this occasionally. | |
| .. method:: get_flags(key) | |
| Return as a string the flags that are set on the message | |
| corresponding to *key*. | |
| This is the same as ``get_message(key).get_flags()`` but much | |
| faster, because it does not open the message file. | |
| Use this method when iterating over the keys to determine which | |
| messages are interesting to get. | |
| If you do have a :class:`MaildirMessage` object, use | |
| its :meth:`~MaildirMessage.get_flags` method instead, because | |
| changes made by the message's :meth:`~MaildirMessage.set_flags`, | |
| :meth:`~MaildirMessage.add_flag` and :meth:`~MaildirMessage.remove_flag` | |
| methods are not reflected here until the mailbox's | |
| :meth:`__setitem__` method is called. | |
| .. versionadded:: 3.13 | |
| .. method:: set_flags(key, flags) | |
| On the message corresponding to *key*, set the flags specified | |
| by *flags* and unset all others. | |
| Calling ``some_mailbox.set_flags(key, flags)`` is similar to :: | |
| one_message = some_mailbox.get_message(key) | |
| one_message.set_flags(flags) | |
| some_mailbox[key] = one_message | |
| but faster, because it does not open the message file. | |
| If you do have a :class:`MaildirMessage` object, use | |
| its :meth:`~MaildirMessage.set_flags` method instead, because | |
| changes made with this mailbox method will not be visible to the | |
| message object's method, :meth:`~MaildirMessage.get_flags`. | |
| .. versionadded:: 3.13 | |
| .. method:: add_flag(key, flag) | |
| On the message corresponding to *key*, set the flags specified | |
| by *flag* without changing other flags. To add more than one | |
| flag at a time, *flag* may be a string of more than one character. | |
| Considerations for using this method versus the message object's | |
| :meth:`~MaildirMessage.add_flag` method are similar to | |
| those for :meth:`set_flags`; see the discussion there. | |
| .. versionadded:: 3.13 | |
| .. method:: remove_flag(key, flag) | |
| On the message corresponding to *key*, unset the flags specified | |
| by *flag* without changing other flags. To remove more than one | |
| flag at a time, *flag* may be a string of more than one character. | |
| Considerations for using this method versus the message object's | |
| :meth:`~MaildirMessage.remove_flag` method are similar to | |
| those for :meth:`set_flags`; see the discussion there. | |
| .. versionadded:: 3.13 | |
| .. method:: get_info(key) | |
| Return a string containing the info for the message | |
| corresponding to *key*. | |
| This is the same as ``get_message(key).get_info()`` but much | |
| faster, because it does not open the message file. | |
| Use this method when iterating over the keys to determine which | |
| messages are interesting to get. | |
| If you do have a :class:`MaildirMessage` object, use | |
| its :meth:`~MaildirMessage.get_info` method instead, because | |
| changes made by the message's :meth:`~MaildirMessage.set_info` method | |
| are not reflected here until the mailbox's :meth:`__setitem__` method | |
| is called. | |
| .. versionadded:: 3.13 | |
| .. method:: set_info(key, info) | |
| Set the info of the message corresponding to *key* to *info*. | |
| Calling ``some_mailbox.set_info(key, flags)`` is similar to :: | |
| one_message = some_mailbox.get_message(key) | |
| one_message.set_info(info) | |
| some_mailbox[key] = one_message | |
| but faster, because it does not open the message file. | |
| If you do have a :class:`MaildirMessage` object, use | |
| its :meth:`~MaildirMessage.set_info` method instead, because | |
| changes made with this mailbox method will not be visible to the | |
| message object's method, :meth:`~MaildirMessage.get_info`. | |
| .. versionadded:: 3.13 | |
| Some :class:`Mailbox` methods implemented by :class:`!Maildir` deserve special | |
| remarks: | |
| .. method:: add(message) | |
| __setitem__(key, message) | |
| update(arg) | |
| .. warning:: | |
| These methods generate unique file names based upon the current process | |
| ID. When using multiple threads, undetected name clashes may occur and | |
| cause corruption of the mailbox unless threads are coordinated to avoid | |
| using these methods to manipulate the same mailbox simultaneously. | |
| .. method:: flush() | |
| All changes to Maildir mailboxes are immediately applied, so this method | |
| does nothing. | |
| .. method:: lock() | |
| unlock() | |
| Maildir mailboxes do not support (or require) locking, so these methods do | |
| nothing. | |
| .. method:: close() | |
| :class:`!Maildir` instances do not keep any open files and the underlying | |
| mailboxes do not support locking, so this method does nothing. | |
| .. method:: get_file(key) | |
| Depending upon the host platform, it may not be possible to modify or | |
| remove the underlying message while the returned file remains open. | |
| .. seealso:: | |
| `maildir man page from Courier <https://www.courier-mta.org/maildir.html>`_ | |
| A specification of the format. Describes a common extension for | |
| supporting folders. | |
| `Using maildir format <https://cr.yp.to/proto/maildir.html>`_ | |
| Notes on Maildir by its inventor. Includes an updated name-creation scheme and | |
| details on "info" semantics. | |
| .. _mailbox-mbox: | |
| :class:`!mbox` objects | |
| ^^^^^^^^^^^^^^^^^^^^^^ | |
| .. class:: mbox(path, factory=None, create=True) | |
| A subclass of :class:`Mailbox` for mailboxes in mbox format. Parameter *factory* | |
| is a callable object that accepts a file-like message representation (which | |
| behaves as if opened in binary mode) and returns a custom representation. If | |
| *factory* is ``None``, :class:`mboxMessage` is used as the default message | |
| representation. If *create* is ``True``, the mailbox is created if it does not | |
| exist. | |
| The mbox format is the classic format for storing mail on Unix systems. All | |
| messages in an mbox mailbox are stored in a single file with the beginning of | |
| each message indicated by a line whose first five characters are "From ". | |
| Several variations of the mbox format exist to address perceived shortcomings in | |
| the original. In the interest of compatibility, :class:`!mbox` implements the | |
| original format, which is sometimes referred to as :dfn:`mboxo`. This means that | |
| the :mailheader:`Content-Length` header, if present, is ignored and that any | |
| occurrences of "From " at the beginning of a line in a message body are | |
| transformed to ">From " when storing the message, although occurrences of ">From | |
| " are not transformed to "From " when reading the message. | |
| Some :class:`Mailbox` methods implemented by :class:`!mbox` deserve special | |
| remarks: | |
| .. method:: get_bytes(key, from_=False) | |
| Note: This method has an extra parameter (*from_*) compared with other classes. | |
| The first line of an mbox file entry is the Unix "From " line. | |
| If *from_* is False, the first line of the file is dropped. | |
| .. method:: get_file(key, from_=False) | |
| Using the file after calling :meth:`~Mailbox.flush` or | |
| :meth:`~Mailbox.close` on the :class:`!mbox` instance may yield | |
| unpredictable results or raise an exception. | |
| Note: This method has an extra parameter (*from_*) compared with other classes. | |
| The first line of an mbox file entry is the Unix "From " line. | |
| If *from_* is False, the first line of the file is dropped. | |
| .. method:: get_string(key, from_=False) | |
| Note: This method has an extra parameter (*from_*) compared with other classes. | |
| The first line of an mbox file entry is the Unix "From " line. | |
| If *from_* is False, the first line of the file is dropped. | |
| .. method:: lock() | |
| unlock() | |
| Three locking mechanisms are used---dot locking and, if available, the | |
| :c:func:`!flock` and :c:func:`!lockf` system calls. | |
| .. seealso:: | |
| `mbox man page from tin <http://www.tin.org/bin/man.cgi?section=5&topic=mbox>`_ | |
| A specification of the format, with details on locking. | |
| `Configuring Netscape Mail on Unix: Why The Content-Length Format is Bad <https://www.jwz.org/doc/content-length.html>`_ | |
| An argument for using the original mbox format rather than a variation. | |
| `"mbox" is a family of several mutually incompatible mailbox formats <https://www.loc.gov/preservation/digital/formats/fdd/fdd000383.shtml>`_ | |
| A history of mbox variations. | |
| .. _mailbox-mh: | |
| :class:`!MH` objects | |
| ^^^^^^^^^^^^^^^^^^^^ | |
| .. class:: MH(path, factory=None, create=True) | |
| A subclass of :class:`Mailbox` for mailboxes in MH format. Parameter *factory* | |
| is a callable object that accepts a file-like message representation (which | |
| behaves as if opened in binary mode) and returns a custom representation. If | |
| *factory* is ``None``, :class:`MHMessage` is used as the default message | |
| representation. If *create* is ``True``, the mailbox is created if it does not | |
| exist. | |
| MH is a directory-based mailbox format invented for the MH Message Handling | |
| System, a mail user agent. Each message in an MH mailbox resides in its own | |
| file. An MH mailbox may contain other MH mailboxes (called :dfn:`folders`) in | |
| addition to messages. Folders may be nested indefinitely. MH mailboxes also | |
| support :dfn:`sequences`, which are named lists used to logically group | |
| messages without moving them to sub-folders. Sequences are defined in a file | |
| called :file:`.mh_sequences` in each folder. | |
| The :class:`!MH` class manipulates MH mailboxes, but it does not attempt to | |
| emulate all of :program:`mh`'s behaviors. In particular, it does not modify | |
| and is not affected by the :file:`context` or :file:`.mh_profile` files that | |
| are used by :program:`mh` to store its state and configuration. | |
| :class:`!MH` instances have all of the methods of :class:`Mailbox` in addition | |
| to the following: | |
| .. versionchanged:: 3.13 | |
| Supported folders that don't contain a :file:`.mh_sequences` file. | |
| .. method:: list_folders() | |
| Return a list of the names of all folders. | |
| .. method:: get_folder(folder) | |
| Return an :class:`!MH` instance representing the folder whose name is | |
| *folder*. A :exc:`NoSuchMailboxError` exception is raised if the folder | |
| does not exist. | |
| .. method:: add_folder(folder) | |
| Create a folder whose name is *folder* and return an :class:`!MH` instance | |
| representing it. | |
| .. method:: remove_folder(folder) | |
| Delete the folder whose name is *folder*. If the folder contains any | |
| messages, a :exc:`NotEmptyError` exception will be raised and the folder | |
| will not be deleted. | |
| .. method:: get_sequences() | |
| Return a dictionary of sequence names mapped to key lists. If there are no | |
| sequences, the empty dictionary is returned. | |
| .. method:: set_sequences(sequences) | |
| Re-define the sequences that exist in the mailbox based upon *sequences*, | |
| a dictionary of names mapped to key lists, like returned by | |
| :meth:`get_sequences`. | |
| .. method:: pack() | |
| Rename messages in the mailbox as necessary to eliminate gaps in | |
| numbering. Entries in the sequences list are updated correspondingly. | |
| .. note:: | |
| Already-issued keys are invalidated by this operation and should not be | |
| subsequently used. | |
| Some :class:`Mailbox` methods implemented by :class:`!MH` deserve special | |
| remarks: | |
| .. method:: remove(key) | |
| __delitem__(key) | |
| discard(key) | |
| These methods immediately delete the message. The MH convention of marking | |
| a message for deletion by prepending a comma to its name is not used. | |
| .. method:: lock() | |
| unlock() | |
| Three locking mechanisms are used---dot locking and, if available, the | |
| :c:func:`!flock` and :c:func:`!lockf` system calls. For MH mailboxes, locking | |
| the mailbox means locking the :file:`.mh_sequences` file and, only for the | |
| duration of any operations that affect them, locking individual message | |
| files. | |
| .. method:: get_file(key) | |
| Depending upon the host platform, it may not be possible to remove the | |
| underlying message while the returned file remains open. | |
| .. method:: flush() | |
| All changes to MH mailboxes are immediately applied, so this method does | |
| nothing. | |
| .. method:: close() | |
| :class:`!MH` instances do not keep any open files, so this method is | |
| equivalent to :meth:`unlock`. | |
| .. seealso:: | |
| `nmh - Message Handling System <https://www.nongnu.org/nmh/>`_ | |
| Home page of :program:`nmh`, an updated version of the original :program:`mh`. | |
| `MH & nmh: Email for Users & Programmers <https://rand-mh.sourceforge.io/book/>`_ | |
| A GPL-licensed book on :program:`mh` and :program:`nmh`, with some information | |
| on the mailbox format. | |
| .. _mailbox-babyl: | |
| :class:`!Babyl` objects | |
| ^^^^^^^^^^^^^^^^^^^^^^^ | |
| .. class:: Babyl(path, factory=None, create=True) | |
| A subclass of :class:`Mailbox` for mailboxes in Babyl format. Parameter | |
| *factory* is a callable object that accepts a file-like message representation | |
| (which behaves as if opened in binary mode) and returns a custom representation. | |
| If *factory* is ``None``, :class:`BabylMessage` is used as the default message | |
| representation. If *create* is ``True``, the mailbox is created if it does not | |
| exist. | |
| Babyl is a single-file mailbox format used by the Rmail mail user agent | |
| included with Emacs. The beginning of a message is indicated by a line | |
| containing the two characters Control-Underscore (``'\037'``) and Control-L | |
| (``'\014'``). The end of a message is indicated by the start of the next | |
| message or, in the case of the last message, a line containing a | |
| Control-Underscore (``'\037'``) character. | |
| Messages in a Babyl mailbox have two sets of headers, original headers and | |
| so-called visible headers. Visible headers are typically a subset of the | |
| original headers that have been reformatted or abridged to be more | |
| attractive. Each message in a Babyl mailbox also has an accompanying list of | |
| :dfn:`labels`, or short strings that record extra information about the | |
| message, and a list of all user-defined labels found in the mailbox is kept | |
| in the Babyl options section. | |
| :class:`!Babyl` instances have all of the methods of :class:`Mailbox` in | |
| addition to the following: | |
| .. method:: get_labels() | |
| Return a list of the names of all user-defined labels used in the mailbox. | |
| .. note:: | |
| The actual messages are inspected to determine which labels exist in | |
| the mailbox rather than consulting the list of labels in the Babyl | |
| options section, but the Babyl section is updated whenever the mailbox | |
| is modified. | |
| Some :class:`Mailbox` methods implemented by :class:`!Babyl` deserve special | |
| remarks: | |
| .. method:: get_file(key) | |
| In Babyl mailboxes, the headers of a message are not stored contiguously | |
| with the body of the message. To generate a file-like representation, the | |
| headers and body are copied together into an :class:`io.BytesIO` instance, | |
| which has an API identical to that of a | |
| file. As a result, the file-like object is truly independent of the | |
| underlying mailbox but does not save memory compared to a string | |
| representation. | |
| .. method:: lock() | |
| unlock() | |
| Three locking mechanisms are used---dot locking and, if available, the | |
| :c:func:`!flock` and :c:func:`!lockf` system calls. | |
| .. seealso:: | |
| `Format of Version 5 Babyl Files <https://quimby.gnus.org/notes/BABYL>`_ | |
| A specification of the Babyl format. | |
| `Reading Mail with Rmail <https://www.gnu.org/software/emacs/manual/html_node/emacs/Rmail.html>`_ | |
| The Rmail manual, with some information on Babyl semantics. | |
| .. _mailbox-mmdf: | |
| :class:`!MMDF` objects | |
| ^^^^^^^^^^^^^^^^^^^^^^ | |
| .. class:: MMDF(path, factory=None, create=True) | |
| A subclass of :class:`Mailbox` for mailboxes in MMDF format. Parameter *factory* | |
| is a callable object that accepts a file-like message representation (which | |
| behaves as if opened in binary mode) and returns a custom representation. If | |
| *factory* is ``None``, :class:`MMDFMessage` is used as the default message | |
| representation. If *create* is ``True``, the mailbox is created if it does not | |
| exist. | |
| MMDF is a single-file mailbox format invented for the Multichannel Memorandum | |
| Distribution Facility, a mail transfer agent. Each message is in the same | |
| form as an mbox message but is bracketed before and after by lines containing | |
| four Control-A (``'\001'``) characters. As with the mbox format, the | |
| beginning of each message is indicated by a line whose first five characters | |
| are "From ", but additional occurrences of "From " are not transformed to | |
| ">From " when storing messages because the extra message separator lines | |
| prevent mistaking such occurrences for the starts of subsequent messages. | |
| Some :class:`Mailbox` methods implemented by :class:`!MMDF` deserve special | |
| remarks: | |
| .. method:: get_bytes(key, from_=False) | |
| Note: This method has an extra parameter (*from_*) compared with other classes. | |
| The first line of an mbox file entry is the Unix "From " line. | |
| If *from_* is False, the first line of the file is dropped. | |
| .. method:: get_file(key, from_=False) | |
| Using the file after calling :meth:`~Mailbox.flush` or | |
| :meth:`~Mailbox.close` on the :class:`!MMDF` instance may yield | |
| unpredictable results or raise an exception. | |
| Note: This method has an extra parameter (*from_*) compared with other classes. | |
| The first line of an mbox file entry is the Unix "From " line. | |
| If *from_* is False, the first line of the file is dropped. | |
| .. method:: lock() | |
| unlock() | |
| Three locking mechanisms are used---dot locking and, if available, the | |
| :c:func:`!flock` and :c:func:`!lockf` system calls. | |
| .. seealso:: | |
| `mmdf man page from tin <http://www.tin.org/bin/man.cgi?section=5&topic=mmdf>`_ | |
| A specification of MMDF format from the documentation of tin, a newsreader. | |
| `MMDF <https://en.wikipedia.org/wiki/MMDF>`_ | |
| A Wikipedia article describing the Multichannel Memorandum Distribution | |
| Facility. | |
| .. _mailbox-message-objects: | |
| :class:`!Message` objects | |
| ------------------------- | |
| .. class:: Message(message=None) | |
| A subclass of the :mod:`email.message` module's | |
| :class:`~email.message.Message`. Subclasses of :class:`!mailbox.Message` add | |
| mailbox-format-specific state and behavior. | |
| If *message* is omitted, the new instance is created in a default, empty state. | |
| If *message* is an :class:`email.message.Message` instance, its contents are | |
| copied; furthermore, any format-specific information is converted insofar as | |
| possible if *message* is a :class:`!Message` instance. If *message* is a string, | |
| a byte string, | |
| or a file, it should contain an :rfc:`5322`\ -compliant message, which is read | |
| and parsed. Files should be open in binary mode, but text mode files | |
| are accepted for backward compatibility. | |
| The format-specific state and behaviors offered by subclasses vary, but in | |
| general it is only the properties that are not specific to a particular | |
| mailbox that are supported (although presumably the properties are specific | |
| to a particular mailbox format). For example, file offsets for single-file | |
| mailbox formats and file names for directory-based mailbox formats are not | |
| retained, because they are only applicable to the original mailbox. But state | |
| such as whether a message has been read by the user or marked as important is | |
| retained, because it applies to the message itself. | |
| There is no requirement that :class:`!Message` instances be used to represent | |
| messages retrieved using :class:`Mailbox` instances. In some situations, the | |
| time and memory required to generate :class:`!Message` representations might | |
| not be acceptable. For such situations, :class:`!Mailbox` instances also | |
| offer string and file-like representations, and a custom message factory may | |
| be specified when a :class:`!Mailbox` instance is initialized. | |
| .. _mailbox-maildirmessage: | |
| :class:`!MaildirMessage` objects | |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| .. class:: MaildirMessage(message=None) | |
| A message with Maildir-specific behaviors. Parameter *message* has the same | |
| meaning as with the :class:`Message` constructor. | |
| Typically, a mail user agent application moves all of the messages in the | |
| :file:`new` subdirectory to the :file:`cur` subdirectory after the first time | |
| the user opens and closes the mailbox, recording that the messages are old | |
| whether or not they've actually been read. Each message in :file:`cur` has an | |
| "info" section added to its file name to store information about its state. | |
| (Some mail readers may also add an "info" section to messages in | |
| :file:`new`.) The "info" section may take one of two forms: it may contain | |
| "2," followed by a list of standardized flags (e.g., "2,FR") or it may | |
| contain "1," followed by so-called experimental information. Standard flags | |
| for Maildir messages are as follows: | |
| +------+---------+--------------------------------+ | |
| | Flag | Meaning | Explanation | | |
| +======+=========+================================+ | |
| | D | Draft | Under composition | | |
| +------+---------+--------------------------------+ | |
| | F | Flagged | Marked as important | | |
| +------+---------+--------------------------------+ | |
| | P | Passed | Forwarded, resent, or bounced | | |
| +------+---------+--------------------------------+ | |
| | R | Replied | Replied to | | |
| +------+---------+--------------------------------+ | |
| | S | Seen | Read | | |
| +------+---------+--------------------------------+ | |
| | T | Trashed | Marked for subsequent deletion | | |
| +------+---------+--------------------------------+ | |
| :class:`!MaildirMessage` instances offer the following methods: | |
| .. method:: get_subdir() | |
| Return either "new" (if the message should be stored in the :file:`new` | |
| subdirectory) or "cur" (if the message should be stored in the :file:`cur` | |
| subdirectory). | |
| .. note:: | |
| A message is typically moved from :file:`new` to :file:`cur` after its | |
| mailbox has been accessed, whether or not the message has been | |
| read. A message ``msg`` has been read if ``"S" in msg.get_flags()`` is | |
| ``True``. | |
| .. method:: set_subdir(subdir) | |
| Set the subdirectory the message should be stored in. Parameter *subdir* | |
| must be either "new" or "cur". | |
| .. method:: get_flags() | |
| Return a string specifying the flags that are currently set. If the | |
| message complies with the standard Maildir format, the result is the | |
| concatenation in alphabetical order of zero or one occurrence of each of | |
| ``'D'``, ``'F'``, ``'P'``, ``'R'``, ``'S'``, and ``'T'``. The empty string | |
| is returned if no flags are set or if "info" contains experimental | |
| semantics. | |
| .. method:: set_flags(flags) | |
| Set the flags specified by *flags* and unset all others. | |
| .. method:: add_flag(flag) | |
| Set the flag(s) specified by *flag* without changing other flags. To add | |
| more than one flag at a time, *flag* may be a string of more than one | |
| character. The current "info" is overwritten whether or not it contains | |
| experimental information rather than flags. | |
| .. method:: remove_flag(flag) | |
| Unset the flag(s) specified by *flag* without changing other flags. To | |
| remove more than one flag at a time, *flag* may be a string of more than | |
| one character. If "info" contains experimental information rather than | |
| flags, the current "info" is not modified. | |
| .. method:: get_date() | |
| Return the delivery date of the message as a floating-point number | |
| representing seconds since the epoch. | |
| .. method:: set_date(date) | |
| Set the delivery date of the message to *date*, a floating-point number | |
| representing seconds since the epoch. | |
| .. method:: get_info() | |
| Return a string containing the "info" for a message. This is useful for | |
| accessing and modifying "info" that is experimental (i.e., not a list of | |
| flags). | |
| .. method:: set_info(info) | |
| Set "info" to *info*, which should be a string. | |
| When a :class:`!MaildirMessage` instance is created based upon an | |
| :class:`mboxMessage` or :class:`MMDFMessage` instance, the :mailheader:`Status` | |
| and :mailheader:`X-Status` headers are omitted and the following conversions | |
| take place: | |
| +--------------------+----------------------------------------------+ | |
| | Resulting state | :class:`mboxMessage` or :class:`MMDFMessage` | | |
| | | state | | |
| +====================+==============================================+ | |
| | "cur" subdirectory | O flag | | |
| +--------------------+----------------------------------------------+ | |
| | F flag | F flag | | |
| +--------------------+----------------------------------------------+ | |
| | R flag | A flag | | |
| +--------------------+----------------------------------------------+ | |
| | S flag | R flag | | |
| +--------------------+----------------------------------------------+ | |
| | T flag | D flag | | |
| +--------------------+----------------------------------------------+ | |
| When a :class:`!MaildirMessage` instance is created based upon an | |
| :class:`MHMessage` instance, the following conversions take place: | |
| +-------------------------------+--------------------------+ | |
| | Resulting state | :class:`MHMessage` state | | |
| +===============================+==========================+ | |
| | "cur" subdirectory | "unseen" sequence | | |
| +-------------------------------+--------------------------+ | |
| | "cur" subdirectory and S flag | no "unseen" sequence | | |
| +-------------------------------+--------------------------+ | |
| | F flag | "flagged" sequence | | |
| +-------------------------------+--------------------------+ | |
| | R flag | "replied" sequence | | |
| +-------------------------------+--------------------------+ | |
| When a :class:`!MaildirMessage` instance is created based upon a | |
| :class:`BabylMessage` instance, the following conversions take place: | |
| +-------------------------------+-------------------------------+ | |
| | Resulting state | :class:`BabylMessage` state | | |
| +===============================+===============================+ | |
| | "cur" subdirectory | "unseen" label | | |
| +-------------------------------+-------------------------------+ | |
| | "cur" subdirectory and S flag | no "unseen" label | | |
| +-------------------------------+-------------------------------+ | |
| | P flag | "forwarded" or "resent" label | | |
| +-------------------------------+-------------------------------+ | |
| | R flag | "answered" label | | |
| +-------------------------------+-------------------------------+ | |
| | T flag | "deleted" label | | |
| +-------------------------------+-------------------------------+ | |
| .. _mailbox-mboxmessage: | |
| :class:`!mboxMessage` objects | |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| .. class:: mboxMessage(message=None) | |
| A message with mbox-specific behaviors. Parameter *message* has the same meaning | |
| as with the :class:`Message` constructor. | |
| Messages in an mbox mailbox are stored together in a single file. The | |
| sender's envelope address and the time of delivery are typically stored in a | |
| line beginning with "From " that is used to indicate the start of a message, | |
| though there is considerable variation in the exact format of this data among | |
| mbox implementations. Flags that indicate the state of the message, such as | |
| whether it has been read or marked as important, are typically stored in | |
| :mailheader:`Status` and :mailheader:`X-Status` headers. | |
| Conventional flags for mbox messages are as follows: | |
| +------+----------+--------------------------------+ | |
| | Flag | Meaning | Explanation | | |
| +======+==========+================================+ | |
| | R | Read | Read | | |
| +------+----------+--------------------------------+ | |
| | O | Old | Previously detected by MUA | | |
| +------+----------+--------------------------------+ | |
| | D | Deleted | Marked for subsequent deletion | | |
| +------+----------+--------------------------------+ | |
| | F | Flagged | Marked as important | | |
| +------+----------+--------------------------------+ | |
| | A | Answered | Replied to | | |
| +------+----------+--------------------------------+ | |
| The "R" and "O" flags are stored in the :mailheader:`Status` header, and the | |
| "D", "F", and "A" flags are stored in the :mailheader:`X-Status` header. The | |
| flags and headers typically appear in the order mentioned. | |
| :class:`!mboxMessage` instances offer the following methods: | |
| .. method:: get_from() | |
| Return a string representing the "From " line that marks the start of the | |
| message in an mbox mailbox. The leading "From " and the trailing newline | |
| are excluded. | |
| .. method:: set_from(from_, time_=None) | |
| Set the "From " line to *from_*, which should be specified without a | |
| leading "From " or trailing newline. For convenience, *time_* may be | |
| specified and will be formatted appropriately and appended to *from_*. If | |
| *time_* is specified, it should be a :class:`time.struct_time` instance, a | |
| tuple suitable for passing to :func:`time.strftime`, or ``True`` (to use | |
| :func:`time.gmtime`). | |
| .. method:: get_flags() | |
| Return a string specifying the flags that are currently set. If the | |
| message complies with the conventional format, the result is the | |
| concatenation in the following order of zero or one occurrence of each of | |
| ``'R'``, ``'O'``, ``'D'``, ``'F'``, and ``'A'``. | |
| .. method:: set_flags(flags) | |
| Set the flags specified by *flags* and unset all others. Parameter *flags* | |
| should be the concatenation in any order of zero or more occurrences of | |
| each of ``'R'``, ``'O'``, ``'D'``, ``'F'``, and ``'A'``. | |
| .. method:: add_flag(flag) | |
| Set the flag(s) specified by *flag* without changing other flags. To add | |
| more than one flag at a time, *flag* may be a string of more than one | |
| character. | |
| .. method:: remove_flag(flag) | |
| Unset the flag(s) specified by *flag* without changing other flags. To | |
| remove more than one flag at a time, *flag* may be a string of more than | |
| one character. | |
| When an :class:`!mboxMessage` instance is created based upon a | |
| :class:`MaildirMessage` instance, a "From " line is generated based upon the | |
| :class:`MaildirMessage` instance's delivery date, and the following conversions | |
| take place: | |
| +-----------------+-------------------------------+ | |
| | Resulting state | :class:`MaildirMessage` state | | |
| +=================+===============================+ | |
| | R flag | S flag | | |
| +-----------------+-------------------------------+ | |
| | O flag | "cur" subdirectory | | |
| +-----------------+-------------------------------+ | |
| | D flag | T flag | | |
| +-----------------+-------------------------------+ | |
| | F flag | F flag | | |
| +-----------------+-------------------------------+ | |
| | A flag | R flag | | |
| +-----------------+-------------------------------+ | |
| When an :class:`!mboxMessage` instance is created based upon an | |
| :class:`MHMessage` instance, the following conversions take place: | |
| +-------------------+--------------------------+ | |
| | Resulting state | :class:`MHMessage` state | | |
| +===================+==========================+ | |
| | R flag and O flag | no "unseen" sequence | | |
| +-------------------+--------------------------+ | |
| | O flag | "unseen" sequence | | |
| +-------------------+--------------------------+ | |
| | F flag | "flagged" sequence | | |
| +-------------------+--------------------------+ | |
| | A flag | "replied" sequence | | |
| +-------------------+--------------------------+ | |
| When an :class:`!mboxMessage` instance is created based upon a | |
| :class:`BabylMessage` instance, the following conversions take place: | |
| +-------------------+-----------------------------+ | |
| | Resulting state | :class:`BabylMessage` state | | |
| +===================+=============================+ | |
| | R flag and O flag | no "unseen" label | | |
| +-------------------+-----------------------------+ | |
| | O flag | "unseen" label | | |
| +-------------------+-----------------------------+ | |
| | D flag | "deleted" label | | |
| +-------------------+-----------------------------+ | |
| | A flag | "answered" label | | |
| +-------------------+-----------------------------+ | |
| When a :class:`!mboxMessage` instance is created based upon an | |
| :class:`MMDFMessage` | |
| instance, the "From " line is copied and all flags directly correspond: | |
| +-----------------+----------------------------+ | |
| | Resulting state | :class:`MMDFMessage` state | | |
| +=================+============================+ | |
| | R flag | R flag | | |
| +-----------------+----------------------------+ | |
| | O flag | O flag | | |
| +-----------------+----------------------------+ | |
| | D flag | D flag | | |
| +-----------------+----------------------------+ | |
| | F flag | F flag | | |
| +-----------------+----------------------------+ | |
| | A flag | A flag | | |
| +-----------------+----------------------------+ | |
| .. _mailbox-mhmessage: | |
| :class:`!MHMessage` objects | |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| .. class:: MHMessage(message=None) | |
| A message with MH-specific behaviors. Parameter *message* has the same meaning | |
| as with the :class:`Message` constructor. | |
| MH messages do not support marks or flags in the traditional sense, but they | |
| do support sequences, which are logical groupings of arbitrary messages. Some | |
| mail reading programs (although not the standard :program:`mh` and | |
| :program:`nmh`) use sequences in much the same way flags are used with other | |
| formats, as follows: | |
| +----------+------------------------------------------+ | |
| | Sequence | Explanation | | |
| +==========+==========================================+ | |
| | unseen | Not read, but previously detected by MUA | | |
| +----------+------------------------------------------+ | |
| | replied | Replied to | | |
| +----------+------------------------------------------+ | |
| | flagged | Marked as important | | |
| +----------+------------------------------------------+ | |
| :class:`!MHMessage` instances offer the following methods: | |
| .. method:: get_sequences() | |
| Return a list of the names of sequences that include this message. | |
| .. method:: set_sequences(sequences) | |
| Set the list of sequences that include this message. | |
| .. method:: add_sequence(sequence) | |
| Add *sequence* to the list of sequences that include this message. | |
| .. method:: remove_sequence(sequence) | |
| Remove *sequence* from the list of sequences that include this message. | |
| When an :class:`!MHMessage` instance is created based upon a | |
| :class:`MaildirMessage` instance, the following conversions take place: | |
| +--------------------+-------------------------------+ | |
| | Resulting state | :class:`MaildirMessage` state | | |
| +====================+===============================+ | |
| | "unseen" sequence | no S flag | | |
| +--------------------+-------------------------------+ | |
| | "replied" sequence | R flag | | |
| +--------------------+-------------------------------+ | |
| | "flagged" sequence | F flag | | |
| +--------------------+-------------------------------+ | |
| When an :class:`!MHMessage` instance is created based upon an | |
| :class:`mboxMessage` or :class:`MMDFMessage` instance, the :mailheader:`Status` | |
| and :mailheader:`X-Status` headers are omitted and the following conversions | |
| take place: | |
| +--------------------+----------------------------------------------+ | |
| | Resulting state | :class:`mboxMessage` or :class:`MMDFMessage` | | |
| | | state | | |
| +====================+==============================================+ | |
| | "unseen" sequence | no R flag | | |
| +--------------------+----------------------------------------------+ | |
| | "replied" sequence | A flag | | |
| +--------------------+----------------------------------------------+ | |
| | "flagged" sequence | F flag | | |
| +--------------------+----------------------------------------------+ | |
| When an :class:`!MHMessage` instance is created based upon a | |
| :class:`BabylMessage` instance, the following conversions take place: | |
| +--------------------+-----------------------------+ | |
| | Resulting state | :class:`BabylMessage` state | | |
| +====================+=============================+ | |
| | "unseen" sequence | "unseen" label | | |
| +--------------------+-----------------------------+ | |
| | "replied" sequence | "answered" label | | |
| +--------------------+-----------------------------+ | |
| .. _mailbox-babylmessage: | |
| :class:`!BabylMessage` objects | |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| .. class:: BabylMessage(message=None) | |
| A message with Babyl-specific behaviors. Parameter *message* has the same | |
| meaning as with the :class:`Message` constructor. | |
| Certain message labels, called :dfn:`attributes`, are defined by convention | |
| to have special meanings. The attributes are as follows: | |
| +-----------+------------------------------------------+ | |
| | Label | Explanation | | |
| +===========+==========================================+ | |
| | unseen | Not read, but previously detected by MUA | | |
| +-----------+------------------------------------------+ | |
| | deleted | Marked for subsequent deletion | | |
| +-----------+------------------------------------------+ | |
| | filed | Copied to another file or mailbox | | |
| +-----------+------------------------------------------+ | |
| | answered | Replied to | | |
| +-----------+------------------------------------------+ | |
| | forwarded | Forwarded | | |
| +-----------+------------------------------------------+ | |
| | edited | Modified by the user | | |
| +-----------+------------------------------------------+ | |
| | resent | Resent | | |
| +-----------+------------------------------------------+ | |
| By default, Rmail displays only visible headers. The :class:`!BabylMessage` | |
| class, though, uses the original headers because they are more | |
| complete. Visible headers may be accessed explicitly if desired. | |
| :class:`!BabylMessage` instances offer the following methods: | |
| .. method:: get_labels() | |
| Return a list of labels on the message. | |
| .. method:: set_labels(labels) | |
| Set the list of labels on the message to *labels*. | |
| .. method:: add_label(label) | |
| Add *label* to the list of labels on the message. | |
| .. method:: remove_label(label) | |
| Remove *label* from the list of labels on the message. | |
| .. method:: get_visible() | |
| Return a :class:`Message` instance whose headers are the message's | |
| visible headers and whose body is empty. | |
| .. method:: set_visible(visible) | |
| Set the message's visible headers to be the same as the headers in | |
| *message*. Parameter *visible* should be a :class:`Message` instance, an | |
| :class:`email.message.Message` instance, a string, or a file-like object | |
| (which should be open in text mode). | |
| .. method:: update_visible() | |
| When a :class:`!BabylMessage` instance's original headers are modified, the | |
| visible headers are not automatically modified to correspond. This method | |
| updates the visible headers as follows: each visible header with a | |
| corresponding original header is set to the value of the original header, | |
| each visible header without a corresponding original header is removed, | |
| and any of :mailheader:`Date`, :mailheader:`From`, :mailheader:`Reply-To`, | |
| :mailheader:`To`, :mailheader:`CC`, and :mailheader:`Subject` that are | |
| present in the original headers but not the visible headers are added to | |
| the visible headers. | |
| When a :class:`!BabylMessage` instance is created based upon a | |
| :class:`MaildirMessage` instance, the following conversions take place: | |
| +-------------------+-------------------------------+ | |
| | Resulting state | :class:`MaildirMessage` state | | |
| +===================+===============================+ | |
| | "unseen" label | no S flag | | |
| +-------------------+-------------------------------+ | |
| | "deleted" label | T flag | | |
| +-------------------+-------------------------------+ | |
| | "answered" label | R flag | | |
| +-------------------+-------------------------------+ | |
| | "forwarded" label | P flag | | |
| +-------------------+-------------------------------+ | |
| When a :class:`!BabylMessage` instance is created based upon an | |
| :class:`mboxMessage` or :class:`MMDFMessage` instance, the :mailheader:`Status` | |
| and :mailheader:`X-Status` headers are omitted and the following conversions | |
| take place: | |
| +------------------+----------------------------------------------+ | |
| | Resulting state | :class:`mboxMessage` or :class:`MMDFMessage` | | |
| | | state | | |
| +==================+==============================================+ | |
| | "unseen" label | no R flag | | |
| +------------------+----------------------------------------------+ | |
| | "deleted" label | D flag | | |
| +------------------+----------------------------------------------+ | |
| | "answered" label | A flag | | |
| +------------------+----------------------------------------------+ | |
| When a :class:`!BabylMessage` instance is created based upon an | |
| :class:`MHMessage` instance, the following conversions take place: | |
| +------------------+--------------------------+ | |
| | Resulting state | :class:`MHMessage` state | | |
| +==================+==========================+ | |
| | "unseen" label | "unseen" sequence | | |
| +------------------+--------------------------+ | |
| | "answered" label | "replied" sequence | | |
| +------------------+--------------------------+ | |
| .. _mailbox-mmdfmessage: | |
| :class:`!MMDFMessage` objects | |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| .. class:: MMDFMessage(message=None) | |
| A message with MMDF-specific behaviors. Parameter *message* has the same meaning | |
| as with the :class:`Message` constructor. | |
| As with message in an mbox mailbox, MMDF messages are stored with the | |
| sender's address and the delivery date in an initial line beginning with | |
| "From ". Likewise, flags that indicate the state of the message are | |
| typically stored in :mailheader:`Status` and :mailheader:`X-Status` headers. | |
| Conventional flags for MMDF messages are identical to those of mbox message | |
| and are as follows: | |
| +------+----------+--------------------------------+ | |
| | Flag | Meaning | Explanation | | |
| +======+==========+================================+ | |
| | R | Read | Read | | |
| +------+----------+--------------------------------+ | |
| | O | Old | Previously detected by MUA | | |
| +------+----------+--------------------------------+ | |
| | D | Deleted | Marked for subsequent deletion | | |
| +------+----------+--------------------------------+ | |
| | F | Flagged | Marked as important | | |
| +------+----------+--------------------------------+ | |
| | A | Answered | Replied to | | |
| +------+----------+--------------------------------+ | |
| The "R" and "O" flags are stored in the :mailheader:`Status` header, and the | |
| "D", "F", and "A" flags are stored in the :mailheader:`X-Status` header. The | |
| flags and headers typically appear in the order mentioned. | |
| :class:`!MMDFMessage` instances offer the following methods, which are | |
| identical to those offered by :class:`mboxMessage`: | |
| .. method:: get_from() | |
| Return a string representing the "From " line that marks the start of the | |
| message in an mbox mailbox. The leading "From " and the trailing newline | |
| are excluded. | |
| .. method:: set_from(from_, time_=None) | |
| Set the "From " line to *from_*, which should be specified without a | |
| leading "From " or trailing newline. For convenience, *time_* may be | |
| specified and will be formatted appropriately and appended to *from_*. If | |
| *time_* is specified, it should be a :class:`time.struct_time` instance, a | |
| tuple suitable for passing to :func:`time.strftime`, or ``True`` (to use | |
| :func:`time.gmtime`). | |
| .. method:: get_flags() | |
| Return a string specifying the flags that are currently set. If the | |
| message complies with the conventional format, the result is the | |
| concatenation in the following order of zero or one occurrence of each of | |
| ``'R'``, ``'O'``, ``'D'``, ``'F'``, and ``'A'``. | |
| .. method:: set_flags(flags) | |
| Set the flags specified by *flags* and unset all others. Parameter *flags* | |
| should be the concatenation in any order of zero or more occurrences of | |
| each of ``'R'``, ``'O'``, ``'D'``, ``'F'``, and ``'A'``. | |
| .. method:: add_flag(flag) | |
| Set the flag(s) specified by *flag* without changing other flags. To add | |
| more than one flag at a time, *flag* may be a string of more than one | |
| character. | |
| .. method:: remove_flag(flag) | |
| Unset the flag(s) specified by *flag* without changing other flags. To | |
| remove more than one flag at a time, *flag* may be a string of more than | |
| one character. | |
| When an :class:`!MMDFMessage` instance is created based upon a | |
| :class:`MaildirMessage` instance, a "From " line is generated based upon the | |
| :class:`MaildirMessage` instance's delivery date, and the following conversions | |
| take place: | |
| +-----------------+-------------------------------+ | |
| | Resulting state | :class:`MaildirMessage` state | | |
| +=================+===============================+ | |
| | R flag | S flag | | |
| +-----------------+-------------------------------+ | |
| | O flag | "cur" subdirectory | | |
| +-----------------+-------------------------------+ | |
| | D flag | T flag | | |
| +-----------------+-------------------------------+ | |
| | F flag | F flag | | |
| +-----------------+-------------------------------+ | |
| | A flag | R flag | | |
| +-----------------+-------------------------------+ | |
| When an :class:`!MMDFMessage` instance is created based upon an | |
| :class:`MHMessage` instance, the following conversions take place: | |
| +-------------------+--------------------------+ | |
| | Resulting state | :class:`MHMessage` state | | |
| +===================+==========================+ | |
| | R flag and O flag | no "unseen" sequence | | |
| +-------------------+--------------------------+ | |
| | O flag | "unseen" sequence | | |
| +-------------------+--------------------------+ | |
| | F flag | "flagged" sequence | | |
| +-------------------+--------------------------+ | |
| | A flag | "replied" sequence | | |
| +-------------------+--------------------------+ | |
| When an :class:`!MMDFMessage` instance is created based upon a | |
| :class:`BabylMessage` instance, the following conversions take place: | |
| +-------------------+-----------------------------+ | |
| | Resulting state | :class:`BabylMessage` state | | |
| +===================+=============================+ | |
| | R flag and O flag | no "unseen" label | | |
| +-------------------+-----------------------------+ | |
| | O flag | "unseen" label | | |
| +-------------------+-----------------------------+ | |
| | D flag | "deleted" label | | |
| +-------------------+-----------------------------+ | |
| | A flag | "answered" label | | |
| +-------------------+-----------------------------+ | |
| When an :class:`!MMDFMessage` instance is created based upon an | |
| :class:`mboxMessage` instance, the "From " line is copied and all flags directly | |
| correspond: | |
| +-----------------+----------------------------+ | |
| | Resulting state | :class:`mboxMessage` state | | |
| +=================+============================+ | |
| | R flag | R flag | | |
| +-----------------+----------------------------+ | |
| | O flag | O flag | | |
| +-----------------+----------------------------+ | |
| | D flag | D flag | | |
| +-----------------+----------------------------+ | |
| | F flag | F flag | | |
| +-----------------+----------------------------+ | |
| | A flag | A flag | | |
| +-----------------+----------------------------+ | |
| Exceptions | |
| ---------- | |
| The following exception classes are defined in the :mod:`!mailbox` module: | |
| .. exception:: Error() | |
| The base class for all other module-specific exceptions. | |
| .. exception:: NoSuchMailboxError() | |
| Raised when a mailbox is expected but is not found, such as when instantiating a | |
| :class:`Mailbox` subclass with a path that does not exist (and with the *create* | |
| parameter set to ``False``), or when opening a folder that does not exist. | |
| .. exception:: NotEmptyError() | |
| Raised when a mailbox is not empty but is expected to be, such as when deleting | |
| a folder that contains messages. | |
| .. exception:: ExternalClashError() | |
| Raised when some mailbox-related condition beyond the control of the program | |
| causes it to be unable to proceed, such as when failing to acquire a lock that | |
| another program already holds, or when a uniquely generated file name | |
| already exists. | |
| .. exception:: FormatError() | |
| Raised when the data in a file cannot be parsed, such as when an :class:`MH` | |
| instance attempts to read a corrupted :file:`.mh_sequences` file. | |
| .. _mailbox-examples: | |
| Examples | |
| -------- | |
| A simple example of printing the subjects of all messages in a mailbox that seem | |
| interesting:: | |
| import mailbox | |
| for message in mailbox.mbox('~/mbox'): | |
| subject = message['subject'] # Could possibly be None. | |
| if subject and 'python' in subject.lower(): | |
| print(subject) | |
| To copy all mail from a Babyl mailbox to an MH mailbox, converting all of the | |
| format-specific information that can be converted:: | |
| import mailbox | |
| destination = mailbox.MH('~/Mail') | |
| destination.lock() | |
| for message in mailbox.Babyl('~/RMAIL'): | |
| destination.add(mailbox.MHMessage(message)) | |
| destination.flush() | |
| destination.unlock() | |
| This example sorts mail from several mailing lists into different mailboxes, | |
| being careful to avoid mail corruption due to concurrent modification by other | |
| programs, mail loss due to interruption of the program, or premature termination | |
| due to malformed messages in the mailbox:: | |
| import mailbox | |
| import email.errors | |
| list_names = ('python-list', 'python-dev', 'python-bugs') | |
| boxes = {name: mailbox.mbox('~/email/%s' % name) for name in list_names} | |
| inbox = mailbox.Maildir('~/Maildir', factory=None) | |
| for key in inbox.iterkeys(): | |
| try: | |
| message = inbox[key] | |
| except email.errors.MessageParseError: | |
| continue # The message is malformed. Just leave it. | |
| for name in list_names: | |
| list_id = message['list-id'] | |
| if list_id and name in list_id: | |
| # Get mailbox to use | |
| box = boxes[name] | |
| # Write copy to disk before removing original. | |
| # If there's a crash, you might duplicate a message, but | |
| # that's better than losing a message completely. | |
| box.lock() | |
| box.add(message) | |
| box.flush() | |
| box.unlock() | |
| # Remove original message | |
| inbox.lock() | |
| inbox.discard(key) | |
| inbox.flush() | |
| inbox.unlock() | |
| break # Found destination, so stop looking. | |
| for box in boxes.itervalues(): | |
| box.close() | |