Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fetch an email body using imaplib in python?

Tags:

python

imaplib

I'd like to fetch the whole message from IMAP4 server. In python docs if found this bit of code that works:

>>> t, data = M.fetch('1', '(RFC822)') >>> body = data[0][1] 

I'm wondering if I can always trust that data[0][1] returns the body of the message. When I've run 'RFC822.SIZE' I've got just a string instead of a tuple.

I've skimmed through rfc1730 but I wasn't able to figure out the proper response structure for the 'RFC822'. It is also hard to tell the fetch result structure from imaplib documentation.

Here is what I'm getting when fetching RFC822:

('OK', [('1 (RFC822 {858569}', 'body of the message', ')')]) 

But when I fetch RFC822.SIZE I'm getting:

('OK', ['1 (RFC822.SIZE 847403)']) 

How should I properly handle the data[0] list? Can I trust that when it is a list of tuples the tuples has exactly 3 parts and the second part is the payload?

Maybe you know any better library for imap4?

like image 712
Piotr Czapla Avatar asked Feb 09 '10 15:02

Piotr Czapla


2 Answers

No... imaplib is a pretty good library, it's imap that's so unintelligible.

You may wish to check that t == 'OK', but data[0][1] works as expected for as much as I've used it.

Here's a quick example I use to extract signed certificates I've received by email, not bomb-proof, but suits my purposes:

import getpass, os, imaplib, email from OpenSSL.crypto import load_certificate, FILETYPE_PEM  def getMsgs(servername="myimapserverfqdn"):   usernm = getpass.getuser()   passwd = getpass.getpass()   subject = 'Your SSL Certificate'   conn = imaplib.IMAP4_SSL(servername)   conn.login(usernm,passwd)   conn.select('Inbox')   typ, data = conn.search(None,'(UNSEEN SUBJECT "%s")' % subject)   for num in data[0].split():     typ, data = conn.fetch(num,'(RFC822)')     msg = email.message_from_string(data[0][1])     typ, data = conn.store(num,'-FLAGS','\\Seen')     yield msg  def getAttachment(msg,check):   for part in msg.walk():     if part.get_content_type() == 'application/octet-stream':       if check(part.get_filename()):         return part.get_payload(decode=1)  if __name__ == '__main__':   for msg in getMsgs():     payload = getAttachment(msg,lambda x: x.endswith('.pem'))     if not payload:       continue     try:       cert = load_certificate(FILETYPE_PEM,payload)     except:       cert = None     if cert:       cn = cert.get_subject().commonName       filename = "%s.pem" % cn       if not os.path.exists(filename):         open(filename,'w').write(payload)         print "Writing to %s" % filename       else:         print "%s already exists" % filename 
like image 93
MattH Avatar answered Sep 28 '22 23:09

MattH


The IMAPClient package is a fair bit easier to work with. From the description:

Easy-to-use, Pythonic and complete IMAP client library.

like image 44
Peter Hansen Avatar answered Sep 28 '22 23:09

Peter Hansen