E-mail Automation using Python (Part - 2)

No comments
In this post I'll will be covering retrieving email using Python script:
Just as SMTP is the protocol for sending email, the Internet Message Access Protocol (IMAP) specifies how to communicate with an email provider’s server to retrieve emails sent to your email address. Python comes with an imaplib module, but in fact the third-party imapclient module is easier to use. This is an introduction to use IMAPClient. The full documentation is at imapclient.readthedocs.org.

The imapclient module downloads emails from an IMAP server in a rather complicated format. Most likely, we’ll want to convert them from this format into simple string values. The pyzmail module does the hard job of parsing these email messages for us.  Complete documentation for PyzMail at www.magiksys.net/pyzmail.

#!/usr/bin/python
# coding: utf-8
def retmail():
 import imapclient, time, pprint, pyzmail, getpass
 print "Establishing connection to gmail..."
 imapobj = imapclient.IMAPClient('imap.gmail.com', ssl=True)
 print "Encryption enabled to gmail."
 time.sleep(1)

 mailid = raw_input("\nEnter your mail id to login: ")
 pswd = getpass.getpass("Enter your password: ")
 imapobj.login(mailid, pswd)

 print "\nList of folders: (loading...)\n"
 for i in range(len(imapobj.list_folders())):
  print imapobj.list_folders()[i][2] + ',',
 folder = raw_input("\nEnter folder you want(eg: INBOX): ")
 imapobj.select_folder(folder.upper(), readonly=True)

 sendername = raw_input("Enter sender's mail id (eg:choose 'ALL' to retrieve all mails):")
 since_date = raw_input("Enter date since which you want to receive the mail(eg: 01-JAN-2015): ")
 if sendername == 'ALL':
  UIDs = imapobj.search(['SINCE ' + since_date, sendername ])
 else:
  UIDs = imapobj.search(['SINCE ' + since_date, 'FROM ' + sendername ])

 l = len(UIDs)
 rawmsg = imapobj.fetch(UIDs, ['BODY[]'])

 for i in range(l):
  msg = pyzmail.PyzMessage.factory(rawmsg[UIDs[i]]['BODY[]'])
  subject = msg.get_subject()
  fromaddr = msg.get_address('from')
  body = msg.text_part.get_payload().decode(msg.text_part.charset)

  print '\nMessage ' + str(i+1) + ': '
  print 'Subject: ' + subject
  print 'From: ' + fromaddr[0] + ' <' + fromaddr[1] + '>'
  print 'Body:\n'+ body

 
 imapobj.logout()
 print "Logout requested..."
 time.sleep(1)
 print "Logout successful"

retmail()


On line 4, we import all necessary libraries. imapclient for creating IMAP object, pymail for parsing mails, getpass to get password in hidden mode, pprint(stands for pretty print) to display formatted output.
Then we establish connection to gmail's imap client by creating a imapobj on line 6 and enable SSL encryption.

In lines 10-12 mail id and password of user is accepted and authenticated. On line 15, we print all the folders present in the user's gmail (like: INBOX, sent, trash etc.). The user can choose which folder he/she wants to explore or retrieve mail from.
On line 20th, sender's mail id accepted from user. Here the user has choice that he/she can either enter mail id of any one contact or 'ALL' to retrieve mail from all.
On line 21st the program asks the user to enter date from which he/she wants to retrieve mail. The format of date to be followed must be 'dd-MMM-YYYY' like '01-JAN-2015'.
The search() doesn't return mail themselves but rather unique IDs (UIDs)for emails, as integer values. We can then pass the UIDs to fetch() to obtain email content.

SIZE LIMIT
If your search matches a large number of emails, Python might raise an exception that says: imapib.error: got more than 10000 bytes. When this happens, we will have to disconnect and re-connect IMAP server and try again.
This limit is in place to prevent Python programs from eating too much memory. We can change this limit to (say)10,000,000 bytes by running this code: 


import imaplib
imaplib.MAXLINE = 10000000

Now in lines 30-35 we pass each UID and parse the mail components (like body, subject etc) and print it in a neat format in lines 36-40.
When our program has finished retrieving mails, we simply call IMAPClient's logout() to disconnect from IMAP server.

If your program runs for several minutes or more, IMAP server may time out or automatically disconnect. In this case the method call our program make will throw exception like:- imaplib.abort: socket error: [Winerror] An existing connection was forcibly closed by the remote host.
Your program will have to call imapclient.IMAPClient() to re-connect.

Now you might be thinking where is the automation part in all of this...well the automation part will be exactly same as that of Email Automation (Part-1).
You can choose when to retrieve mail and then take action accordingly. You can even write a script in which based on (say) subject of a particular mail, you can automate it to do perform another action(for example: you can remotely command your bot to perform certain task!)