Search code examples
pythonweb-applicationsimap

Writing multiple Emails to a text file Python IMAP


I currently have a code that works in a pyramid web-application. By pressing a button, the web app runs a function that reads unread Emails from inbox, deletes first 6 lines (not important info) and writes them onto a file. Later, this data is used as plotting data with matplotlib. My current problem is that the code only reads one unread Email at a time. This means that if I have for example 5 unread emails with data that I want to write to a file, the press of the button only writes the data of one Email, while I want the data from all 5 Emails.

Is there any possible way to read all unread Emails at once and write them onto a text file? I've been thinking about adding code that counts the amount of unread emails, and it keeps looping the read/write function until the unread amount reaches 0. There might be a more professional way to do this, so that's why I ask. Thanks in advance!

Here is my current code:

@view_config(route_name='update-data')
def update_view(request):

    m = imaplib.IMAP4_SSL('imap.gmail.com')
    m.login('email@gmail.com', 'password')
    m.list()
    m.select('inbox')

    result, data = m.uid('search', None, 'FROM', '"senderEmail"', 'UNSEEN') # Only unseen mail

    i = len(data[0].split()) #space separate string

    if i == 0:
        return Response('<head><link rel="stylesheet" href="/static/styleplot.css"/></head>'
        + '<h3> Data cannot be updated </h3><h4>No new emails</h4>'
        + '<form class="anchor" action="http://localhost:8888"><input class="homebutton" type="submit" value="Return" /></form>')

    for x in range(i):
        latest_email_uid = data[0].split()[x]
        result, email_data = m.uid('fetch', latest_email_uid, '(RFC822)')
        raw_email = email_data[0][1]
        raw_email_string = raw_email.decode('utf-8')
        email_message = email.message_from_string(raw_email_string)



        for part in email_message.walk():
            if part.get_content_type() == 'text/plain':
                body = part.get_payload(decode=True)
                with open('C:/Email/file.txt', 'a') as myfile:  # Opens file.txt and writes the email body
                    myfile.write(str(body)) 
                with open('C:/Email/file.txt', 'r+') as f:  # Opens file.txt again in read mode and reads lines
                    lines = f.readlines()
                    with open ('C:/Email/newfile.txt','a') as g: # Writes file.txt contents to newfile.txt, starting from line 6, deletes contents of the first file
                        g.writelines(lines[6:])
                        f.truncate(0)
            else:
                continue




            return Response('<h3>Data update successful</h3>'
            + '<form class="anchor" action="http://localhost:8888"><input class="homebutton" type="submit" value="Return" /></form>')

Solution

  • Might be because you are writing and reading in the same iteration of the for ... at the same indentation level. Basically on each iteration you are:

    • getting an email
    • write to the file
    • read that file (seems useless at this point just use the body)
    • still "here", after reading the file you write to another file and truncate the first.

    To make things worst you have the return also under the for ... so you are returning on the first iteration.
    I think your code should be more like

    @view_config(route_name='update-data')
    def update_view(request):
    
        m = imaplib.IMAP4_SSL('imap.gmail.com')
        m.login('email@gmail.com', 'password')
        m.list()
        m.select('inbox')
    
        result, data = m.uid('search', None, 'FROM', '"senderEmail"', 'UNSEEN') # Only unseen mail
    
        i = len(data[0].split()) #space separate string
    
        if i == 0:
            return Response('<head><link rel="stylesheet" href="/static/styleplot.css"/></head>'
            + '<h3> Data cannot be updated </h3><h4>No new emails</h4>'
            + '<form class="anchor" action="http://localhost:8888"><input class="homebutton" type="submit" value="Return" /></form>')
    
        for latest_email_uid in data[0].split():
            result, email_data = m.uid('fetch', latest_email_uid, '(RFC822)')
            raw_email = email_data[0][1]
            raw_email_string = raw_email.decode('utf-8')
            email_message = email.message_from_string(raw_email_string)
            with open('C:/Email/file.txt', 'a') as myfile:  # Opens file.txt and writes the email body
                for part in email_message.walk():
                    if part.get_content_type() == 'text/plain':
                        body = part.get_payload(decode=True)
                        myfile.write(str(body)) 
    
        with open('C:/Email/file.txt', 'r+') as f:  # Opens file.txt again in read mode and reads lines
            lines = f.readlines()
            with open ('C:/Email/newfile.txt','a') as g: # Writes file.txt contents to newfile.txt, starting from line 6, deletes contents of the first file
                g.writelines(lines[6:])
            f.truncate(0)
    
    
    
        return Response('<h3>Data update successful</h3>'
            + '<form class="anchor" action="http://localhost:8888"><input class="homebutton" type="submit" value="Return" /></form>')
    

    Later edit: I don't really know what's the reasoning of writing in the intermediary file, I think the real problem in you code might've been the "wrong" indentation of the return