Hi so I have this program which basically goes into the inbox and then looks at the latest email. Scans it and if it has a link it gives you a notification, or if it has an attachment it gives a notification. Everything is working fine although I tried to combine the two notifications into one. So it's a bit nicer, instead of having one notification show, then another right after it. If an email has both a link and attachment. I'd of prefer it just to be one notification if the email has both and then separate notifications if they only contain either a link or attachment. I've tried to split it up into a if and elif loop.
I can get a notification to appear for both if I do an 'and' within the loop in the if statement - e.g
if any(word in html_text for word in word) and file_name == None:
fboth()
fboth() (this is the function that would tell you there is both a link and attachment, just like flink() and fattach())
although when I put my other options as elif: statements, one for a link by itself and one for an attachment by itself. Those still play out even though it found the first statement to be True and it alerts that the email has both a link and attachment. Is there away to stop this? I'm starting to think it's another if statement? But I had a few failed attempts and maybe not fully understanding it. Is my theory correct with how I am tackling it by still using the for loop?
Here is the code:
import imaplib
import email
import Tkinter as tk
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()
latest_email_uid = ''
#Finding a link popup
def flink():
flink = tk.Tk()
flink.title("Found Link")
tk.Label(flink, text="Email has link in body\n" + "From: " + msg['From'] + "\n" + "Subject: " + msg['Subject'] + "\n" + "Date: " + msg['Date'], fg='yellow', bg='black').pack()
flink.after(5000, lambda: flink.destroy()) # time in ms
flink.mainloop()
#Finding an attachment popup
def fattach():
fattach = tk.Tk()
fattach.title("Found Attachment")
tk.Label(fattach, text= " Latest Email has attachment\n" + "Filename: " + file_name + "\n" + "Fron: " + msg['From'] + "\n" + "Subject: " + msg['Subject'] + "\n" + "Date: " + msg['Date'], fg='yellow', bg='black').pack()
fattach.after(5000, lambda: fattach.destroy()) # time in ms
fattach.mainloop()
while True:
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
if data[0].split()[-1] == latest_email_uid:
time.sleep(120) # value here once per minute is already considered fairly aggressive by many IMAP server admins. Depending on your application and expected
else:
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 ID7
raw_email = data[0][1]
# "---------------------------------------------------------"
# "Are there links in the email?"
# "---------------------------------------------------------"
msg = email.message_from_string(raw_email)
for part in msg.walk():
# each part is a either non-multipart, or another multipart message
# that contains further parts... Message is organized like a tree
if part.get_content_type() == 'text/html':
html_text = part.get_payload()
if any(word in html_text for word in word):
flink()
else:
pass
# "---------------------------------------------------------"
# "Are there attachments?"
# "---------------------------------------------------------"
for part in msg.walk():
attach = part.get_content_type()
file_name = part.get_filename()
if file_name == None:
pass
else:
fattach()
mail.close()
time.sleep(120)
EDIT: Ok so I got this far and I can get the loop to find a message with just a link in the email body (the first elif) yet nothing else works. As when sending an attachment that should make my file_name != to None now, yes?
msg = email.message_from_string(raw_email)
for part in msg.walk():
attach = part.get_content_type()
file_name = part.get_filename()
# each part is a either non-multipart, or another multipart message
# that contains further parts... Message is organized like a tree
if part.get_content_type() == 'text/html':
html_text = part.get_payload()
text = any(word in html_text for word in word)
if text == True and file_name != None:
print "file name and attachment"
elif text == True and file_name == None:
print "Just link in text"
elif text == False and file_name != None:
print "just an attachment"
You are needlessly doing the walk
twice. Just call both functions within the same loop.
maybe = False
msg = email.message_from_string(raw_email)
for part in msg.walk():
if part.get_content_type() == 'text/html':
html_text = part.get_payload()
if any(word in html_text for word in word):
maybe = True
else:
attach = part.get_content_type()
file_name = part.get_filename()
if file_name == None:
pass
else:
maybe = True
mail.close()
if maybe:
# display message
If you want the message to reflect in more detail whether there was a link or an attachment or both, you can change the maybe
flag variable from a simple boolean to e.g. a set
which you pass to the message display function to indicate what strings exactly to populate the message dialog with.