2

I have this code that checks the latest email and then goes and does something. Is it possible to write something that keeps checking the inbox folder for new mail? Although I want it to keep checking for the latest new email. Is it getting too complicated if I try and store that it has made one pass? So it doesn't alert about the same email twice about the same email.

Code:

import imaplib
import email
import Tkinter as tk

word = ["href=", "href", "<a href="] #list of strings to search for in email body

#connection to the email server
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.login('xxxx', 'xxxx')
mail.list()
# Out: list of "folders" aka labels in gmail.
mail.select("Inbox", readonly=True) # connect to inbox.

result, data = mail.uid('search', None, "ALL") # search and return uids instead

ids = data[0] # data is a list.
id_list = ids.split() # ids is a space separated string
latest_email_uid = data[0].split()[-1]

result, data = mail.uid('fetch', latest_email_uid, '(RFC822)') # fetch the email headers and body (RFC822) for the given ID


raw_email = data[0][1] # here's the body, which is raw headers and html and body of the whole email
# including headers and alternate payloads

.....goes and does other code regarding to email html....
idwithin
  • 47
  • 1
  • 2
  • 8
  • 2
    In pseudocode, *while true: fetch newest message; if it's newer than the previous, display an alert; previous := newest; sleep;* – tripleee Mar 03 '18 at 16:32
  • 1
    Python's `imaplib` doesn't support the IMAP `IDLE` command but ideally, use that. – tripleee Mar 03 '18 at 16:33
  • IIRC you shoud be able to get away with something much less brutal than always doing "search all" but not in a /ood place to check right now. – tripleee Mar 03 '18 at 16:35

1 Answers1

5

Try to use this approach:

Logic is the same as from @tripleee comment.

import time
word = ["href=", "href", "<a href="] #list of strings to search for in email body

#connection to the email server
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.login('xxxx', 'xxxx')
mail.list()
# Out: list of "folders" aka labels in gmail.
latest_email_uid = ''

while True:
    mail.select("Inbox", readonly=True)
    result, data = mail.uid('search', None, "ALL") # search and return uids instead
    ids = data[0] # data is a list.
    id_list = ids.split() # ids is a space separated string

    if data[0].split()[-1] == latest_email_uid:
         time.sleep(120) # put your value here, be sure that this value is sufficient ( see @tripleee comment below)
    else:
         result, data = mail.uid('fetch', latest_email_uid, '(RFC822)') # fetch the email headers and body (RFC822) for the given ID
         raw_email = data[0][1]
         latest_email_uid == data[0].split()[-1]
         time.sleep(120) # put your value here, be sure that this value is sufficient ( see @tripleee comment below)
Kyrylo
  • 651
  • 1
  • 6
  • 15
  • You want to sleep significantly longer than five seconds; once per minute is already considered fairly aggressive by many IMAP server admins. Depending on your application and expected traffic, checking every five or ten minutes may well be quite sufficient. – tripleee Mar 03 '18 at 16:51
  • 1
    @tripleee Okay, I will change it :) I do not familiar with IMAP imaplib, so this code is just my thought that I had when finished reading the question. – Kyrylo Mar 03 '18 at 16:54
  • I needed to restructure the else statement to get everything to work and then run my command. In this order - latest_email_uid == data[0].split()[-1] > result, data = mail.uid('fetch', latest_email_uid, '(RFC822)') > raw_email = data[0][1] It runs and waits yet when it seems to run again I get this error..... in next comment..... – idwithin Mar 04 '18 at 13:26
  • Traceback (most recent call last): File "beta_1.4.py", line 36, in result, data = mail.uid('search', None, "ALL") # search and return uids instead File "C:\Python27\lib\imaplib.py", line 773, in uid ', '.join(Commands[command]))) imaplib.error: command SEARCH illegal in state LOGOUT, only allowed in states SELECTED – idwithin Mar 04 '18 at 13:27
  • @idwithin Can you move `mail.select("Inbox", readonly)` inside `while True`? Put it on the first line after `while True` statement. – Kyrylo Mar 04 '18 at 13:43
  • That fixed it and worked with testing new emails sent. Thanks so much :) – idwithin Mar 04 '18 at 14:41
  • @Kyrylo : Getting the error **Traceback (most recent call last): File "C:/Users/sh/PycharmProjects/DemoReadmail/demo.py", line 23, in mail.select("INBOX") AttributeError: 'Message' object has no attribute 'select'** after using while loop, the file is downloaded once and when it goes to check for new mails (while loop) then i got this error. –  Oct 10 '18 at 13:06