This is my first attempt at an email client. It does not handle all email. It's setup for plain text. Will handle some multipart but I have it setup to remove some html tags. Current setting will poll mail server once a minute. Right clicking on the subject will delete. As all my scripts this was done on a linux system so I do not know how it will look on a windows system.
As always I welcome all comments. I tested on my own personal mail server so, I do not know if it works on servers like gmail, yahoo, etc...
As always I welcome all comments. I tested on my own personal mail server so, I do not know if it works on servers like gmail, yahoo, etc...
#! /usr/bin/env python3 # Do the imports import imaplib import email import tkinter as tk from functools import partial import re # Set mail server connection vars user = '' passwd = '' server = '' def cleaner(tags): cleanr = re.compile('<.*?>|&([a-z0-9]+|#[0-9]{1,6}|#x[0-9a-f]{1,6});') cleantext = re.sub(cleanr, '', tags) return cleantext class Mail: def __init__(self, parent): # Configure the root window self.parent = parent self.parent.columnconfigure(0, weight=1) self.parent.rowconfigure(0, weight=1) # Get screen width & height self.width = self.parent.winfo_screenwidth() self.height = self.parent.winfo_screenheight() # Setup the mainframe container. self.mainframe = tk.Frame(self.parent) self.mainframe['width'] = int(self.width/2) self.mainframe['height'] = int(self.height/2) self.mainframe.grid(column=0, row=0, sticky='new') self.mainframe.grid_columnconfigure(0, weight=3) self.mainframe.grid_rowconfigure(0, weight=3) # Setup header frame to place our widget header self.headerframe = tk.Frame(self.mainframe) self.headerframe['width'] = int((self.width/2)-1) self.headerframe['relief'] = 'ridge' self.headerframe['borderwidth'] = 2 self.headerframe.grid(column=0, row=0, sticky='new') self.headerframe.grid_columnconfigure(0, weight=3) # Setup the mini header frame. This will hold the labels # for the inbox and messages labels self.mini_headerframe = tk.Frame(self.mainframe) self.mini_headerframe.grid(column=0, row=1, sticky='new', pady=3) self.mini_headerframe.grid_columnconfigure(0, weight=1) self.mini_headerframe.grid_columnconfigure(1, weight=10) # Setup the subject frame self.subjectframe = tk.Frame(self.mini_headerframe) self.subjectframe['relief'] = 'solid' self.subjectframe['borderwidth'] = 1 self.subjectframe['border'] = 0 self.subjectframe['highlightthickness'] = 1 self.subjectframe['highlightbackground'] = 'grey65' self.subjectframe.grid(column=0, row=1, sticky='news', pady=2, ipady=2) # Message frame self.message_frame = tk.Frame(self.mini_headerframe) self.message_frame['relief'] = 'solid' self.message_frame['borderwidth'] = 1 self.message_frame['border'] = 0 self.message_frame['bg'] = 'white' self.message_frame['highlightthickness'] = 1 self.message_frame['highlightbackground'] = 'grey65' self.message_frame.grid(column=1, row=1, sticky='news', pady=2, ipady=2) #Setup the inbox label self.inbox_label = tk.Label(self.mini_headerframe) self.inbox_label['text'] = 'Inbox' self.inbox_label['font'] = 'sans 10 bold' self.inbox_label['relief'] = 'solid' self.inbox_label['borderwidth'] = 1 self.inbox_label['border'] = 0 self.inbox_label['highlightthickness'] = 1 self.inbox_label['highlightbackground'] = 'grey65' self.inbox_label['width'] = 50 self.inbox_label.grid(column=0, row=0, sticky='new') # Setup the messages label self.msg_label = tk.Label(self.mini_headerframe) self.msg_label['text'] = 'Messages' self.msg_label['font'] = 'sans 10 bold' self.msg_label['relief'] = 'solid' self.msg_label['borderwidth'] = 1 self.msg_label['border'] = 0 self.msg_label['highlightthickness'] = 1 self.msg_label['highlightbackground'] = 'grey65' self.msg_label['width'] = 80 self.msg_label.grid(column=1, row=0, sticky='new') # Setup the header label self.header_label = tk.Label(self.headerframe, padx=5, pady=2) self.header_label['text'] = 'Tkinter Email Client' self.header_label['font'] = 'sans 16 bold' self.header_label['fg'] = 'indigo' self.header_label.grid(column=0, row=0, sticky='new') self.header_label.grid_columnconfigure(0, weight=3) self.scrollbar = tk.Scrollbar(self.message_frame) self.message = tk.Text(self.message_frame, wrap='word', padx=5, pady=3) self.message['width'] = 87 self.message['height'] = 26 self.message['state'] = 'disabled' self.scrollbar.config(command=self.message.yview) self.message.config(yscrollcommand=self.scrollbar.set) self.message.insert(tk.END, ' ') self.scrollbar.grid(column=0, row=0, sticky='ns') self.message.grid(column=1, row=0, sticky='news') self.subjects() def subjects(self): canvas = tk.Canvas(self.subjectframe) canvas['height'] = 450 canvas['bg'] = 'white' canvas['width'] = int(self.width/4) scrollbar = tk.Scrollbar(self.subjectframe, orient='vertical', command=canvas.yview) scrollable_frame = tk.Frame(canvas) scrollable_frame.bind('<Configure>', lambda e: canvas.configure(scrollregion=canvas.bbox('all'))) canvas.create_window((0, 0), window=scrollable_frame, anchor='nw') canvas.configure(yscrollcommand=scrollbar.set) scrollbar.grid(column=0, row=0, sticky='ns') canvas.grid(column=1, row=0, sticky='news') mail = Connect() mail = mail.connect(user, passwd, server) mailbox = GetInbox() uids = mailbox.get_uids(mail) headers = GrabHeader() header = headers.get_headers(mail, uids) i = 0 for heads in header: for head, id in heads.items(): button = tk.Button(scrollable_frame, cursor='hand2', anchor='w', wraplength=430, justify='left') button['text'] = head button['relief'] = 'flat' button['bg'] = 'white' button['fg'] = 'blue' button['activeforeground'] = 'red' button['command'] = partial(self.messagebox, id=id) button['width'] = int(self.width/4) button.grid(column=0, row=i, sticky='ew') button.bind('<Button-3>', partial(self.delete_message, id)) i += 1 mail.close() mail.logout() self.subjectframe.after(60000, self.subjects) def messagebox(self, id): mail = Connect() mail = mail.connect(user, passwd, server) mailbox = GetInbox() uids = mailbox.get_uids(mail) body = GetBody() msg = body.get_body(mail, str(id)) msg = cleaner(msg) self.scrollbar = tk.Scrollbar(self.message_frame) self.message = tk.Text(self.message_frame, wrap='word', padx=5, pady=3) self.message['width'] = 87 self.message['height'] = 26 self.scrollbar.config(command=self.message.yview) self.message.config(yscrollcommand=self.scrollbar.set) self.message['state'] = 'normal' self.message.insert(tk.END,msg) self.message['state'] = 'disabled' self.scrollbar.grid(column=0, row=0, sticky='ns') self.message.grid(column=1, row=0, sticky='news') mail.close() mail.logout() def delete_message(self, id, event): mail = Connect() mail = mail.connect(user, passwd, server) mail.select('inbox') mail.uid('STORE', str(id), '+FLAGS', '\\Deleted') mail.expunge() mail.close() mail.logout() self.subjectframe.after(0, self.subjects) self.message['state'] = 'normal' self.message.delete(1.0, tk.END) self.message['state'] = 'disabled' # Create the connection class class Connect: # Connect to the server and return def connect(self, user, passwd, server): mail = imaplib.IMAP4_SSL(server) mail.login(user, passwd) return mail # Class for doin operations on the inbox class GetInbox: def get_uids(self, mail): mail.select('inbox') result, data = mail.uid('search', None, 'ALL') return data # Class for grabbing message headers and uid class GrabHeader: def get_headers(self, mail, uids): subjects = [] for numbers in range(len(uids[0].split())): uid = uids[0].split()[numbers] result, data = mail.uid('fetch', uid, '(RFC822)') raw_data = data[0][1] raw_data_string = raw_data.decode('utf-8') message = email.message_from_string(raw_data_string) subject = str(email.header.make_header(email.header.decode_header(message['subject']))) subjects.append({subject:int(uid)}) return subjects # Class for retrieving message body class GetBody: def get_body(self, mail, uid): result, data = mail.uid('fetch', uid, '(RFC822)') raw_data = data[0][1] raw_data_string = raw_data.decode('utf-8') message = email.message_from_string(raw_data_string) for part in message.walk(): if part.get_content_type() == 'text/plain': body = part.get_payload(decode=True) return body.decode() else: continue def main(): root = tk.Tk() root.title('Tkinter Email Client') root['pady'] = 5 root['padx'] = 10 root['borderwidth'] = 2 root.resizable(False, False) Mail(root) root.mainloop() if __name__ == '__main__': main()
I welcome all feedback.
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags
Download my project scripts
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags
Download my project scripts