This was both an exercise after learning some Python and an application I needed as a simple replacement to my dear Digsby on Ubuntu.
It is an email notifier to automatically check mailbox every 60 seconds. In the case of GMail, it was no problem at all, just a couple of lines and I get the new "UnSeen" mail. But for Hotmail, it was a problem because POP3 protocol does not offer this feature. So if you use this script/application for Hotmail, notice that it will notify if any mail arrives after logging in, and notification will still be there until you log in again.
The application deals with one account at a time, but I could run several instances.
The script is not perfect but it did the job on both Ubuntu 10.10 and Windows 7 Professional :)
You can find a compiled version of the script (for linux) here : Download
for compiling the code, I used PyInstaller :
the process was as simple as that:
adly@ubuntu:~/Documents/pyinstaller-1.5$ python Configure.py adly@ubuntu:~/Documents/pyinstaller-1.5$ python Makespec.py --onefile /home/adly/Documents/mail_notifier.py adly@ubuntu:~/Documents/pyinstaller-1.5$ python Build.py /home/adly/Documents/pyinstaller-1.5/mail_notifier/mail_notifier.spec
then the application was created in:
/home/adly/Documents/pyinstaller-1.5/mail_notifier/dist
Script Code:
[mail_notifier.py] Download
from Tkinter import * import imaplib import poplib import re import time import threading #GUI root root = Tk() #variables connecting between core and GUI email = StringVar() password = StringVar() status = StringVar() def checkMail(*args): #check for GMail if re.search(r'@gmail.', email.get()): okbutton.configure(state=DISABLED) gmail = gmailThread() gmail.setDaemon(True) gmail.start() #check for Hotmail/Live accounts elif re.search(r'@hotmail.', email.get()) or re.search(r'@live.', email.get()): okbutton.configure(state=DISABLED) msn = msnThread() msn.setDaemon(True) msn.start() else: status.set("Only GMail/Hotmail/Live accounts accepted!") class gmailThread (threading.Thread): def run(self): try: status.set("Checking inbox. Please wait ...") #gmail only takes username, so some splitting needed usernameString = email.get().split('@')[0] passwordString = password.get() #Working with IMAP protocol in GMail allows to get the number of #"UnSeen" mail. So the Gmail part of this script is just straight #forward. while 1==1: mailObj = imaplib.IMAP4_SSL('imap.gmail.com','993') mailObj.login(usernameString, passwordString) mailObj.select() unreadMail = str(len(mailObj.search(None, 'UnSeen')[1][0].split())) mailObj.close() mailObj.logout() msg = email.get()+"("+unreadMail+")" status.set(msg) #sleep for 60 sec time.sleep(60) except: okbutton.configure(state=NORMAL) status.set("Error occurred! Please check credentials or internet connection.") class msnThread (threading.Thread): def run(self): try: status.set("You will get notification of any new mail(s) since login ...") usernameString = email.get() passwordString = password.get() #get list of email unique ids mailObj = poplib.POP3_SSL('pop3.live.com', 995) mailObj.user(usernameString) mailObj.pass_(passwordString) mailList = mailObj.uidl()[1] mailObj.quit() #the only thing to do is to get the id of newest email and #check if it exists in the list above, if it does not exist #then it is a new email. So actually user can only notice #any new mail that came after the first login, this is all #because POP3 protocol does not give data about new mail and #what i made was just a simple solution while 1==1: time.sleep(60) mailObj = poplib.POP3_SSL('pop3.live.com', 995) mailObj.user(usernameString) mailObj.pass_(passwordString) newestMailId = mailObj.uidl()[1][-1] if newestMailId not in mailList: status.set("New mail(s) arrived since last login!") mailObj.quit() except: okbutton.configure(state=NORMAL) status.set("Error occurred! Please check credentials or internet connection.") ########## GUI section ########### root.title("GMail/Hotmail Notifier") mainframe = Frame(root) mainframe.grid(column=0, row=0, sticky=(N, W, E, S)) mainframe.columnconfigure(0, weight=1) mainframe.rowconfigure(0, weight=1) #email emailLabel = Label(mainframe, text="Email:") emailLabel.grid(column=1, row=1, sticky=W) emailEntry = Entry(mainframe, width=30, textvariable=email) emailEntry.grid(column=2, row=1, sticky=(W,E)) #password passwordLabel = Label(mainframe, text="Password:") passwordLabel.grid(column=1, row=2, sticky=W) passwordEntry = Entry(mainframe, width=30, textvariable=password, show="*") passwordEntry.grid(column=2, row=2, sticky=(W,E)) #ok button okbutton = Button(mainframe, text="ok", command=checkMail ) okbutton.grid(column=2, row=3, sticky=E) #status bar statusLabel = Label(mainframe, textvariable=status) statusLabel.grid(column=1, row=4, columnspan=2, sticky=W) #capture focus on start emailEntry.focus() #capture the "enter" key for usability emailEntry.bind('<Return>', checkMail) passwordEntry.bind('<Return>', checkMail) root.bind('<Return>', checkMail) root.mainloop()
Resources:
- Tutorials Point - Python
- DeveloperWorks: Practical Threaded Programming with Python
- StackOverflow: Daemon Threads Explanation
- Java2S: PythonExamples
- Tkinter 8.4 reference: a GUI for Python [this is the current code for my GUI]
- An Introduction to Tkinter
- Compiling Python Code
- TkDocs [note: faced some problems as I needed Python3 which conflicted with some other core code]
- Python.org: Tkinter [some helpful links]
- StackOverflow: Check unread count of Gmail messages with Python
- k0d.cc: Multi Account Checker Gmail-Hotmail-Yahoo
- StackOverflow: Python Hotmail login
- Python docs: IMAP4 protocol - POP3 protocol