IMAPv4

Python IMAP Interface

Connecting directly to an IMAP server

Excellent examples: Email via IMAP using Telent

To connect with Telnet

telnet <hostname> 143

or to connect with SSL (recommended)

openssl s_client -connect <hostname>:993

IMAP Sample Connection

* OK Domino IMAP4 Server Release 10.0.1FP1 ready Wed, 24 Nov 2010 08:22:03 -0800
C A0001 LOGIN user@domain password
S A0001 OK LOGIN completed
C A0002 EXAMINE INBOX
S * 507 EXISTS
S * 0 RECENT
S * OK [UNSEEN 344] Message 344 is first unseen
S * OK [UIDVALIDITY 405] UIDs valid
S * OK [UIDNEXT 596] Predicted next UID
S * FLAGS (\Flagged \Seen \Answered \Deleted \Draft)
S * OK [PERMANENTFLAGS ()] No permanent flags permitted
S A0002 OK [READ-ONLY] EXAMINE completed

Legend: 'C' = data sent by client, 'S' = data sent by server

Notes:

  1. You must prefix each of your commands with an identifier called a “tag” (any alphanumeric string, i.e. A0001, A0002), otherwise your command will fail.
  2. The “tag” must be followed with exactly one space followed by the IMAP command.
  3. IMAP Commands are case-sensitive.
  4. What IMAP4 client applications often label as “folders” are actually each separate “mailboxes”.
  5. “Mailboxes” can be in a SUBSCRIBED or UNSUBSCRIBED state, i.e. a mailbox can be CREATED on the server, but if not SUBSCRIBED a user's client application may not display it.
  6. A “session” starts when a mailbox is “EXAMINED” or “SELECTED”.
  7. Messages in IMAP4rev1 are accessed by one of two numbers; the unique indentifier (UID) or the message sequence number.
    • UID's are unique and do not change during a session.
    • Message sequence numbers can change during a session.
    • Mailbox name + UIDVALIDITY + UID together create a unique value that refers to a single immutable message on that server forever.
    • UIDVALIDITY only changes if UID's in a previous session fail to persist in the current session (i.e. when the message store has no mechanism to store unique identifiers).
    • UIDVALIDITY & UIDNEXT are values that belong to mailboxes not messages.
    • UID's & Message sequence numbers can be mapped back-and-forth using SEARCH UID <…> and FETCH UID <…>.
  8. IMAP server connections will time out after 30 minutes of inactivity, you can send a NOOP to keep it alive.

IMAP State & Flow

CONNECT <hostname>
command: mail = imaplib.IMAP4_SSL(hostname)
object: <imaplib.IMAP4_SSL instance at 0x02586AD0>
state: NONAUTH
 
LOGIN <username> <password>
Notes: username is user@domain
command: typ, data = mail.login(username, getpass.getpass())
Password:
typ: OK
data: ['LOGIN completed']
state: AUTH
 
EXAMINE Inbox
command: typ, data = mbox.select(mailbox_name, True)
typ: OK
data: ['344']
state: SELECTED
 
SEARCH All
typ: OK
data: ['1 2 3']
state: SELECTED
 
FETCH 1 RFC2822
typ: OK
data: [...]
state: SELECTED
 
CLOSE
typ: OK
data: ['CLOSE completed']
state: AUTH
 
LOGOUT
typ: BYE
data: ['logging out']
state: LOGOUT

Connect to IMAP Server

Set imaplib.Debug = 5 prior to creating an IMAP4 instance to see commands sent to the server, the responses and how the responses are parsed.

imaplib.IMAP4([host[, port]]) Connect to IMAP server, default port=123
imaplib.IMAP4_SSL([host[, port[, keyfile[, certfile]]]]) Connect to IMAP server over SSL, default port=993

State: NONAUTH

LOGIN IMAP4.login(user, password) or IMAP4.login_cram_md5(user, password) login with user@domain
AUTHENTICATE IMAP4.authenticate(mechanism, authobject) Indicates a SASL authentication mechanism on server (1)
STARTTLS Not supported

(1) If you don't know, then don't use the authenticate command, just LOGIN.

State: AUTH

Browse, Select, Subscribe and CRUD for mailboxes.

SELECT IMAP4.select([mailbox]]) Returns number of messages found in mailbox, to get the remaining information view IMAP4. # Exists
EXAMINE IMAP4.select(mailbox, True)
STATUS IMAP4.status(mailbox, names)
LIST IMAP4.list([directory[, pattern]])
LSUB IMAP4.lsub([directory[, pattern]])
CREATE IMAP4.create(mailbox)
DELETE IMAP4.delete(mailbox)
RENAME IMAP4.rename(oldmailbox, newmailbox)
SUBSCRIBE IMAP4.subscribe(mailbox)
UNSUBSCRIBE IMAP4.unsubscribe(mailbox)

pattern: supports wildcards * = match any character & descend path, % = match any character in current path

Select Returns

FLAGS Defined flags in mailbox
EXISTS Number of messages in mailbox
RECENT Number of messages with \Recent flag set
UNSEEN Message number of first unseen message
PERMANENT FLAGS A list of messages flags that client can change permanently
UIDNEXT Next UID
UIDVALIDITY UID validity value

State: SELECTED

CLOSE IMAP4.close()
SEARCH IMAP4.search(charset, criterion[, …])
FETCH IMAP4.fetch(message_set, message_parts) or IMAP4.partial(message_num, message_part, start, length)
STORE IMAP4.store(message_set, command, flag_list)
EXPUNGE IMAP4.expunge()
COPY IMAP4.copy(message_set, new_mailbox)
CHECK IMAP4.check()
UID IMAP4.uid(command, arg[, …])

Any State

LOGOUT IMAP4.logout()
CAPABILITY
NOOP

SEARCH Command

imaplib requires that you enclose your search criterion in parentheses. '*' can be used as wildcard characters. Example IMAP4.search('(FROM “*yahoo.com”)') will search for all email from yahoo.com Returns message numbers matching the specified search criteria.

ALL Return all message numbers
OR search-key1 search-key2 Return messages that match either search-key
NOT search-key Exclude messages containing string
search-key1 search-key2 Equivalent to search-key1 AND search-key2

Search for Strings in Message

TO <str> Return messages with string in “To” header field
FROM <str> Return messages with string in “From” header field
CC <str> Return messages with string in “CC” header field
BCC <str> Return messages with string in “BCC” header field
SUBJECT <str> Return messages with string in “Body” of message
BODY <str> Return messages with string in “Body” of message
TEXT <str> Return messages with string in “Body” or any of the above header fields

Search on Message Flags

Flag set Flag NOT set Description
ANSWERED UNANSWERED Return messages that have been replied to
DELETED UNDELETED Return deleted messages
DRAFT UNDRAFT Return draft message
FLAGGED UNFLAGGED Return flagged messages
NEW OLD Return recent messages
SEEN UNSEEN Return read messages

Search on Date/Time

Date Format: %d-%b-%Y Time Format: %H:%M:%S %z

Search on Internal Message Date

BEFORE <datet> Return messages with an internal date before specified date
ON <date> Return messages with an internal date on specified date
SINCE <date> Return messages with an internal date on or after specified date

Search on Message Header Date

SENTBEFORE <date> Return messages sent before specified date
SENTON <date> Return messages sent on specified date/time
SENTSINCE <date> Return messages sent on or after specified date/time

Search on Message Size

SMALLER <n> Smaller than specified number of octets
LARGER <n> Larger than specified number of octets

Example search command

Search flagged since 1-Feb-1994 NOT FROM "Smith"

Fetch Commands

Use “UID FETCH” if you want to fetch UID's instead of message sequence numbers.

BODYSTRUCTURE Perl BODYSTRUCTURE parser
ENVELOPE
FLAGS
INTERNALDATE internal date, not the sent date
BODY [section] partial Message body
BODY.PEEK[section] partial Does not set the \Seen flag, i.e. BODY.PEEK[2.1]
ALL same as FLAGS INTERNALDATE RFC822.SIZE ENVELOPE
FAST same as FLAGS INTERNALDATE RFC822.SIZE
RFC822 same as BODY[]
RFC822.TEXT same as BODY[TEXT]
RFC822.HEADER same as BODY.PEEK[HEADER] headers = email.parser.HeaderParser().parsestr(data), treat headers like a dictionary
RFC822.SIZE size of the message

Message Parts

data.walk() will iterate through
get_filename()
get_content_type()
>>> for part in msg.walk():
...     print part.get_content_type()
multipart/report
text/plain
message/delivery-status
text/plain
text/plain
message/rfc822

Example:

FETCH 2:4 (FLAGS BODY[HEADER.FIELDS (DATE FROM)])
FETCH 1,3 BODY[2.MIME]

Sample body structure:

(158 (BODYSTRUCTURE (("text" "plain"  ("charset" "iso-8859-1") NIL NIL "quoted-printable" 17355 290 NIL NIL NIL)("image" "gif"  ("name" "graycol.
"filename" "graycol.gif")) NIL)("image" "gif"  ("name" "ecblank.gif") "<4__=07BBFD21DFC942328f98a93@domain.org>" "ecblank.gif" "base64" 64 NIL ("in
A60A5CDD5EFaocsvrmbx01jc_" "type" "text/plain") NIL ("en-US")))
 
imapv4_protocol.txt · Last modified: 2010/12/09 16:47 by bpeterso
 
Except where otherwise noted, content on this wiki is licensed under the following license:CC Attribution-Noncommercial-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki