Make Python delete your unwanted emails periodically.-SaralGyaan


  • Jan. 9, 2019, 3:54 p.m.
  • 6 minutes read
  • 1 Comment
  • 708 Views

There was a time when you will run to the mailbox outside your home at a fixed time and check your mail and segregate the crap out of it manually. But today, we all live in a digital era where the mail keeps on getting delivered to your electronic mailboxes throughout the day. All the mails received in your mailboxe are not important and there are tools like spam filters and unsubcribe optons to get rid of them. However, there are certain kinds of emails which do not exactly fall into the above two categories, one of the most common example is OTPs received from credit cards and banks. You won’t like to add them into your spambox or unsubscribe them.

If you are using a google mail account, google has come up with an API which can be seamlessly used with python to auto-delete your mails. Let’s walk through the steps one by one.

First of all visit https://developers.google.com/gmail/api/quickstart/pythonpython_gmail_api_integration_by_saralgyaan.PNG

Login with the desired credentials and select a name for your project. python_gmail_api_integration_saralgyaan.png

Download Client Configuration will download the required ‘credentials.json’ file. Save it in a folder in which you are going to create the python script.

Learn_python_easy_way_saralgyaan.png

Now, we will use pip to download the desired modules i.e. google api and oauthclient

pip install --upgrade google-api-python-client oauth2client

Now time to create a python file and start coding. Let’s name it auto_delete.py. Just make sure that this script is created in the folder containing the ‘credentials.json’ file above. Since, we later will be hosting this script on PythonAnywhere and we need it to run in Python 3.6. Let’s add the shebang at the very top of it.

#!/usr/bin/python3.6

Now we will make the necessary imports.

import os
from googleapiclient.discovery import build
from httplib2 import Http
from oauth2client import file, client, tools
from apiclient import errors

Since, we will be hosting this script on a cloud i.e. PythonAnywhere , it is better of to log the stuff to have some idea of what is going on daily. So quickly punch in the basic logging stuff. If it is bit overwhelming for you, just copy and paste it as soon we will be coming up with a basic tutorial on logging too.

import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s:%(name)s:%(message)s')
file_handler = logging.FileHandler('auto_delete.log')
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)

The script will be used to delete the email messages, so we need both read and write privileges. The same is called scope in terms of google email api

SCOPES = 'https://mail.google.com/' # read-write mode

We will be needing a service to access our mailbox and since we will be using a function called ‘init’ to create the same, for now we will be setting it to none.

SERVICE = None

Create a function init, which will take three variables- user_id, token_file, credentials_file.

user_id : In all the cases we will be using ‘me’ as user_id which depicts the user for whom the credentials.json file has been downloaded in the steps above.

credentials_file: It is the ‘credentials.json’ downloaded above, note that this file must exist in the directory containing the script i.e. ‘auto_delete.py’.

token_file: When the init function will be run for the very first time, it will open the browser and ask you to login to the desired gmail account(the one for which the ‘credentials.json’ file has been created.) and ‘token.json’ will be created in the same parent directory. If you ever change the ‘SCOPE’ defined above, you need to delete the token.json and re-generate the same.

def init(user_id='me', token_file='token.json', credentials_file='credentials.json'): global SERVICE if not os.path.exists(credentials_file): raise AutoDeleteException('Can\'t find credentials file at %s. You can download this file from https://developers.google.com/gmail/api/quickstart/python and clicking "Enable the Gmail API"' % (os.path.abspath(credentials_file))) store = file.Storage(token_file) creds = store.get() if not creds or creds.invalid: flow = client.flow_from_clientsecrets(credentials_file, SCOPES) creds = tools.run_flow(flow, store) SERVICE = build('gmail', 'v1', http=creds.authorize(Http()))

In order to raise a custom exception in case of non missing ‘credentials.json’, we will be creating a class for that exception as under:-

class AutoDeleteException(Exception): pass

Now we will run the init() method using the following codes. If there is no error in the script, it will take you to the browser and ask you for the login credentials for which ‘credentials.json’ file was created. This will create a ‘token.json’ file in the same parent directory. Note that if you ever change the scope, you need to delete the ‘token.json’ and run init() again to re-create the ‘token.json’ file.

if __name__ == '__main__': init()

Now let’s create a search function with variables ‘query’ and user_id = ‘me’ to search for the messages matching the query.

The query will be set of queries as we will enter in the searchbox of gmail e.g.

label:UNREAD
from:abc@email.com subject:”hello”

has:attachment

for more details you can visit https://support.google.com/mail/answer/7190?hl=en

Run the init() method to create the “SERVICE”

def search(query, user_id='me'): if SERVICE is None: init()

The following code will return a list of gmail thread objects matching the query. The gmail thread object is basically a dictionary with keys ‘id’ and ‘threadId’-

{'id': '15573cf1adfassafas', 'threadId': '15573cf1adfassafas'}

We will need the value of ‘id’ in our next function to delete the messages matching the query.

 try: response = SERVICE.users().messages().list(userId=user_id, q=query).execute() messages = [] if 'messages' in response: messages.extend(response['messages']) while 'nextPageToken' in response: page_token = response['nextPageToken'] response = SERVICE.users().messages().list(userId=user_id, q=query, pageToken=page_token).execute() messages.extend(response['messages']) return messages except errors.HttpError as e: logger.exception(f'An error occurred:{e}') 

So far so good, now create our last function to delete the messages matching the query. You must remember that this will permanently delete the message and won’t send it to the trash.So please use it with some caution.

def delete_messages(query, user_id='me'): messages = search(query) if messages: for message in messages: SERVICE.users().messages().delete(userId=user_id, id=message['id']).execute() logger.info(f'Message with id: {message["id"]} deleted successfully.') else: logger.info("There was no message matching the query.")

To run the script, let’s add the most loved dunders :P

if __name__ == '__main__': logger.info("Deleting messages from abc@gmail.com.") delete_messages('from:abc@gmail.com\ subject:"Go Shopping"\ older_than:1d' )

You can watch the entire tutorial on youtube too

Read this post to learn how to host the script on PythonAnywhere and schedule it to run daily.

Complete code for the same can be found at https://gist.github.com/saralgyaan/bb005d371bcf0bacd9cec06e21708a50

एक समय था जब आप एक निश्चित समय पर अपने घर के बाहर लगे मेलबॉक्स की ओर भागते थे और अपने पत्रों की जांच करते थे ओर बेकार की डाक कूड़ेदान में फेंक देते थे। लेकिन आज, हम सभी एक डिजिटल युग में रहते हैं, जहां दिन भर आपके इलेक्ट्रॉनिक मेलबॉक्सक पर मेल आती रहती है। आपके मेलबॉक्स में प्राप्त सभी मेल महत्वपूर्ण नहीं हैं और इनसे छुटकारा पाने के लिए स्पैम फिल्टर और अनसब्सक्राइब जैसे ऑप्शन हैं। हालांकि, कुछ प्रकार के ईमेल हैं जो वास्तव में उपरोक्त दो श्रेणियों में नहीं आते हैं, सबसे आम उदाहरण क्रेडिट कार्ड और बैंकों से प्राप्त ओटीपी है। आप उन्हें अपने स्पैमबॉक्स में जोड़ना या उन्हें अनसब्सक्राइब करना पसंद नहीं करेंगे।

यदि आप एक Google मेल खाते का उपयोग कर रहे हैं, तो Google एक एपीआई लेकर आया है, जो आपके मेल को ऑटो-डिलीट करने के लिए Python के साथ मूल रूप से उपयोग किया जा सकता है। एक-एक करके सभी स्टेप्स करते है।

आप ये टूटोरीयल youtube पर भी देख सकते है।

सबसे पहले https://developers.google.com/gmail/api/quickstart/python खोलें python_gmail_api_integration_by_saralgyaan.PNG

अपने यूसरनेम व पासवर्ड के साथ लॉगिन करें व अपने प्रोजेक्ट का नाम चुने।
python_gmail_api_integration_saralgyaan.png

‘Download Client Configuration’ पर क्लिक करने से ‘credentials.json’ नामक फ़ाइल डाउन्लोड होगी जिसे की आपने उसी फोंल्डर मे रखना है जिसमे आप Python की स्क्रिप्ट बनाने जा रहें है।

Learn_python_easy_way_saralgyaan.png

अभ हम इस्तमाल में आने वाले modules- google api व oauthclient को pip के द्वारा इन्स्टाल करेंगे।

pip install --upgrade google-api-python-client oauth2client

अभ एक python फ़ाइल बनाने ओर कोड लिखने की बारी है। हम इस फ़ाइल को auto_delete.py रखते है। हमें बस इस बात का ध्यान रखना है कि यह फ़ाइल हम उसी फोंल्डर मे बनाए जिसमे हमने ‘credentials.json’ को डाउनलोड किया है। क्युंकी हम इस script को PythonAnywhere पर host करने वाले है ओर हम चाहते है कि यह Python 3.6 में चले, हम सबसे ऊपर shebang add करेंगे।

#!/usr/bin/python3.6

जरूरत में आने वाले modules इम्पोर्ट करेंगे

import os
from googleapiclient.discovery import build
from httplib2 import Http
from oauth2client import file, client, tools
from apiclient import errors

क्यूंकी हम इस script को एक cloud सर्विस यानि के PythonAnywhere पर होस्ट करने वालें हैं, बेहतर होगा कि हम logging module कि सहायता से कुछ steps का log तयार करलें। इसके लिए हम logging module के बेसिक कोड का इस्तमाल करेंगे। अगर आपको यह step समझ नहीं आ रहा तो अभ के लिए आप इसे कॉपी/पेस्ट करलें, हम बहुत ही जल्द इसपर एक tutorial शृंखला ला रहें।

import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s:%(name)s:%(message)s')
file_handler = logging.FileHandler('auto_delete.log')
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)

इस स्क्रिप्ट का इस्तमाल gmail अकाउंट से ईमेल को डिलीट करने के लिए होगा। इसलिए हमें read/write privilege चाहिए होगी जिसे के ‘gmail api’ की भाषा में ‘SCOPE’ कहते हैं।

SCOPES = 'https://mail.google.com/' # read-write mode

मेल-बॉक्स को access करने के लिए हमे एक service की जरूरत होगी। चूंकि हम उस service का निर्माण init() method से करेंगे, अभ के लिए हम इसे None set करेंगे।
SERVICE = None
init() नामक एक function बनायें जो के 3 variable accept करेगा- user_id, token_file, credentials_file

user_id: इसकी default value ‘me’ होगी ओर यह उस account को दर्शाती है जिसके द्वारा हमने शुरुआत में ‘credentials.json’ file डाउन्लोड की थी।

credentials_file: यह डाउन्लोड की गई ‘credentials.json’ file है। ध्यान रखिए के यह auto_delete.py वाले फोंल्डर मे है।
token_file : जभ init() method को run किया जाएगा तो हमें browser में अपनी यूसरनेम व पासवर्ड भरके लॉगिन करना पड़ेगा (वही login credentials जिसके साथ ‘credentials.json’ डाउन्लोड की थी। इस से ‘token.json’ नाम की फ़ाइल डाउन्लोड होगी। अगर आप कभी भी ‘SCOPE’ बदलते है तो आपको यह दुबारा run करना पड़ेगा।

def init(user_id='me', token_file='token.json', credentials_file='credentials.json'): global SERVICE if not os.path.exists(credentials_file): raise AutoDeleteException('Can\'t find credentials file at %s. You can download this file from https://developers.google.com/gmail/api/quickstart/python and clicking "Enable the Gmail API"' % (os.path.abspath(credentials_file))) store = file.Storage(token_file) creds = store.get() if not creds or creds.invalid: flow = client.flow_from_clientsecrets(credentials_file, SCOPES) creds = tools.run_flow(flow, store) SERVICE = build('gmail', 'v1', http=creds.authorize(Http()))

हम ‘credentials.json’ के miss होने पे एक custom exception raise कर रहें है, इसलिए हम उस exception के लिए एक class का निर्माण करेंगे।

class AutoDeleteException(Exception): pass

अभ हम निम्नलिखित कोड से init() method को रन करेंगे। अगर आपकी स्क्रिप्ट में कोई error नहीं है तो ‘token.json’ फ़ाइल डाउन्लोड हो जाएगी। इस बात का ध्यान रखें के अगर आप कभी भी SCOPE को बदलते है तो आपको init() method run करके दुबारा ‘token.json’ डाउन्लोड होगी।

if __name__ == '__main__': init()

अभ हम search() method बनाएँगे जो के दो variable ‘query’ व user_id = ‘me’ लेकर query से मिलने वाले emails search करेगा।

Query उसी प्रकार की होगी जैसी की हम gmail के searchbox मे लिखते है। उदाहरण स्वरूप

label:UNREAD
from:abc@email.com subject:”hello”

has:attachment

ज्यादा जानकारी के लिए https://support.google.com/mail/answer/7190?hl=en देखें

“SERVICE” create karne के लिए init() method चलाये

def search(query, user_id='me'): if SERVICE is None: init()

निम्नलिखित कोड query को मैच करने वाले gmail thread objects की एक list return करेगा। Gmail thread object एक python dictionary है जिसकी keys ‘id’ and ‘threadId’ हैं-

{'id': '15573cf1adfassafas', 'threadId': '15573cf1adfassafas'}

हमे अपने अगले function में query से match करने वाले messages को delete करने के लिए ‘id’ की जरूरत पड़ेगी।

 try: response = SERVICE.users().messages().list(userId=user_id, q=query).execute() messages = [] if 'messages' in response: messages.extend(response['messages']) while 'nextPageToken' in response: page_token = response['nextPageToken'] response = SERVICE.users().messages().list(userId=user_id, q=query, pageToken=page_token).execute() messages.extend(response['messages']) return messages except errors.HttpError as e: logger.exception(f'An error occurred:{e}') 

अभ हम query से match करने वाले messages को delete करने के लिए delete_message() function बनाएँगे. इस बात का ध्यान रखिए के ऐसा करने से messages permanently delete होंगे व trash में नहीं जाएंगे। इसलिए इसका इस्त्माल सोच समझ के करें।

def delete_messages(query, user_id='me'): messages = search(query) if messages: for message in messages: SERVICE.users().messages().delete(userId=user_id, id=message['id']).execute() logger.info(f'Message with id: {message["id"]} deleted successfully.') else: logger.info("There was no message matching the query.")

अभ इस script को रन करने के लिए हम dunders का इस्त्माल करेंगे।

if __name__ == '__main__': logger.info("Deleting messages from abc@gmail.com.") delete_messages('from:abc@gmail.com\ subject:"Go Shopping"\ older_than:1d' )

PythonAnywhere पर इसे होस्ट करने व schedule करके रन करने के लिए यह post पढ़े।

यह पूरा कोड आप https://gist.github.com/saralgyaan/bb005d371bcf0bacd9cec06e21708a50 पर देख सकते है।