From 0406497b7987b39597a4ac8df93a795558573790 Mon Sep 17 00:00:00 2001 From: oliverclozov Date: Wed, 30 Oct 2019 20:42:23 -0400 Subject: [PATCH 01/18] Fixed a bug in the getEmails function by Changing ['BODY unsubscribe'] in self.imap.search to ['TEXT', 'unsubscribe']. I found the fix in the docs at https://imapclient.readthedocs.io/en/2.1.0/api.html?highlight=search#imapclient.IMAPClient.search. --- AutoUnsubscriber.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/AutoUnsubscriber.py b/AutoUnsubscriber.py index 8ddc46b..b1148aa 100644 --- a/AutoUnsubscriber.py +++ b/AutoUnsubscriber.py @@ -85,7 +85,7 @@ def accessServer(self, readonly=True): ''' def getEmails(self): print('Getting emails with unsubscribe in the body\n') - UIDs = self.imap.search(['BODY unsubscribe']) + UIDs = self.imap.search([u'TEXT','unsubscribe']) raw = self.imap.fetch(UIDs, ['BODY[]']) print('Getting links and addresses\n') for UID in UIDs: @@ -176,7 +176,7 @@ def choice(userInput): break else: print('Invalid choice, please enter \'Y\' or \'N\'.\n') - while True: + '''while True: delete = input('Delete emails from '+str(self.senderList[j][1])+' (Y/N): ') d = choice(delete) if d: @@ -187,6 +187,7 @@ def choice(userInput): break else: print('Invalid choice, please enter \'Y\' or \'N\'.\n') + ''' '''Navigate to selected unsubscribe, 10 at a time''' def openLinks(self): if self.goToLinks != True: @@ -220,7 +221,7 @@ def deleteEmails(self): print('Searching for emails to delete from '+str(self.senderList[i][1])) fromSender = 'FROM '+str(self.senderList[i][1]) '''Search for unsubscribe in body from selected providers''' - DelUIDs = self.imap.search(['BODY unsubscribe', fromSender]) + DelUIDs = self.imap.search(['TEXT','unsubscribe', fromSender]) DelCount = 0 for DelUID in DelUIDs: '''Delete emails from selected providers''' From 6e5d5856b152ab0fa56c528824be02e9066654d5 Mon Sep 17 00:00:00 2001 From: oliverclozov Date: Wed, 30 Oct 2019 20:44:45 -0400 Subject: [PATCH 02/18] Fixed a bug in the getEmails function by Changing ['BODY unsubscribe'] in self.imap.search to ['TEXT', 'unsubscribe']. I found the fix in the docs at https://imapclient.readthedocs.io/en/2.1.0/api.html?highlight=search#imapclient.IMAPClient.search. --- AutoUnsubscriber.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/AutoUnsubscriber.py b/AutoUnsubscriber.py index b1148aa..4dfb206 100644 --- a/AutoUnsubscriber.py +++ b/AutoUnsubscriber.py @@ -176,7 +176,7 @@ def choice(userInput): break else: print('Invalid choice, please enter \'Y\' or \'N\'.\n') - '''while True: + while True: delete = input('Delete emails from '+str(self.senderList[j][1])+' (Y/N): ') d = choice(delete) if d: @@ -187,7 +187,6 @@ def choice(userInput): break else: print('Invalid choice, please enter \'Y\' or \'N\'.\n') - ''' '''Navigate to selected unsubscribe, 10 at a time''' def openLinks(self): if self.goToLinks != True: From f5507c94d3580a8cd5ce089c3b860bef8ef25a5a Mon Sep 17 00:00:00 2001 From: oliverclozov Date: Wed, 30 Oct 2019 20:45:29 -0400 Subject: [PATCH 03/18] Fixed a bug in the getEmails function by Changing ['BODY unsubscribe'] in self.imap.search to ['TEXT', 'unsubscribe']. I found the fix in the docs at https://imapclient.readthedocs.io/en/2.1.0/api.html?highlight=search#imapclient.IMAPClient.search. --- AutoUnsubscriber.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AutoUnsubscriber.py b/AutoUnsubscriber.py index 4dfb206..da04b6b 100644 --- a/AutoUnsubscriber.py +++ b/AutoUnsubscriber.py @@ -176,7 +176,7 @@ def choice(userInput): break else: print('Invalid choice, please enter \'Y\' or \'N\'.\n') - while True: + while True: delete = input('Delete emails from '+str(self.senderList[j][1])+' (Y/N): ') d = choice(delete) if d: From b16541c5d0647b91218cdee2c444d0c4d848d1bd Mon Sep 17 00:00:00 2001 From: Kailii Date: Thu, 10 Mar 2022 20:39:50 -0800 Subject: [PATCH 04/18] Added Support for adding your own IMAP Server! Added GMX too! --- AutoUnsubscriber.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/AutoUnsubscriber.py b/AutoUnsubscriber.py index da04b6b..cfc3727 100644 --- a/AutoUnsubscriber.py +++ b/AutoUnsubscriber.py @@ -13,14 +13,13 @@ ('Hotmail','imap-mail.outlook.com'),('Yahoo','imap.mail.yahoo.com'), ('ATT','imap.mail.att.net'),('Comcast','imap.comcast.net'), ('Verizon','incoming.verizon.net'),('AOL','imap.aol.com'), - ('Zoho','imap.zoho.com')] + ('Zoho','imap.zoho.com'),('GMX','imap.gmx.com')] #add to words if more words found '''Key words for unsubscribe link - add more if found''' words = ['unsubscribe','subscription','optout'] class AutoUnsubscriber(): - def __init__(self): self.email = '' self.user = None @@ -40,8 +39,8 @@ def __init__(self): '''Get initial user info - email, password, and service provider''' def getInfo(self): print('This program searchs your email for junk mail to unsubscribe from and delete') - print('Suported emails: Gmail, Outlook, Hotmail, Yahoo, AOL, Zoho,') - print('AT&T, Comcast, and Verizon') + print('Supported emails: Gmail, Outlook, Hotmail, Yahoo, AOL, Zoho,') + print('GMX, AT&T, Comcast, and Verizon') print('Please note: you may need to allow access to less secure apps') getEmail = True while getEmail: @@ -54,6 +53,13 @@ def getInfo(self): getEmail = False break if self.user == None: + print('\nEmail type not recognized, enter an imap server, or press enter to try a different email address:\n') + myimap = input('\n[myimapserver.tld] | [enter] : ') + if myimap: + self.user = ('Self-defined IMAP', myimap) + print('\nYou are using a'+self.user[0]+' account!\n') + getEmail = False + break print('\nNo useable email type detected, try a different account') self.password = getpass.getpass('Enter password for '+self.email+': ') From 09a3528b5dfc6fa86ff9b563895ba9a013b9c425 Mon Sep 17 00:00:00 2001 From: Kailii Date: Tue, 15 Mar 2022 17:15:16 -0700 Subject: [PATCH 05/18] Fixed delete function: deletes all messages from the sender who you unsubscribed from now, not sure if that's different functionality than desired (it might've only deleted the emails with 'unsubscribe' in the body before). But anyways now deleting newsletter emails is fixed! --- AutoUnsubscriber.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/AutoUnsubscriber.py b/AutoUnsubscriber.py index cfc3727..3be7344 100644 --- a/AutoUnsubscriber.py +++ b/AutoUnsubscriber.py @@ -57,7 +57,7 @@ def getInfo(self): myimap = input('\n[myimapserver.tld] | [enter] : ') if myimap: self.user = ('Self-defined IMAP', myimap) - print('\nYou are using a'+self.user[0]+' account!\n') + print('\nYou are using a '+self.user[0]+' account!\n') getEmail = False break print('\nNo useable email type detected, try a different account') @@ -223,10 +223,10 @@ def deleteEmails(self): DelTotal = 0 for i in range(len(self.senderList)): if self.senderList[i][4] == True: - print('Searching for emails to delete from '+str(self.senderList[i][1])) - fromSender = 'FROM '+str(self.senderList[i][1]) + sender=str(self.senderList[i][1]) + print('Searching for emails to delete from '+sender) '''Search for unsubscribe in body from selected providers''' - DelUIDs = self.imap.search(['TEXT','unsubscribe', fromSender]) + DelUIDs = self.imap.search([u'FROM', sender]) DelCount = 0 for DelUID in DelUIDs: '''Delete emails from selected providers''' From d1d7476e960793ba63f1467d1b69042aed755313 Mon Sep 17 00:00:00 2001 From: Kailii Date: Tue, 15 Mar 2022 17:34:37 -0700 Subject: [PATCH 06/18] Updated Comments --- AutoUnsubscriber.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AutoUnsubscriber.py b/AutoUnsubscriber.py index 3be7344..499d5b7 100644 --- a/AutoUnsubscriber.py +++ b/AutoUnsubscriber.py @@ -210,8 +210,8 @@ def openLinks(self): counter = 0 '''Log back into IMAP servers, NOT in readonly mode, and delete emails from - selected providers. Note: only deleting emails with unsubscribe in the body. - Emails from provider without unsubscribe in the body will not be deleted. + selected providers. Note: Deletes all emails from unsubscribed sender. + Emails from provider without unsubscribe in the body will be deleted. ''' def deleteEmails(self): if self.delEmails != True: From a9e9c3feeaf8e46cc91504de892c27543ce8393e Mon Sep 17 00:00:00 2001 From: Kailii Date: Tue, 15 Mar 2022 17:37:03 -0700 Subject: [PATCH 07/18] Updated other comment --- AutoUnsubscriber.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AutoUnsubscriber.py b/AutoUnsubscriber.py index 499d5b7..fd4292f 100644 --- a/AutoUnsubscriber.py +++ b/AutoUnsubscriber.py @@ -225,7 +225,7 @@ def deleteEmails(self): if self.senderList[i][4] == True: sender=str(self.senderList[i][1]) print('Searching for emails to delete from '+sender) - '''Search for unsubscribe in body from selected providers''' + '''Search for UID from selected providers''' DelUIDs = self.imap.search([u'FROM', sender]) DelCount = 0 for DelUID in DelUIDs: From 0924f8f0be664d9c60ee7e5c31b8700c8502dc84 Mon Sep 17 00:00:00 2001 From: Kailii Date: Tue, 15 Mar 2022 19:43:21 -0700 Subject: [PATCH 08/18] Fixed problem with weird emails without bodies that kept the script from running --- AutoUnsubscriber.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/AutoUnsubscriber.py b/AutoUnsubscriber.py index fd4292f..6db40c8 100644 --- a/AutoUnsubscriber.py +++ b/AutoUnsubscriber.py @@ -67,7 +67,7 @@ def getInfo(self): def login(self, read=True): try: self.imap = imapclient.IMAPClient(self.user[1], ssl=True) - self.imap._MAXLINE = 10000000 + #self.imap._MAXLINE = 10000000 self.imap.login(self.email, self.password) self.imap.select_folder('INBOX', readonly=read) print('\nLog in successful\n') @@ -95,8 +95,12 @@ def getEmails(self): raw = self.imap.fetch(UIDs, ['BODY[]']) print('Getting links and addresses\n') for UID in UIDs: - '''Get address and check if sender already in senderList''' - msg = pyzmail.PyzMessage.factory(raw[UID][b'BODY[]']) + '''If Body exists (resolves weird error with no body emails from Yahoo), then + Get address and check if sender already in senderList ''' + if b'BODY[]' in raw[UID]: msg = pyzmail.PyzMessage.factory(raw[UID][b'BODY[]']) + else: + print("Odd Email at UID: "+str(UID)+"; SKIPPING....") + continue sender = msg.get_addresses('from') trySender = True for spammers in self.senderList: From 99cbf2ba6049b186c0f6cf40451ac9c4a7911c98 Mon Sep 17 00:00:00 2001 From: Kailii Date: Tue, 15 Mar 2022 19:55:53 -0700 Subject: [PATCH 09/18] Fixed problem with non-existent bodies in messages (From Yahoo!?) stopping script from running. Also fixed deletion, script now also deletes all emails from the sender. --- AutoUnsubscriber.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/AutoUnsubscriber.py b/AutoUnsubscriber.py index cfc3727..6db40c8 100644 --- a/AutoUnsubscriber.py +++ b/AutoUnsubscriber.py @@ -57,7 +57,7 @@ def getInfo(self): myimap = input('\n[myimapserver.tld] | [enter] : ') if myimap: self.user = ('Self-defined IMAP', myimap) - print('\nYou are using a'+self.user[0]+' account!\n') + print('\nYou are using a '+self.user[0]+' account!\n') getEmail = False break print('\nNo useable email type detected, try a different account') @@ -67,7 +67,7 @@ def getInfo(self): def login(self, read=True): try: self.imap = imapclient.IMAPClient(self.user[1], ssl=True) - self.imap._MAXLINE = 10000000 + #self.imap._MAXLINE = 10000000 self.imap.login(self.email, self.password) self.imap.select_folder('INBOX', readonly=read) print('\nLog in successful\n') @@ -95,8 +95,12 @@ def getEmails(self): raw = self.imap.fetch(UIDs, ['BODY[]']) print('Getting links and addresses\n') for UID in UIDs: - '''Get address and check if sender already in senderList''' - msg = pyzmail.PyzMessage.factory(raw[UID][b'BODY[]']) + '''If Body exists (resolves weird error with no body emails from Yahoo), then + Get address and check if sender already in senderList ''' + if b'BODY[]' in raw[UID]: msg = pyzmail.PyzMessage.factory(raw[UID][b'BODY[]']) + else: + print("Odd Email at UID: "+str(UID)+"; SKIPPING....") + continue sender = msg.get_addresses('from') trySender = True for spammers in self.senderList: @@ -210,8 +214,8 @@ def openLinks(self): counter = 0 '''Log back into IMAP servers, NOT in readonly mode, and delete emails from - selected providers. Note: only deleting emails with unsubscribe in the body. - Emails from provider without unsubscribe in the body will not be deleted. + selected providers. Note: Deletes all emails from unsubscribed sender. + Emails from provider without unsubscribe in the body will be deleted. ''' def deleteEmails(self): if self.delEmails != True: @@ -223,10 +227,10 @@ def deleteEmails(self): DelTotal = 0 for i in range(len(self.senderList)): if self.senderList[i][4] == True: - print('Searching for emails to delete from '+str(self.senderList[i][1])) - fromSender = 'FROM '+str(self.senderList[i][1]) - '''Search for unsubscribe in body from selected providers''' - DelUIDs = self.imap.search(['TEXT','unsubscribe', fromSender]) + sender=str(self.senderList[i][1]) + print('Searching for emails to delete from '+sender) + '''Search for UID from selected providers''' + DelUIDs = self.imap.search([u'FROM', sender]) DelCount = 0 for DelUID in DelUIDs: '''Delete emails from selected providers''' From 3e70616caaff9918c2ec54da85e1fd3b9df88000 Mon Sep 17 00:00:00 2001 From: Kailii Date: Tue, 15 Mar 2022 21:11:33 -0700 Subject: [PATCH 10/18] Added support for ProtonMail Bridge --- AutoUnsubscriber.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/AutoUnsubscriber.py b/AutoUnsubscriber.py index 6db40c8..14e615a 100644 --- a/AutoUnsubscriber.py +++ b/AutoUnsubscriber.py @@ -7,13 +7,14 @@ import webbrowser import re import sys +import ssl '''List of accepted service providers and respective imap link''' servers = [('Gmail','imap.gmail.com'),('Outlook','imap-mail.outlook.com'), ('Hotmail','imap-mail.outlook.com'),('Yahoo','imap.mail.yahoo.com'), ('ATT','imap.mail.att.net'),('Comcast','imap.comcast.net'), ('Verizon','incoming.verizon.net'),('AOL','imap.aol.com'), - ('Zoho','imap.zoho.com'),('GMX','imap.gmx.com')] + ('Zoho','imap.zoho.com'),('GMX','imap.gmx.com'),('ProtonMail','127.0.0.1')] #add to words if more words found '''Key words for unsubscribe link - add more if found''' @@ -40,7 +41,7 @@ def __init__(self): def getInfo(self): print('This program searchs your email for junk mail to unsubscribe from and delete') print('Supported emails: Gmail, Outlook, Hotmail, Yahoo, AOL, Zoho,') - print('GMX, AT&T, Comcast, and Verizon') + print('GMX, AT&T, Comcast, ProtonMail (Bridge), and Verizon') print('Please note: you may need to allow access to less secure apps') getEmail = True while getEmail: @@ -66,8 +67,16 @@ def getInfo(self): '''Log in to IMAP server, argument determines whether readonly or not''' def login(self, read=True): try: - self.imap = imapclient.IMAPClient(self.user[1], ssl=True) - #self.imap._MAXLINE = 10000000 + '''ProtonMail Bridge Support - Requires unverified STARTTLS and changing ports''' + if self.user[0]=='ProtonMail': + print("\nProtonMail require ProtonMail Bridge installed, make sure you've used the password Bridge gives you.") + self.context = ssl.create_default_context() + self.context.check_hostname = False + self.context.verify_mode = ssl.CERT_NONE + self.imap = imapclient.IMAPClient(self.user[1], port=1143, ssl=False) + self.imap.starttls(ssl_context=self.context) + else: self.imap = imapclient.IMAPClient(self.user[1], ssl=True) + self.imap._MAXLINE = 10000000 self.imap.login(self.email, self.password) self.imap.select_folder('INBOX', readonly=read) print('\nLog in successful\n') From a3458a5a1df818c78999b09b0ba2ab9edbd16dab Mon Sep 17 00:00:00 2001 From: Kailii Date: Thu, 17 Mar 2022 02:49:13 -0700 Subject: [PATCH 11/18] Code cleanup --- AutoUnsubscriber.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/AutoUnsubscriber.py b/AutoUnsubscriber.py index 14e615a..29517f1 100644 --- a/AutoUnsubscriber.py +++ b/AutoUnsubscriber.py @@ -32,11 +32,13 @@ def __init__(self): self.noLinkList = [] self.wordCheck = [] self.providers = [] - for i in range(len(servers)): - self.providers.append(re.compile(servers[i][0], re.I)) - for i in range(len(words)): - self.wordCheck.append(re.compile(words[i], re.I)) - + #server name is later matched against second level domain names + for server in servers: + self.providers.append(re.compile(server[0], re.I)) + #TODO maybe add support for servers with a + #company name different than their domain name... + for i in words: + self.wordCheck.append(re.compile(i, re.I)) '''Get initial user info - email, password, and service provider''' def getInfo(self): print('This program searchs your email for junk mail to unsubscribe from and delete') @@ -46,8 +48,8 @@ def getInfo(self): getEmail = True while getEmail: self.email = input('\nEnter your email address: ') - for j in range(len(self.providers)): - choice = self.providers[j].search(self.email) + for provider in self.providers): + choice = provider.search(self.email) if choice != None: self.user = servers[j] print('\nLooks like you\'re using a '+self.user[0]+' account\n') @@ -131,13 +133,13 @@ def getEmails(self): soup = bs4.BeautifulSoup(html, 'html.parser') elems = soup.select('a') '''For each anchor tag, use regex to search for key words''' - for i in range(len(elems)): - for j in range(len(self.wordCheck)): - k = self.wordCheck[j].search(str(elems[i])) + for elem in elems: + for word in self.wordCheck: + k = word.search(elem) '''If one is found, get the url''' if k != None: print('Link found') - url = elems[i].get('href') + url = elem.get('href') break if url != False: break From a64f21b26db3dec05c66b2792e003507cb7cc991 Mon Sep 17 00:00:00 2001 From: Kailii Date: Thu, 17 Mar 2022 05:38:01 -0700 Subject: [PATCH 12/18] Code cleanup, added support for multiple and alternative domains, instead of relying on the name of the provider to be in the email address. --- AutoUnsubscriber.py | 90 +++++++++++++++++++++++++++++++++------------ 1 file changed, 66 insertions(+), 24 deletions(-) diff --git a/AutoUnsubscriber.py b/AutoUnsubscriber.py index 29517f1..eaeda4d 100644 --- a/AutoUnsubscriber.py +++ b/AutoUnsubscriber.py @@ -15,8 +15,51 @@ ('ATT','imap.mail.att.net'),('Comcast','imap.comcast.net'), ('Verizon','incoming.verizon.net'),('AOL','imap.aol.com'), ('Zoho','imap.zoho.com'),('GMX','imap.gmx.com'),('ProtonMail','127.0.0.1')] +#Rewrote with dictionaries +serverD = { + 'Gmail': { + 'imap': 'imap.gmail.com', + 'domains': ['@gmail.com'] + }, + 'Outlook/Hotmail': { + 'imap': 'imap-mail.outlook.com', + 'domains': ['@outlook.com','@hotmail.com'] + }, + 'Yahoo': { + 'imap': 'imap.mail.yahoo.com', + 'domains': ['@yahoo.com'] + }, + 'ATT': { + 'imap': 'imap.mail.att.net', + 'domains': ['@att.net'] + }, + 'Comcast': { + 'imap': 'imap.comcast.net', + 'domains': ['@comcast.net'] + }, + 'Verizon': { + 'imap': 'incoming.verizon.net', + 'domains': ['@verizon.net'] + }, + 'AOL': { + 'imap': 'imap.aol.com', + 'domains': ['@aol.com'] + }, + 'Zoho': { + 'imap': 'imap.zoho.com', + 'domains': ['@zoho.com'] + }, + 'GMX': { + 'imap': 'imap.gmx.com', + 'domains': ['@gmx.com'] + }, + 'ProtonMail': { + 'imap': '127.0.0.1', + 'domains': ['@protonmail.com','@pm.me'] + } +} + -#add to words if more words found '''Key words for unsubscribe link - add more if found''' words = ['unsubscribe','subscription','optout'] @@ -30,15 +73,12 @@ def __init__(self): self.delEmails = False self.senderList = [] self.noLinkList = [] - self.wordCheck = [] self.providers = [] #server name is later matched against second level domain names for server in servers: self.providers.append(re.compile(server[0], re.I)) #TODO maybe add support for servers with a #company name different than their domain name... - for i in words: - self.wordCheck.append(re.compile(i, re.I)) '''Get initial user info - email, password, and service provider''' def getInfo(self): print('This program searchs your email for junk mail to unsubscribe from and delete') @@ -47,15 +87,18 @@ def getInfo(self): print('Please note: you may need to allow access to less secure apps') getEmail = True while getEmail: - self.email = input('\nEnter your email address: ') - for provider in self.providers): - choice = provider.search(self.email) - if choice != None: - self.user = servers[j] - print('\nLooks like you\'re using a '+self.user[0]+' account\n') - getEmail = False - break - if self.user == None: + self.email = str.lower(input('\nEnter your email address: ')) + for prov in serverD: + match=False + for domain in serverD[prov]['domains']: + if domain in self.email: + print('\nLooks like you\'re using a '+prov+' account\n') + self.user = (prov, serverD[prov]['imap']) + getEmail = False + match = True + break + if match: break + if self.user is None: print('\nEmail type not recognized, enter an imap server, or press enter to try a different email address:\n') myimap = input('\n[myimapserver.tld] | [enter] : ') if myimap: @@ -63,7 +106,7 @@ def getInfo(self): print('\nYou are using a '+self.user[0]+' account!\n') getEmail = False break - print('\nNo useable email type detected, try a different account') + print('\nTry a different account') self.password = getpass.getpass('Enter password for '+self.email+': ') '''Log in to IMAP server, argument determines whether readonly or not''' @@ -128,27 +171,26 @@ def getEmails(self): print('Searching for unsubscribe link from '+str(senderName)) url = False '''Parse html for elements with anchor tags''' - if msg.html_part != None: - html = msg.html_part.get_payload().decode('utf-8') + if html_piece := msg.html_part: + html = html_piece.get_payload().decode('utf-8') soup = bs4.BeautifulSoup(html, 'html.parser') elems = soup.select('a') '''For each anchor tag, use regex to search for key words''' + elems.reverse() + #search starting at the bottom of email for elem in elems: - for word in self.wordCheck: - k = word.search(elem) + for word in self.words: '''If one is found, get the url''' - if k != None: + if re.match( word, str(elem), re.IGNORECASE): print('Link found') url = elem.get('href') break - if url != False: - break + if url: break '''If link found, add info to senderList format: (Name, email, link, go to link, delete emails) If no link found, add to noLinkList ''' - if url != False: - self.senderList.append([senderName, sender[0][1], url, False, False]) + if url: self.senderList.append([senderName, sender[0][1], url, False, False]) else: print('No link found') notInList = True @@ -298,7 +340,7 @@ def nextMove(self): def fullProcess(self): self.accessServer() self.getEmails() - if self.senderList != []: + if self.senderList: self.decisions() self.openLinks() self.deleteEmails() From 20a6ae697bc0f9dc2f02f95b8f4e7e8386fbd16a Mon Sep 17 00:00:00 2001 From: Justin Knox Date: Fri, 5 Aug 2022 16:19:41 -0400 Subject: [PATCH 13/18] init commit - added pip instructions --- README.txt | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/README.txt b/README.txt index 5ecc878..c4e39bc 100644 --- a/README.txt +++ b/README.txt @@ -4,4 +4,19 @@ It uses IMAP to log into your email. From there, it goes through every email wit After the program has a list of emails and links, for each address in the list, it gives the user the option to navigate to the unsubscribe link and to delete emails with unsubscribe in the body from the sender. -Once the program finishes going through the list, it gives the user the option to run the program again on the same email address, run it on a different email address, or quit the program. \ No newline at end of file +Once the program finishes going through the list, it gives the user the option to run the program again on the same email address, run it on a different email address, or quit the program. + +------ +# Python package Installation + +''' +pip install getpass4 +pip install bs4 +pip install IMAPclient +pip install regex +pip install os-sys +pip install syspath +pip install pyopenssl +pip install pyzmail +pip install pyzmail35 +''' From 05fae778ebb5764dab7c453d6e5f8d3d5c5cd575 Mon Sep 17 00:00:00 2001 From: Justin Knox Date: Fri, 5 Aug 2022 16:25:08 -0400 Subject: [PATCH 14/18] added md for readme --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..c4e39bc --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +This program is an email auto-unsubscriber. Depending on your email provider and settings, it may require you to allow access to less secure apps. + +It uses IMAP to log into your email. From there, it goes through every email with "unsubscribe" in the body, parses the HTML, and uses regex to search through anchor tags for keywords that indicate an unsubscribe link (unsubscribe, optout, etc). If it finds a match, it grabs the href link and puts the address and link in a list. + +After the program has a list of emails and links, for each address in the list, it gives the user the option to navigate to the unsubscribe link and to delete emails with unsubscribe in the body from the sender. + +Once the program finishes going through the list, it gives the user the option to run the program again on the same email address, run it on a different email address, or quit the program. + +------ +# Python package Installation + +''' +pip install getpass4 +pip install bs4 +pip install IMAPclient +pip install regex +pip install os-sys +pip install syspath +pip install pyopenssl +pip install pyzmail +pip install pyzmail35 +''' From 9b94771912f7cf4f9234d2c94a085e1c30835a64 Mon Sep 17 00:00:00 2001 From: Justin Knox Date: Fri, 5 Aug 2022 16:27:19 -0400 Subject: [PATCH 15/18] fixed heading and codeblock --- README.md | 6 +++--- README.md~ | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 README.md~ diff --git a/README.md b/README.md index c4e39bc..670051d 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,9 @@ After the program has a list of emails and links, for each address in the list, Once the program finishes going through the list, it gives the user the option to run the program again on the same email address, run it on a different email address, or quit the program. ------ -# Python package Installation +### Python package Installation -''' +` pip install getpass4 pip install bs4 pip install IMAPclient @@ -19,4 +19,4 @@ pip install syspath pip install pyopenssl pip install pyzmail pip install pyzmail35 -''' +` diff --git a/README.md~ b/README.md~ new file mode 100644 index 0000000..c4e39bc --- /dev/null +++ b/README.md~ @@ -0,0 +1,22 @@ +This program is an email auto-unsubscriber. Depending on your email provider and settings, it may require you to allow access to less secure apps. + +It uses IMAP to log into your email. From there, it goes through every email with "unsubscribe" in the body, parses the HTML, and uses regex to search through anchor tags for keywords that indicate an unsubscribe link (unsubscribe, optout, etc). If it finds a match, it grabs the href link and puts the address and link in a list. + +After the program has a list of emails and links, for each address in the list, it gives the user the option to navigate to the unsubscribe link and to delete emails with unsubscribe in the body from the sender. + +Once the program finishes going through the list, it gives the user the option to run the program again on the same email address, run it on a different email address, or quit the program. + +------ +# Python package Installation + +''' +pip install getpass4 +pip install bs4 +pip install IMAPclient +pip install regex +pip install os-sys +pip install syspath +pip install pyopenssl +pip install pyzmail +pip install pyzmail35 +''' From 3be5037b246ddb3d7c0b5a8cafc373d55c8a58de Mon Sep 17 00:00:00 2001 From: Justin Knox Date: Fri, 5 Aug 2022 16:29:05 -0400 Subject: [PATCH 16/18] fixed heading and codeblock --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 670051d..3584ae7 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Once the program finishes going through the list, it gives the user the option t ------ ### Python package Installation -` +``` pip install getpass4 pip install bs4 pip install IMAPclient @@ -19,4 +19,7 @@ pip install syspath pip install pyopenssl pip install pyzmail pip install pyzmail35 -` +``` + + + From 4aa6a26e08814e6bc5598a1c6ddde936669eecc4 Mon Sep 17 00:00:00 2001 From: Justin Knox Date: Fri, 5 Aug 2022 16:31:45 -0400 Subject: [PATCH 17/18] added title --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 3584ae7..ff0bc3c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +### AutoUnsubscriber + This program is an email auto-unsubscriber. Depending on your email provider and settings, it may require you to allow access to less secure apps. It uses IMAP to log into your email. From there, it goes through every email with "unsubscribe" in the body, parses the HTML, and uses regex to search through anchor tags for keywords that indicate an unsubscribe link (unsubscribe, optout, etc). If it finds a match, it grabs the href link and puts the address and link in a list. From 3f233eece20d02aefce7d38c7adbc07fdcb07d3e Mon Sep 17 00:00:00 2001 From: Kai Date: Wed, 18 Jan 2023 22:23:31 +1300 Subject: [PATCH 18/18] Update pyzmail library number --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ff0bc3c..7be88f0 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ pip install os-sys pip install syspath pip install pyopenssl pip install pyzmail -pip install pyzmail35 +pip install pyzmail39 ```