├── LICENSE ├── README.md ├── authenticate.py ├── getmessage.py ├── listmessages.py ├── send.py ├── text_speech.py └── voice_project.py /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2017, Vansh Jain, Chayan Dhaddha, Arpit Maheshwari, Anuraag Kansara 4 | Department of Computer Science and Engineering ,M.B.M Engineering College ( 2014-2018 ) 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Voice-Based-E-Mail 2 | This is a Python Application which allows its users to send, receive E-Mails through voice. 3 | 4 | 5 | Complete the steps described in the rest of this page, and in about five minutes you'll have a simple Python command-line application that makes requests to the Gmail API. 6 | 7 | Prerequisites:- 8 | 9 | 10 | 11 | 1. Python 2.6 or greater. 12 | 2. The pip package management tool. 13 | 3. Access to the internet and a web browser. 14 | 4. A Google account with Gmail enabled. 15 | 16 | Use the link given to create client_secret.json 17 | https://developers.google.com/gmail/api/quickstart/python 18 | 19 | 20 | Step 1: Turn on the Gmail API 21 | 22 | a)Use this wizard to create or select a project in the Google Developers Console and automatically turn on the API. Click Continue, then Go to credentials. 23 | b)On the Add credentials to your project page, click the Cancel button. 24 | c)At the top of the page, select the OAuth consent screen tab. Select an Email address, enter a Product name if not already set, and click the Save button. 25 | d)Select the Credentials tab, click the Create credentials button and select OAuth client ID. 26 | e)Select the application type Other, enter the name "Gmail API Quickstart", and click the Create button. 27 | f)Click OK to dismiss the resulting dialog. 28 | g)Click the file_download (Download JSON) button to the right of the client ID. 29 | h)Move this file to your working directory and rename it client_secret.json. 30 | 31 | Step 2: Install the Google Client Library 32 | 33 | Run the following command to install the library using pip: 34 | 35 | pip install --upgrade google-api-python-client 36 | 37 | Step 3: Run the following commands on terminal- 38 | 39 | 1) $ sudo apt-get install python-pip (check the version by running $ pip -V , must be version 9.0.1 or above). 40 | 2) $ sudo python -m pip install html2text 41 | 3) $ sudo pip install git 42 | 4) $ sudo apt-get install libasound-dev 43 | 5) $ git clone http://people.csail.mit.edu/hubert/git/pyaudio.git 44 | 6) $ cd pyaudio 45 | 7) $ sudo python setup.py install 46 | 8) $ sudo apt-get install libportaudio-dev 47 | 9) $ sudo apt-get install python-dev 48 | 10) $ sudo apt-get install libportaudio0 libportaudio2 libportaudiocpp0 portaudio19-dev 49 | 11) $ sudo pip install SpeechRecognition 50 | 51 | 52 | Step 4: Save the files voice_project.py, send.py, text_speech.py, listmessages.py, authenticate.py, getmessage.py, client_secret.json in a folder named voice EMail 53 | 54 | Step 5: Open Terminal and use the command 'cd voice EMail' to change the directory. 55 | 56 | Step 6: Run 'python voice_project.py' to start the application 57 | -------------------------------------------------------------------------------- /authenticate.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import httplib2 3 | import os 4 | 5 | from apiclient import discovery 6 | from oauth2client import client 7 | from oauth2client import tools 8 | from oauth2client.file import Storage 9 | 10 | try: 11 | import argparse 12 | flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args() 13 | except ImportError: 14 | flags = None 15 | 16 | # If modifying these scopes, delete your previously saved credentials 17 | # at ~/.credentials/gmail-python-quickstart.json 18 | SCOPES = 'https://mail.google.com/' 19 | CLIENT_SECRET_FILE = 'client_secret.json' 20 | APPLICATION_NAME = 'Gmail API Python Quickstart' 21 | 22 | 23 | def get_credentials(): 24 | """Gets valid user credentials from storage. 25 | 26 | If nothing has been stored, or if the stored credentials are invalid, 27 | the OAuth2 flow is completed to obtain the new credentials. 28 | 29 | Returns: 30 | Credentials, the obtained credential. 31 | """ 32 | home_dir = os.path.expanduser('~') 33 | credential_dir = os.path.join(home_dir, '.credentials') 34 | if not os.path.exists(credential_dir): 35 | os.makedirs(credential_dir) 36 | credential_path = os.path.join(credential_dir, 37 | 'gmail-python-quickstart.json') 38 | 39 | store = Storage(credential_path) 40 | credentials = store.get() 41 | if not credentials or credentials.invalid: 42 | flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES) 43 | flow.user_agent = APPLICATION_NAME 44 | if flags: 45 | credentials = tools.run_flow(flow, store, flags) 46 | else: # Needed only for compatibility with Python 2.6 47 | credentials = tools.run(flow, store) 48 | print('Storing credentials to ' + credential_path) 49 | return credentials 50 | 51 | credentials = get_credentials() 52 | http = credentials.authorize(httplib2.Http()) 53 | service = discovery.build('gmail', 'v1', http=http) 54 | 55 | results = service.users().labels().list(userId='me').execute() 56 | labels = results.get('labels', []) 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /getmessage.py: -------------------------------------------------------------------------------- 1 | """Get Message with given ID. 2 | """ 3 | import base64 4 | import email 5 | from apiclient import errors 6 | 7 | 8 | #from apiclient.discovery import build 9 | #service = build('gmail', 'v1',developerKey='AIzaSyBYz9sTDX9JIDhEk3IWdjzFI9FiZB8YqYg') 10 | 11 | 12 | 13 | def GetMessage(service, user_id, msg_id): 14 | """Get a Message with given ID. 15 | 16 | Args: 17 | service: Authorized Gmail API service instance. 18 | user_id: User's email address. The special value "me" 19 | can be used to indicate the authenticated user. 20 | msg_id: The ID of the Message required. 21 | 22 | Returns: 23 | A Message. 24 | """ 25 | try: 26 | message = service.users().messages().get(userId=user_id, id=msg_id).execute() 27 | 28 | #print 'Message snippet: %s' % message['snippet'] 29 | 30 | return message 31 | except errors.HttpError, error: 32 | print 'An error occurred: %s' % error 33 | 34 | 35 | def GetMimeMessage(service, user_id, msg_id): 36 | """Get a Message and use it to create a MIME Message. 37 | 38 | Args: 39 | service: Authorized Gmail API service instance. 40 | user_id: User's email address. The special value "me" 41 | can be used to indicate the authenticated user. 42 | msg_id: The ID of the Message required. 43 | 44 | Returns: 45 | A MIME Message, consisting of data from Message. 46 | """ 47 | try: 48 | message = service.users().messages().get(userId=user_id, id=msg_id, 49 | format='raw').execute() 50 | 51 | #print 'Message snippet: %s' % message['snippet'] 52 | 53 | msg_str = base64.urlsafe_b64decode(message['raw'].encode('ASCII')) 54 | 55 | mime_msg = email.message_from_string(msg_str) 56 | 57 | return mime_msg 58 | except errors.HttpError, error: 59 | print 'An error occurred: %s' % error 60 | 61 | 62 | #resource=GetMessage(service,"me","15b184f2ba936882") 63 | #print resource['snippet'] 64 | -------------------------------------------------------------------------------- /listmessages.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Requires PyAudio and PySpeech. 3 | 4 | 5 | 6 | """Get a list of Messages from the user's mailbox. 7 | """ 8 | from text_speech import * 9 | from apiclient import errors 10 | from authenticate import * 11 | from getmessage import * 12 | import html2text 13 | import pyttsx 14 | 15 | def ListMessagesMatchingQuery(service, user_id, query=''): 16 | """List all Messages of the user's mailbox matching the query. 17 | 18 | Args: 19 | service: Authorized Gmail API service instance. 20 | user_id: User's email address. The special value "me" 21 | can be used to indicate the authenticated user. 22 | query: String used to filter messages returned. 23 | Eg.- 'from:user@some_domain.com' for Messages from a particular sender. 24 | 25 | Returns: 26 | List of Messages that match the criteria of the query. Note that the 27 | returned list contains Message IDs, you must use get with the 28 | appropriate ID to get the details of a Message. 29 | """ 30 | try: 31 | response = service.users().messages().list(userId=user_id, 32 | q=query).execute() 33 | messages = [] 34 | if 'messages' in response: 35 | messages.extend(response['messages']) 36 | 37 | while 'nextPageToken' in response: 38 | page_token = response['nextPageToken'] 39 | response = service.users().messages().list(userId=user_id, q=query, 40 | pageToken=page_token).execute() 41 | messages.extend(response['messages']) 42 | 43 | return messages 44 | except errors.HttpError, error: 45 | print 'An error occurred: %s' % error 46 | 47 | 48 | def ListMessagesWithLabels(service, user_id, label_ids=[]): 49 | """List all Messages of the user's mailbox with label_ids applied. 50 | 51 | Args: 52 | service: Authorized Gmail API service instance. 53 | user_id: User's email address. The special value "me" 54 | can be used to indicate the authenticated user. 55 | label_ids: Only return Messages with these labelIds applied. 56 | 57 | Returns: 58 | List of Messages that have all required Labels applied. Note that the 59 | returned list contains Message IDs, you must use get with the 60 | appropriate id to get the details of a Message. 61 | """ 62 | try: 63 | response = service.users().messages().list(userId=user_id, 64 | labelIds=label_ids).execute() 65 | messages = [] 66 | if 'messages' in response: 67 | messages.extend(response['messages']) 68 | 69 | while 'nextPageToken' in response: 70 | page_token = response['nextPageToken'] 71 | response = service.users().messages().list(userId=user_id, 72 | labelIds=label_ids, 73 | pageToken=page_token).execute() 74 | messages.extend(response['messages']) 75 | 76 | return messages 77 | except errors.HttpError, error: 78 | print 'An error occurred: %s' % error 79 | 80 | def speaking_message(msg_id): 81 | message=GetMimeMessage(service,"me",msg_id) 82 | a=message.get_payload() 83 | b=a[0].get_payload() 84 | print type(b) 85 | text_to_speech('The subject is : ') 86 | text_to_speech(message['subject']) 87 | print b 88 | text_to_speech('The message is : ') 89 | text_to_speech(b) 90 | 91 | 92 | def searched_message(query): 93 | number=0 94 | searched_message_list=ListMessagesMatchingQuery(service, 'me', 'from:'+query) 95 | searched_messageIDs=list() 96 | while number < len(searched_message_list) : 97 | searched_messageIDs.append(searched_message_list[number]['id']) 98 | number=number+1 99 | subjects=list() 100 | for current_mailID in searched_messageIDs : 101 | searched_message=GetMimeMessage(service,"me",current_mailID) 102 | subjects.append(searched_message['subject']) 103 | 104 | number=0 105 | for subject in subjects: 106 | text_to_speech(str(number)+' '+subject) 107 | number=number+1 108 | if len(subjects) == 0 : 109 | text_to_speech('No E-Mails from this sender!') 110 | return 111 | response=speech_to_text() 112 | #message=GetMimeMessage(service,'me',searched_messageIDs[int(response)]) 113 | speaking_message(searched_messageIDs[int(response)]) 114 | 115 | 116 | 117 | def get_message_list(): 118 | 119 | maillist=ListMessagesMatchingQuery(service, 'me') 120 | 121 | number=0 122 | 123 | messageIDs=list() 124 | while number < 100 : 125 | messageIDs.append(maillist[number]['id']) 126 | number=number + 1 127 | 128 | 129 | number=0 130 | senders=list() 131 | while number < 100 : 132 | current_message=GetMimeMessage(service,"me",messageIDs[number]) 133 | senders.append(current_message['from']) 134 | number=number+1 135 | 136 | number=0 137 | while True : 138 | text_to_speech('Say the serial number of E-Mail to read !') 139 | #number=0 140 | #while number < 10 : 141 | while True : 142 | text_to_speech(str(number)+' '+senders[number]) 143 | #number=number+1 144 | if number%10 == 9 : 145 | #number=number+1 146 | break 147 | number=number+1 148 | 149 | text_to_speech('say next to hear next ten messages') 150 | text_to_speech('say skip to return to the main menu') 151 | 152 | response=speech_to_text() 153 | if response.lower() == 'skip' : 154 | return 155 | #response=int(response) 156 | if response.lower() == 'next' : 157 | number=number+1 158 | continue 159 | response=int(response) 160 | 161 | 162 | speaking_message(messageIDs[response]) 163 | 164 | text_to_speech('say continue to hear the E-Mails again !') 165 | response=speech_to_text() 166 | if response.lower() == 'continue' : 167 | number=number-10 168 | continue 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | -------------------------------------------------------------------------------- /send.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Requires PyAudio and PySpeech. 3 | 4 | 5 | 6 | import base64 7 | from email.mime.audio import MIMEAudio 8 | from email.mime.base import MIMEBase 9 | from email.mime.image import MIMEImage 10 | from email.mime.multipart import MIMEMultipart 11 | from email.mime.text import MIMEText 12 | import mimetypes 13 | import os 14 | 15 | 16 | from apiclient import errors 17 | 18 | from authenticate import * 19 | from text_speech import * 20 | 21 | 22 | 23 | def SendMessage(service, user_id, message): 24 | """Send an email message. 25 | 26 | Args: 27 | service: Authorized Gmail API service instance. 28 | user_id: User's email address. The special value "me" 29 | can be used to indicate the authenticated user. 30 | message: Message to be sent. 31 | 32 | Returns: 33 | Sent Message. 34 | """ 35 | try: 36 | message = (service.users().messages().send(userId=user_id, body=message) 37 | .execute()) 38 | print 'Message Id: %s' % message['id'] 39 | return message 40 | except errors.HttpError, error: 41 | print 'An error occurred: %s' % error 42 | 43 | 44 | def CreateMessage(sender, to, subject, message_text): 45 | """Create a message for an email. 46 | 47 | Args: 48 | sender: Email address of the sender. 49 | to: Email address of the receiver. 50 | subject: The subject of the email message. 51 | message_text: The text of the email message. 52 | 53 | Returns: 54 | An object containing a base64url encoded email object. 55 | """ 56 | message = MIMEText(message_text) 57 | message['to'] = to 58 | message['from'] = sender 59 | message['subject'] = subject 60 | return {'raw': base64.urlsafe_b64encode(message.as_string())} 61 | 62 | 63 | def CreateMessageWithAttachment(sender, to, subject, message_text, file_dir, 64 | filename): 65 | """Create a message for an email. 66 | 67 | Args: 68 | sender: Email address of the sender. 69 | to: Email address of the receiver. 70 | subject: The subject of the email message. 71 | message_text: The text of the email message. 72 | file_dir: The directory containing the file to be attached. 73 | filename: The name of the file to be attached. 74 | 75 | Returns: 76 | An object containing a base64url encoded email object. 77 | """ 78 | message = MIMEMultipart() 79 | message['to'] = to 80 | message['from'] = sender 81 | message['subject'] = subject 82 | 83 | msg = MIMEText(message_text) 84 | message.attach(msg) 85 | 86 | path = os.path.join(file_dir, filename) 87 | content_type, encoding = mimetypes.guess_type(path) 88 | 89 | if content_type is None or encoding is not None: 90 | content_type = 'application/octet-stream' 91 | main_type, sub_type = content_type.split('/', 1) 92 | if main_type == 'text': 93 | fp = open(path, 'rb') 94 | msg = MIMEText(fp.read(), _subtype=sub_type) 95 | fp.close() 96 | elif main_type == 'image': 97 | fp = open(path, 'rb') 98 | msg = MIMEImage(fp.read(), _subtype=sub_type) 99 | fp.close() 100 | elif main_type == 'audio': 101 | fp = open(path, 'rb') 102 | msg = MIMEAudio(fp.read(), _subtype=sub_type) 103 | fp.close() 104 | else: 105 | fp = open(path, 'rb') 106 | msg = MIMEBase(main_type, sub_type) 107 | msg.set_payload(fp.read()) 108 | fp.close() 109 | 110 | msg.add_header('Content-Disposition', 'attachment', filename=filename) 111 | message.attach(msg) 112 | 113 | return {'raw': base64.urlsafe_b64encode(message.as_string())} 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | def send_message(): 122 | text_to_speech('say the E-Mail address of the receiver') 123 | email=speech_to_text() 124 | words=email.split() 125 | modified_mail=str() 126 | for word in words: 127 | if word == 'underscore': 128 | modified_mail=modified_mail+'_' 129 | elif word == 'dot': 130 | modified_mail=modified_mail+'.' 131 | else: 132 | modified_mail=modified_mail+word 133 | 134 | modified_mail=modified_mail.lower() 135 | print modified_mail 136 | to=modified_mail 137 | text_to_speech('say the subject of the message you want to send !') 138 | subject=speech_to_text() 139 | text_to_speech('say the message you want to send !') 140 | message_text=speech_to_text() 141 | created_message=CreateMessage('me', to, subject, message_text) 142 | sent_message=SendMessage(service, 'me', created_message) 143 | print sent_message 144 | 145 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /text_speech.py: -------------------------------------------------------------------------------- 1 | import speech_recognition as sr 2 | import pyttsx 3 | 4 | 5 | 6 | 7 | def text_to_speech(sentence): 8 | engine=pyttsx.init() 9 | engine.setProperty('rate',150) 10 | engine.say(sentence) 11 | engine.runAndWait() 12 | del engine 13 | 14 | def speech_to_text(): 15 | r = sr.Recognizer() 16 | with sr.Microphone() as source: 17 | print("Say something!") 18 | audio = r.listen(source) 19 | 20 | # Speech recognition using Google Speech Recognition 21 | try: 22 | # for testing purposes, we're just using the default API key 23 | # to use another API key, use `r.recognize_google(audio, key="GOOGLE_SPEECH_RECOGNITION_API_KEY")` 24 | # instead of `r.recognize_google(audio)` 25 | print("You said: " + r.recognize_google(audio)) 26 | except sr.UnknownValueError: 27 | print("Google Speech Recognition could not understand audio") 28 | except sr.RequestError as e: 29 | print("Could not request results from Google Speech Recognition service; {0}".format(e)) 30 | return str(r.recognize_google(audio)) 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /voice_project.py: -------------------------------------------------------------------------------- 1 | from text_speech import * 2 | from send import * 3 | from listmessages import * 4 | 5 | 6 | 7 | while True : 8 | 9 | 10 | text_to_speech('say 1 to send a message !') 11 | text_to_speech('say 2 to receive messages !') 12 | text_to_speech('say 3 to close the application !') 13 | 14 | first_response=speech_to_text() 15 | 16 | if first_response == '1' : 17 | send_message() 18 | 19 | elif first_response == '2' or first_response == 'tu' or first_response == 'two' or first_response == 'Tu' or first_response == 'to' or first_response == 'To' : 20 | text_to_speech('say 1 for top ten messages') 21 | text_to_speech('say 2 to search for a sender') 22 | receive_response=speech_to_text() 23 | if receive_response == '1' : 24 | get_message_list() 25 | if receive_response == '2' or receive_response == 'Tu' or receive_response == 'tu' or receive_response == 'two' or receive_response == 'To' or receive_response == 'to': 26 | text_to_speech('Say the E-Mail of the sender!') 27 | email=speech_to_text() 28 | words=email.split() 29 | modified_mail=str() 30 | for word in words: 31 | if word == 'underscore': 32 | modified_mail=modified_mail+'_' 33 | elif word == 'dot': 34 | modified_mail=modified_mail+'.' 35 | else: 36 | modified_mail=modified_mail+word 37 | 38 | modified_mail=modified_mail.lower() 39 | #query=speech_to_text() 40 | searched_message(modified_mail) 41 | elif first_response == '3': 42 | exit() 43 | else: 44 | text_to_speech('Sorry you were not clear with your vocals !') 45 | continue 46 | 47 | 48 | 49 | 50 | 51 | 52 | --------------------------------------------------------------------------------