Chapter 15 ■ IMap
286
First, you can copy an existing message from its home folder into another folder. Start by using select_folder()
to visit the folder where the messages live, and then run the copy method like this:
c.select_folder('INBOX')
c.copy([2653L, 2654L], 'TODO')
Finally, it is possible to add a message to a mailbox with IMAP. You do not need to send the message first with
SMTP; IMAP is all that is needed. Adding a message is a simple process, although there are a couple of things about
which you must be aware.
The primary concern is line endings. Many Unix machines use a single ASCII line feed character (0x0a, or '\n' in
Python) to designate the end of a line of text. Windows machines use two characters: CR-LF, a manual return (0x0D, or
'\r' in Python) followed by a line feed. Older Macs use just the manual return.
Like many Internet protocols (HTTP comes immediately to mind), IMAP internally uses CR-LF ('\r\n' in
Python) to designate the end of a line. Some IMAP servers will have problems if you upload a message that uses any
other character for the end of a line. Therefore, you must always be careful to have the correct line endings when you
translate uploaded messages. This problem is more common than you might expect, because most local mailbox
formats use only '\n' for the end of each line.
However, you must also be cautious in how you change the line endings, because some messages may use '\r\n'
somewhere inside them despite using only '\n' for the first few dozen lines, and IMAP clients have been known to fail
if a message uses both different line endings! The solution is a simple one, thanks to Python’s powerful splitlines()
string method that recognizes all three possible line endings; simply call the function on your message and then rejoin
the lines with the standard line ending:
'one\rtwo\nthree\r\nfour'.splitlines()
['one', 'two', 'three', 'four']
'\r\n'.join('one\rtwo\nthree\r\nfour'.splitlines())
'one\r\ntwo\r\nthree\r\nfour'
The actual act of appending a message, once you have the line endings correct, is arranged by calling the
append() method on your IMAP client:
c.append('INBOX', my_message)
You can also supply a list of flags as a keyword argument, as well as a msg_time to be used as its arrival time, by
passing a normal Python datetime object.
Asynchrony
Finally, a major admission needs be made about this chapter’s approach toward IMAP: even though I have described
IMAP as though the protocol were synchronous, it in fact supports clients that want to send dozens of requests down
the socket to the server and then receive the answers back in whatever order the server can most efficiently fetch the
e-mail from disk and respond.
The IMAPClient library hides this protocol flexibility by always sending one request, waiting for the response, and
then returning that value. But other libraries, and in particular the IMAP capabilities provided inside Twisted Python,
let you take advantage of its asynchronicity.
For most Python programmers who need to script mailbox interactions, the synchronous approach taken in this
chapter should work just fine. And if you do branch out and switch to an asynchronous library, then you will at least
already know all of the IMAP commands from their descriptions in this chapter, and you will only have to learn how to
send those same commands through the asynchronous library’s API.