.. This module does not use cog because of the IMAP server requirements. ##################################### imaplib - IMAP4 client library ##################################### .. module:: imaplib :synopsis: IMAP4 client library :Purpose: Client library for IMAP4 communication. :Available In: 1.5.2 and later :mod:`imaplib` implements a client for communicating with Internet Message Access Protocol (IMAP) version 4 servers. The IMAP protocol defines a set of *commands* sent to the server and the responses delivered back to the client. Most of the commands are available as methods of the :class:`IMAP4` object used to communicate with the server. These examples discuss part of the IMAP protocol, but are by no means complete. Refer to :rfc:`3501` for complete details. Variations ========== There are 3 client classes for communicating with servers using various mechanisms. The first, :class:`IMAP4`, uses clear text sockets; :class:`IMAP4_SSL` uses encrypted communication over SSL sockets; and :class:`IMAP4_stream` uses the standard input and standard output of an external command. All of the examples below will use :class:`IMAP4_SSL`. Connecting to a Server ====================== There are two steps for establishing a connection with an IMAP server. First, set up the socket connection itself. Second, authenticate as a user with an account on the server. The following example code will read server and user information from a configuration file. .. warning:: You probably do not want to store email passwords in clear text, but handling encryption will distract from the rest of the examples. .. include:: imaplib_connect.py :literal: :start-after: #end_pymotw_header When run, :func:`open_connection()` reads the configuration information from a file in your home directory, then opens the :class:`IMAP4_SSL` connection and authenticates. :: $ python imaplib_connect.py Connecting to mail.example.com Logging in as example .. note:: The other examples below will reuse this module, to avoid duplicating the code. Authentication Failure ---------------------- If the connection is established but authentication fails, an exception is raised. .. include:: imaplib_connect_fail.py :literal: :start-after: #end_pymotw_header :: $ python imaplib_connect_fail.py Connecting to mail.example.com Logging in as example Traceback (most recent call last): File "/Users/dhellmann/Documents/PyMOTW/in_progress/imaplib/PyMOTW/imaplib/imaplib_connect_fail.py", line 29, in connection.login(username, password) File "/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/imaplib.py", line 501, in login raise self.error(dat[-1]) imaplib.error: Authentication failed. Example Configuration ===================== The example account has 4 mailboxes, ``INBOX``, ``Apple Mail To Do``, ``Archive``, and ``2008`` (a sub-folder of ``Archive``). The mailbox hierarchy looks like: - INBOX - Apple Mail To Do - Archive - 2008 There is one unread message in the ``INBOX`` folder, and one read message in ``Archive/2008``. Listing Mailboxes ================= To retrieve the mailboxes available for an account, use the :meth:`list()` method. .. include:: imaplib_list.py :literal: :start-after: #end_pymotw_header The return value is a tuple with a response code and the data returned by the server. The response code is ``OK``, unless there has been an error. The data for :meth:`list()` is a sequence of strings containing *flags*, the *hierarchy delimiter*, and *mailbox name* for each mailbox. :: $ python imaplib_list.py Response code: OK Response: ['(\\HasNoChildren) "." INBOX', '(\\HasNoChildren) "." "Apple Mail To Do"', '(\\HasChildren) "." "Archive"', '(\\HasNoChildren) "." "Archive.2008"'] Each response string can be split into 3 parts using :mod:`re` or :mod:`csv` (see `IMAP Backup Script`_ for an example using :mod:`csv`). .. include:: imaplib_list_parse.py :literal: :start-after: #end_pymotw_header Notice that the server quotes the mailbox name if it includes spaces, but we need to strip those quotes to use the mailbox name in other calls back to the server later. :: $ python imaplib_list_parse.py Response code: OK Server response: (\HasNoChildren) "." INBOX Parsed response: ('\\HasNoChildren', '.', 'INBOX') Server response: (\HasNoChildren) "." "Apple Mail To Do" Parsed response: ('\\HasNoChildren', '.', 'Apple Mail To Do') Server response: (\HasChildren) "." "Archive" Parsed response: ('\\HasChildren', '.', 'Archive') Server response: (\HasNoChildren) "." "Archive.2008" Parsed response: ('\\HasNoChildren', '.', 'Archive.2008') :meth:`list()` takes arguments to let you ask for mailboxes in part of the hierarchy. For example, to list sub-folders of ``Archive``, you can pass a value as the *directory* argument: .. include:: imaplib_list_subfolders.py :literal: :start-after: #end_pymotw_header Only the single subfolder is returned: :: $ python imaplib_list_subfolders.py Response code: OK Server response: (\HasNoChildren) "." "Archive.2008" Alternately, to list folders matching a pattern you can pass the *pattern* argument: .. include:: imaplib_list_pattern.py :literal: :start-after: #end_pymotw_header In this case, both ``Archive`` and ``Archive.2008`` are included in the response. :: $ python imaplib_list_pattern.py Response code: OK Server response: (\HasChildren) "." "Archive" Server response: (\HasNoChildren) "." "Archive.2008" Mailbox Status ============== Use :meth:`status()` to ask for aggregated information about the contents. The standard defines these *status conditions*: MESSAGES The number of messages in the mailbox. RECENT The number of messages with the \Recent flag set. UIDNEXT The next unique identifier value of the mailbox. UIDVALIDITY The unique identifier validity value of the mailbox. UNSEEN The number of messages which do not have the \Seen flag set. The status conditions must be formatted as a space separated string enclosed in parentheses, the encoding for a "list" in the IMAP4 specification. .. include:: imaplib_status.py :literal: :start-after: #end_pymotw_header The return value is the usual tuple containing a response code and a list of information from the server. In this case, the list contains a single string formatted with the name of the mailbox in quotes, then the status conditions and values in parentheses. :: $ python imaplib_status.py ('OK', ['"INBOX" (MESSAGES 1 RECENT 0 UIDNEXT 3 UIDVALIDITY 1222003700 UNSEEN 1)']) ('OK', ['"Apple Mail To Do" (MESSAGES 0 RECENT 0 UIDNEXT 1 UIDVALIDITY 1222003706 UNSEEN 0)']) ('OK', ['"Archive" (MESSAGES 0 RECENT 0 UIDNEXT 1 UIDVALIDITY 1222003809 UNSEEN 0)']) ('OK', ['"Archive.2008" (MESSAGES 1 RECENT 0 UIDNEXT 2 UIDVALIDITY 1222003831 UNSEEN 0)']) Selecting a Mailbox =================== The basic mode of operation, once the client is authenticated, is to *select* a mailbox and then interrogate the server regarding messages in the mailbox. The connection is stateful, so once a mailbox is selected all commands operate on messages in that mailbox until a new mailbox is selected. .. include:: imaplib_select.py :literal: :start-after: #end_pymotw_header The response data contains the total number of messages in the mailbox. :: $ python imaplib_select.py OK ['1'] There are 1 messages in INBOX If an invalid mailbox is specified, the response code is ``NO``. .. include:: imaplib_select_invalid.py :literal: :start-after: #end_pymotw_header The data contains an error message describing the problem. :: $ python imaplib_select_invalid.py NO ["Mailbox doesn't exist: Does Not Exist"] Searching for Messages ====================== Once the mailbox is selected, use :meth:`search()` to retrieve the ids of messages in the mailbox. .. include:: imaplib_search_all.py :literal: :start-after: #end_pymotw_header Message ids are assigned by the server, and are implementation dependent. The IMAP4 protocol makes a distinction between sequential ids for messages at a given point in time during a transaction and UID identifiers for messages, but not all servers seem to bother. :: $ python imaplib_search_all.py INBOX OK ['1'] Apple Mail To Do OK [''] Archive OK [''] Archive.2008 OK ['1'] In this case, ``INBOX`` and ``Archive.2008`` each have a diffrerent message with id ``1``. The other mailboxes are empty. Search Criteria =============== A variety of other search criteria can be used, including looking at dates for the message, flags, and other headers. Refer to section 6.4.4. of :rfc:`3501` for complete details. As one example, to look for messages with ``'test message 2'`` in the subject, the search criteria could be constructed as:: (SUBJECT "test message 2") This example finds all messages with the title "test message 2" in all mailboxes: .. include:: imaplib_search_subject.py :literal: :start-after: #end_pymotw_header There is only one such message in the account, and it is in the ``INBOX``. :: $ python imaplib_search_subject.py INBOX OK ['1'] Apple Mail To Do OK [''] Archive OK [''] Archive.2008 OK [''] Search criteria can also be combined. .. include:: imaplib_search_from.py :literal: :start-after: #end_pymotw_header The combination is treated as a logical *and* operation. :: $ python imaplib_search_from.py INBOX OK ['1'] Apple Mail To Do OK [''] Archive OK [''] Archive.2008 OK [''] Fetching Messages ================= The identifiers returned by :meth:`search()` are used to retrieve the contents, or partial contents, of messages for further processing via :meth:`fetch()`. :meth:`fetch()` takes 2 arguments, the message ids to fetch and the portion(s) of the message to retrieve. The *message_ids* argument is a comma separated list of ids (``"1"``, ``"1,2"``) or id ranges (``1:2``). The *message_parts* argument is an IMAP list of message segment names. As with search criteria for :meth:`search()`, the IMAP protocol specifies named message segments so clients can efficiently retrieve only the parts of the message they actually need. For example, to print the headers of the messages in a mailbox, we could :meth:`fetch()` the headers using ``BODY.PEEK[HEADER]``. .. note:: Another way to fetch the headers would be simply ``BODY[HEADERS]``, but that form implicitly marks the message as read, which is undesirable in many cases. .. include:: imaplib_fetch_raw.py :literal: :start-after: #end_pymotw_header The return value of :meth:`fetch()` has been partially parsed so it is somewhat harder to work with than the return value of :meth:`list()`. If we turn on debugging, we can see the complete interaction between the client and server to understand why this is so. :: $ python imaplib_fetch_raw.py 13:12.54 imaplib version 2.58 13:12.54 new IMAP4 connection, tag=CFKH 13:12.54 < * OK dovecot ready. 13:12.54 > CFKH0 CAPABILITY 13:12.54 < * CAPABILITY IMAP4rev1 SORT THREAD=REFERENCES MULTIAPPEND UNSELECT IDLE CHILDREN LISTEXT LIST-SUBSCRIBED NAMESPACE AUTH=PLAIN 13:12.54 < CFKH0 OK Capability completed. 13:12.54 CAPABILITIES: ('IMAP4REV1', 'SORT', 'THREAD=REFERENCES', 'MULTIAPPEND', 'UNSELECT', 'IDLE', 'CHILDREN', 'LISTEXT', 'LIST-SUBSCRIBED', 'NAMESPACE', 'AUTH=PLAIN') 13:12.54 > CFKH1 LOGIN example "password" 13:13.18 < CFKH1 OK Logged in. 13:13.18 > CFKH2 EXAMINE INBOX 13:13.20 < * FLAGS (\Answered \Flagged \Deleted \Seen \Draft $NotJunk $Junk) 13:13.20 < * OK [PERMANENTFLAGS ()] Read-only mailbox. 13:13.20 < * 2 EXISTS 13:13.20 < * 1 RECENT 13:13.20 < * OK [UNSEEN 1] First unseen. 13:13.20 < * OK [UIDVALIDITY 1222003700] UIDs valid 13:13.20 < * OK [UIDNEXT 4] Predicted next UID 13:13.20 < CFKH2 OK [READ-ONLY] Select completed. 13:13.20 > CFKH3 FETCH 1 (BODY.PEEK[HEADER] FLAGS) 13:13.20 < * 1 FETCH (FLAGS ($NotJunk) BODY[HEADER] {595} 13:13.20 read literal size 595 13:13.20 < ) 13:13.20 < CFKH3 OK Fetch completed. 13:13.20 > CFKH4 CLOSE 13:13.21 < CFKH4 OK Close completed. 13:13.21 > CFKH5 LOGOUT 13:13.21 < * BYE Logging out 13:13.21 BYE response: Logging out 13:13.21 < CFKH5 OK Logout completed. [('1 (FLAGS ($NotJunk) BODY[HEADER] {595}', 'Return-Path: \r\nReceived: from example.com (localhost [127.0.0.1])\r\n\tby example.com (8.13.4/8.13.4) with ESMTP id m8LDTGW4018260\r\n\tfor ; Sun, 21 Sep 2008 09:29:16 -0400\r\nReceived: (from dhellmann@localhost)\r\n\tby example.com (8.13.4/8.13.4/Submit) id m8LDTGZ5018259\r\n\tfor example@example.com; Sun, 21 Sep 2008 09:29:16 -0400\r\nDate: Sun, 21 Sep 2008 09:29:16 -0400\r\nFrom: Doug Hellmann \r\nMessage-Id: <200809211329.m8LDTGZ5018259@example.com>\r\nTo: example@example.com\r\nSubject: test message 2\r\n\r\n'), ')'] The response from the ``FETCH`` command starts with the flags, then indicates that there are 595 bytes of header data. The client contructs a tuple with the response for the message, and then closes the sequence with a single string containing the ``)`` the server sends at the end of the fetch response. Because of this formatting, it may be easier to fetch different pieces of information separately, or to recombine the response and parse it yourself. .. include:: imaplib_fetch_separately.py :literal: :start-after: #end_pymotw_header Fetching values separately has the added benefit of making it easy to use :func:`ParseFlags()` to parse the flags from the response. :: $ python imaplib_fetch_separately.py HEADER: Return-Path: Received: from example.com (localhost [127.0.0.1]) by example.com (8.13.4/8.13.4) with ESMTP id m8LDTGW4018260 for ; Sun, 21 Sep 2008 09:29:16 -0400 Received: (from dhellmann@localhost) by example.com (8.13.4/8.13.4/Submit) id m8LDTGZ5018259 for example@example.com; Sun, 21 Sep 2008 09:29:16 -0400 Date: Sun, 21 Sep 2008 09:29:16 -0400 From: Doug Hellmann Message-Id: <200809211329.m8LDTGZ5018259@example.com> To: example@example.com Subject: test message 2 BODY TEXT: second message FLAGS: 1 (FLAGS ($NotJunk)) ('$NotJunk',) Whole Messages ============== As illustrated above, the client can ask the server for individual parts of the message separately. It is also possible to retrieve the entire message as an :rfc:`2822` formatted mail message and parse it with classes from the :mod:`email` module. .. include:: imaplib_fetch_rfc822.py :literal: :start-after: #end_pymotw_header The parser in the :mod:`email` module make it very easy to access and manipulate messages. This example prints just a few of the headers for each message. :: $ python imaplib_fetch_rfc822.py SUBJECT : test message 2 TO : example@example.com FROM : Doug Hellmann Uploading Messages ================== To add a new message to a mailbox, pass it to the :meth:`append()` method. .. include:: imaplib_append.py :literal: :start-after: #end_pymotw_header :: pymotw Subject: subject goes here From: pymotw@example.com To: example@example.com This is the body of the message. 1: Return-Path: Received: from example.com (localhost [127.0.0.1]) by example.com (8.13.4/8.13.4) with ESMTP id m8LDTGW4018260 for ; Sun, 21 Sep 2008 09:29:16 -0400 Received: (from dhellmann@localhost) by example.com (8.13.4/8.13.4/Submit) id m8LDTGZ5018259 for example@example.com; Sun, 21 Sep 2008 09:29:16 -0400 Date: Sun, 21 Sep 2008 09:29:16 -0400 From: Doug Hellmann Message-Id: <200809211329.m8LDTGZ5018259@example.com> To: example@example.com Subject: test message 2 2: Return-Path: Message-Id: <0D9C3C50-462A-4FD7-9E5A-11EE222D721D@example.com> From: Doug Hellmann To: example@example.com Content-Type: text/plain; charset=US-ASCII; format=flowed; delsp=yes Content-Transfer-Encoding: 7bit Mime-Version: 1.0 (Apple Message framework v929.2) Subject: lorem ipsum Date: Sun, 21 Sep 2008 12:53:16 -0400 X-Mailer: Apple Mail (2.929.2) 3: pymotw Subject: subject goes here From: pymotw@example.com To: example@example.com Moving and Copying Messages =========================== Once a message is on the server, it can be moved or copied without downloading it using :meth:`move()` or :meth:`copy()`. These methods operate on message id ranges, just as :meth:`fetch()` does. This example script creates a new mailbox under ``Archive`` and copies the read messages from ``INBOX`` into it. .. include:: imaplib_archive_read.py :literal: :start-after: #end_pymotw_header :: $ python imaplib_archive_read.py CREATED Archive.Today: ['Create completed.'] COPYING: 1,2 COPIED: 1 2 Running the same script again shows the importance to checking return codes. Instead of raising an exception, the call to :meth:`create()` to make the new mailbox reports that the mailbox already exists. :: $ python imaplib_archive_read.py CREATED Archive.Today: ['Mailbox exists.'] COPYING: 1,2 COPIED: 1 2 3 4 Deleting Messages ================= Although most modern mail clients use a "Trash folder" model for working with deleted messages, the messages are not usually moved into an actual folder. Instead, their flags are updated to add ``\Deleted``. *Emptying the trash* is implemented through an ``EXPUNGE`` command. This example script finds the archived messages with "Lorem ipsum" in the subject, sets the deleted flag, then shows that the messages are still present in the folder by querying the server again. .. include:: imaplib_delete_messages.py :literal: :start-after: #end_pymotw_header This example explicitly calls :meth:`expunge()` to remove the messages, but calling :meth:`close()` has the same effect. The difference is the client is not notified about the deletions when you call :meth:`close()`. :: $ python imaplib_delete_messages.py Starting messages: 1 2 3 4 Matching messages: 1,3 Flags before: ['1 (FLAGS (\\Seen $NotJunk))', '3 (FLAGS (\\Seen \\Recent $NotJunk))'] Flags after: ['1 (FLAGS (\\Deleted \\Seen $NotJunk))', '3 (FLAGS (\\Deleted \\Seen \\Recent $NotJunk))'] Expunged: ['1', '2'] Remaining messages: 1 2 .. seealso:: `imaplib `_ The standard library documentation for this module. `What is IMAP? `_ imap.org description of the IMAP protocol `University of Washington IMAP Information Center `_ Good resource for IMAP information, along with source code. :rfc:`3501` Internet Message Access Protocol :rfc:`2822` Internet Message Format `IMAP Backup Script`_ A script to backup email from an IMAP server. .. _IMAP Backup Script: http://snipplr.com/view/7955/imap-backup-script/ :mod:`rfc822` The :mod:`rfc822` module includes an :rfc:`822` / :rfc:`2822` parser :mod:`email` The :mod:`email` module for parsing email messages. :mod:`mailbox` Local mailbox parser. :mod:`ConfigParser` Read and write configuration files. `IMAPClient `_ A higher-level client for talking to IMAP servers, written by Menno Smits.