Tkinter email client - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: General (https://python-forum.io/forum-1.html) +--- Forum: News and Discussions (https://python-forum.io/forum-31.html) +--- Thread: Tkinter email client (/thread-28199.html) |
Tkinter email client - menator01 - Jul-09-2020 Just wanted to share the current learning project. Although far from being finished, I the program will get and display email subjects. Refreshes every 5 minutes. I welcome all feedback and thoughts. #! /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 = '' # 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: # Grab the inbox. This could be any box or a list of boxes def inbox(self, mail): status, self.messages = mail.select('inbox') # Grab the ids of the emails and return as a list def get_ids(self, mail): type, data = mail.search(None, 'ALL') mail_ids = data[0] id_list = mail_ids.split() return id_list # Grab the subject headers and ids. Combine for getting the mail body/content def get_headers(self, mail, id_list): # Set some range vars for grabbing mail first = int(id_list[0]) last = int(id_list[-1]) # Create some empty list newids = [] mylist = [] headers = [] # Covert id to int for id in id_list: newids.append(int(id)) # Fetch mails and append to a list for i in range(last, 0, -1): typ, data = mail.fetch(str(i), '(RFC822)') mylist.append(data) # Loop through the list and get subject headers for header in mylist: for response in header: if isinstance(response, tuple): msg = email.message_from_bytes(response[1]) headers.append(msg['subject']) # Combine subjects and their ids and return new_headers = dict(zip(headers, newids)) return new_headers 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') # 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='new', pady=2, ipady=2) 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['highlightthickness'] = 1 self.message_frame['highlightbackground'] = 'grey65' self.message_frame.grid(column=1, row=1, sticky='new', pady=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.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.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.update() def update(self): try: self.subjectframe.destroy() # 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='new', pady=2, ipady=2) i = 0 mail = Connect() mail = mail.connect(user, passwd, server) inbox = GetInbox() messages = inbox.inbox(mail) ids = inbox.get_ids(mail) headers = inbox.get_headers(mail, ids) for subject, id in headers.items(): self.subs = tk.Label(self.subjectframe, padx=5, cursor='hand2', anchor='n') self.subs['text'] = f'{subject} -> {id}' self.subs['font'] = 'sans 10 normal' self.subs.grid(column=0, row=i, sticky='nw') self.subs.bind('<Button-1>', partial(self.get_content, mail, id)) i += 1 mail.close() mail.logout() self.subjectframe.after(10000, self.update) except Exception as error: print(error) # Get the mail body/content def get_content(self, mail, id, event): self.message_frame.destroy() 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['highlightthickness'] = 1 self.message_frame['highlightbackground'] = 'grey65' self.message_frame.grid(column=1, row=1, sticky='new', pady=2) mail = Connect() mail = mail.connect(user, passwd, server) inbox = GetInbox() messages = inbox.inbox(mail) type, data = mail.fetch(str(id), '(RFC822)') print(data) for message in data: if isinstance(message, tuple): msg = email.message_from_bytes(message[1]) if msg.is_multipart(): for line in msg.walk(): content_type = line.get_content_type() body = line.get_payload() if content_type == 'text/plain': body = msg.get_payload() else: content_type = msg.get_content_type() if content_type == 'text/plain': body = msg.get_payload() else: body = msg.get_payload() self.content = tk.Label(self.message_frame, anchor='w', wraplength=420) self.content['text'] = self.cleaner(body).strip() self.content.grid(column=0, row=0, sticky='nw') mail.close() mail.logout() def cleaner(self, tags): cleanr = re.compile('<.*?>|&([a-z0-9]+|#[0-9]{1,6}|#x[0-9a-f]{1,6});') cleantext = re.sub(cleanr, '', tags) return cleantext def main(): root = tk.Tk() root.title('Tkinter Email Client') root['pady'] = 5 root['padx'] = 10 root['borderwidth'] = 2 root.geometry(f'{int(root.winfo_screenwidth()/2)}x{int(root.winfo_screenheight()/2)}') Mail(root) root.mainloop() if __name__ == '__main__': main() RE: Tkinter email client - menator01 - Jul-10-2020 I've ran into a few problems while learning on this project. The one that has got me stuck, After displaying all subjects, and after a few updates, the ids change on which I'm using to fetch the body content. Is there any way to use th message-id to retrieve the body content. Current using fetch(id, '(RFC822)') . Is there another way of fetching current mail body?Any help/thoughts is much appreciated. |