2

I am trying to write some code to read my inbox and process some attachments if present. I decided this would be a good time to learn how generators work as I want to process all messages that have a particular subject. I have gotten to the point where I can get all the attachments and relevant subjects but I sort of had to fake it as the iterator in the for i in range . . . was not advancing so I am advancing the latest_email_id in the loop

def read_email_from_gmail():
    try:
        print 'got here'
        mail = imaplib.IMAP4_SSL(SMTP_SERVER)
        mail.login(FROM_EMAIL,FROM_PWD)
        mail.select('inbox')

        type, data = mail.search(None, 'ALL')
        mail_ids = data[0]

        id_list = mail_ids.split()   
        first_email_id = int(id_list[0])
        latest_email_id = int(id_list[-1])
        print latest_email_id


        while True:
            for i in range(latest_email_id,first_email_id - 1, -1):
                latest_email_id -= 1
                #do stuff to get attachment and subject
                yield attachment_data, subject


    except Exception, e:
        print str(e)

for attachment, subject in read_email_from_gmail():
    x = process_attachment(attachment)
    y = process_subject(subject)

Is there a more pythonic way to advance through my in-box using a generator to hold state in the in-box?

PyNEwbie
  • 4,882
  • 4
  • 38
  • 86
  • You might want to compare your code to [e-satis'](https://stackoverflow.com/a/642988/190597). He shows a different way to iterate through the messages without the `for i in range(...)` loop. – unutbu Nov 25 '17 at 16:38
  • I started with that approach and then wondered about a generator so I could encapsulate the code better - the other stuff I have to do to each email message is very extensive and like I said I am idly wondering how to use generators – PyNEwbie Nov 25 '17 at 16:44

1 Answers1

0

I have learned a bit more about generators and played around with the code I started with so I have a function that uses a generator to send each relevant email message subject to the main function. This is what I have so far, and it works great for my needs

import imaplib
import email
FROM_EMAIL  = 'myemail@gmail.com'
FROM_PWD    = "mygmail_password"
SMTP_SERVER = "imap.gmail.com"
SMTP_PORT   = 993
STOP_MESSAGES = set(['Could not connect to mailbox',
                     'No Messages or None Retrieved Successfully',
                     'Could not retrieve some message',
                     'Finished processing'])

def  read_emails():
    mail = imaplib.IMAP4_SSL(SMTP_SERVER)
    mail.login(FROM_EMAIL,FROM_PWD)
    mail.select('inbox')
    con_status, data = mail.uid('search', None, "ALL")
    if con_status != 'OK':
        yield 'Could not connect to mailbox'
    try:
        mail_ids = data[0].split()
    except Exception:
        yield 'No Messages or None Retrieved Successfully'
    print mail_ids

    processed = []
    while True:
        for mail_id in mail_ids:
            status, mdata = mail.uid('fetch', mail_id, '(RFC822)')
            if status != 'OK':
                yield 'Could not retrieve some message'
            if mail_id in processed:
                yield 'Finished processing'
            raw_msg = mdata[0][1]
            structured_msg = email.message_from_string(raw_msg)
            msg_subject = structured_msg['subject']
            processed.append(mail_id)
            yield msg_subject

To access my messages one by one, I then use the following block to get my messages

for msg_subj in read_emails():
    if msg_subj not in STOP_MESSAGES:
         do some stuff here with msg_subj
    else:
        print msg_subj
        break

I am accessing these messages by their uid as I will be deleting them later and would like to use the uid as the key to manage deletion. For me the trick was to collect the uid in the list named processed and then check to see if I was going to circle through them again because I was working with a uid that had already been processed.

PyNEwbie
  • 4,882
  • 4
  • 38
  • 86