I am trying to download the attachment from gmail using the python and I am not able to fetch the attachment id from my mail. Please find my code below
import os.path
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
def get_gmail_service():
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']
creds = None
# The file token.json stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.json', 'w') as token:
token.write(creds.to_json())
try:
# Call the Gmail API
service = build('gmail', 'v1', credentials=creds)
return service
except HttpError as error:
# TODO(developer) - Handle errors from gmail API.
print(f'An error occurred: {error}')
def get_email_list():
service = get_gmail_service()
results = service.users().messages().list(userId='me',q='from:abc#gmail.com is:read').execute()
# print(results.get('messages',[])[0].get('id',[]))
return results.get('messages', [])[0].get('id', [])
# return results.get('messages',[])
def get_email_content(message_id):
service = get_gmail_service()
attach = service.users().messages().get(userId='me',id =message_id).execute()
attach_id = attach.get('payloads',[]).get('parts',[]).get('body',[])
data = service.users().messages().get(userId='me',id = message_id).execute()
return attach_id
if __name__ == '__main__':
# get_email_list()
print(get_email_content(get_email_list()))
Please correct my code so that I can download the attachment using the gmail api.
There are two main issues with this code.
results.get() method either returns a Message or MessagePart Object. So you only need to use the get() method once to get the complete object and then you can target the specific part of the object you want.
For Example. results.get('messages', [])[0]['id']
A payload for an email can be multipart (which means that "parts" will be an array of MessagePart objects). So we need to iterate over to get a "message part" that has a file. In this case, we can check if the MessagePart object has a filename.
parts = attach.get('payload',[])['parts']
for i in parts:
if( i['filename'] ):
return i['body']['attachmentId']
So After taking care of these two issues, this is the new code:
import os.path
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
def get_gmail_service():
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']
creds = None
# The file token.json stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.json', 'w') as token:
token.write(creds.to_json())
try:
# Call the Gmail API
service = build('gmail', 'v1', credentials=creds)
return service
except HttpError as error:
# TODO(developer) - Handle errors from gmail API.
print(f'An error occurred: {error}')
def get_email_list():
service = get_gmail_service()
results = service.users().messages().list(userId='me',q='from:abc#gmail.com is:read').execute()
# print(results.get('messages',[])[0]['id'] )
return results.get('messages', [])[0]['id']
# return results.get('messages',[])
def get_email_content(message_id):
print(message_id)
service = get_gmail_service()
data = service.users().messages().get(userId='me',id = message_id).execute()
attach = service.users().messages().get(userId='me',id =message_id).execute()
parts = attach.get('payload',[])['parts']
for i in parts:
if( i['filename'] ):
return i['body']['attachmentId']
if __name__ == '__main__':
# get_email_list()
print(get_email_content(get_email_list()))
I hope this answers your question!
Related
I am trying to create a script that uploads pictures to my google drive folder. This script works well on my computer, but the problem is that this script is supposed to run itself every other week automatically, but right now, whenever I run the script google prompts me to log in, instead of remembering the session from the first time I logged in.
my script to push the pictures to google drive looks like this:
def upload_files():
upload_files_list = []
for element in os.listdir("billeder"):
upload_files_list.append("/root/billeder/" + element)
for upload_file in upload_files_list:
gfile = drive.CreateFile({'parents': [{'id': 'folder_id_here'}]})
# Read file and set it as the content of this instance.
gfile.SetContentFile(upload_file)
gfile.Upload() # Upload the file.
my script to authenticate looks like this:
from __future__ import print_function
import os.path
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly']
def main():
"""Shows basic usage of the Drive v3 API.
Prints the names and ids of the first 10 files the user has access to.
"""
creds = None
# The file token.json stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the firstp
# time.
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'client_secrets.json', SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.json', 'w') as token:
token.write(creds.to_json())
try:
service = build('drive', 'v3', credentials=creds)
# Call the Drive v3 API
results = service.files().list(
pageSize=10, fields="nextPageToken, files(id, name)").execute()
items = results.get('files', [])
if not items:
print('No files found.')
return
print('Files:')
for item in items:
print(u'{0} ({1})'.format(item['name'], item['id']))
except HttpError as error:
# TODO(developer) - Handle errors from drive API.
print(f'An error occurred: {error}')
if __name__ == '__main__':
main()
As far as I can see you are not creating a drive service object. In your upload files method. Which means its not authenticated.
# To install the Google client library for Python, run the following command:
# pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
from __future__ import print_function
import os.path
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from google.auth.exceptions import RefreshError
from googleapiclient.http import MediaFileUpload
# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/drive']
CREDENTIALS = 'C:\YouTube\dev\credentials.json'
TOKENJSON = 'tokenDriveUpload.json'
def main():
"""Shows basic usage of the Drive v3 API.
Prints the names and ids of the first 10 files the user has access to.
"""
creds = None
# The file token.json stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists(TOKENJSON):
creds = Credentials.from_authorized_user_file(TOKENJSON, SCOPES)
try:
creds.refresh(Request())
except RefreshError as error:
# If the refresh token has expired then we request authorization again.
os.remove(TOKENJSON)
creds.refresh_token = None
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
CREDENTIALS, SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open(TOKENJSON, 'w') as token:
token.write(creds.to_json())
upload_file(creds, 'C:\YouTube\dev\logo.png')
def upload_file(creds, filepath):
try:
# create drive api client
service = build('drive', 'v3', credentials=creds)
basename = os.path.basename(filepath)
print(basename)
file_metadata = {'name':basename}
media = MediaFileUpload(filepath,
mimetype='text/plain')
file = service.files().create(body=file_metadata, media_body=media,
fields='id').execute()
print(F'File ID: {file.get("id")}')
except HttpError as error:
# TODO(developer) - Handle errors from drive API.
print(F'An error occurred: {error}')
if __name__ == '__main__':
main()
I am writing a program about the YouTube API
flow = google_auth_oauthlib.flow.InstalledAppFlow.from_client_secrets_file(client_secrets_file, scopes)
credentials = flow.run_console()
youtube_analytics = googleapiclient.discovery.build("youtubeAnalytics", "v2", credentials=credentials)
Finally it will return a 'Resource' object, can I store this object?
So that I can get this object to use in the future just by referring to the file
You can store the json creds returned by the authorization flow. The library will then be able to load those stored creds the next time it needs access.
The following example is adapted from the official Google drive quickstart
from __future__ import print_function
import os.path
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/yt-analytics.readonly']
def main():
"""Shows basic usage of the YouTube Analytics v2 API.
"""
creds = None
# The file token.json stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.json', 'w') as token:
token.write(creds.to_json())
try:
service = build('youtubeAnalytics', 'v2', credentials=creds)
# Call the YouTube analytics
...
except HttpError as error:
# TODO(developer) - Handle errors from API.
print(f'An error occurred: {error}')
if __name__ == '__main__':
main()
If you have any issues with this please let me know.
save it as a pkl file then call the file and update it
import pickle
dump into pkl file for first time and updates
with open('mypickle.pickle', 'wb') as f:
pickle.dump(resource, f)
resource = whatever you want to store
open file at later time
with open('mypickle.pickle', 'rb') as f:
loaded_obj = pickle.load(f)
I keep getting this error and have looked everywhere and I cannot fix it. Can someone please hold my hand. I have downloaded the json filed and named it so it matches. I have watched every youtube video to make sure I created credentials correctly and also added my email as a test user. Not sure what to do at this point. I have json file and the token in my IDE, also I was able to log in and choose my username and got the flow message so everything seems to be working. Up until I copy and paste the create_email_draft from gmail api documents. Basically I just want to send some automated emails. Here is my code...let me know if you need anything else.
ERROR:
Traceback (most recent call last):
File "C:\Users\carlo\PycharmProjects\pythonProject3\quickstart.py", line 61, in
gmail_create_draft()
File "C:\Users\carlo\PycharmProjects\pythonProject3\quickstart.py", line 25, in gmail_create_draft
creds, _ = google.auth.default()
File "C:\Users\carlo\PycharmProjects\pythonProject3\venv\lib\site-packages\google\auth_default.py", line 616, in default
raise exceptions.DefaultCredentialsError(_HELP_MESSAGE)
google.auth.exceptions.DefaultCredentialsError: Could not automatically determine credentials. Please set GOOGLE_APPLICATION_CREDENTIALS or explicitly create credentials and re-run the application. For more information, please see https://cloud.google.com/docs/authentication/getting-started
Process finished with exit code 1
from __future__ import print_function
import os.path
import base64
from email.message import EmailMessage
import google.auth
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']
def gmail_create_draft():
"""Create and insert a draft email.
Print the returned draft's message and id.
Returns: Draft object, including draft id and message meta data.
Load pre-authorized user credentials from the environment.
TODO(developer) - See https://developers.google.com/identity
for guides on implementing OAuth2 for the application.
"""
creds, _ = google.auth.default()
try:
# create gmail api client
service = build('gmail', 'v1', credentials=creds)
message = EmailMessage()
message.set_content('This is automated draft mail')
message['To'] = 'carlosmedina239#gmail.com'
message['From'] = 'selenytesting123#gmail.com'
message['Subject'] = 'Automated draft'
# encoded message
encoded_message = base64.urlsafe_b64encode(message.as_bytes()).decode()
create_message = {
'message': {
'raw': encoded_message
}
}
# pylint: disable=E1101
draft = service.users().drafts().create(userId="me",
body=create_message).execute()
print(F'Draft id: {draft["id"]}\nDraft message: {draft["message"]}')
except HttpError as error:
print(F'An error occurred: {error}')
draft = None
return draft
if __name__ == '__main__':
gmail_create_draft()
def main():
"""Shows basic usage of the Gmail API.
Lists the user's Gmail labels.
"""
creds = None
# The file token.json stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.json', 'w') as token:
token.write(creds.to_json())
# You don't have to care about anything on top of this comment
try:
# Call the Gmail API
service = build('gmail', 'v1', credentials=creds)
results = service.users().labels().list(userId='me').execute()
labels = results.get('labels', [])
if not labels:
print('No labels found.')
return
print('Labels:')
for label in labels:
print(label['name'])
except HttpError as error:
# TODO(developer) - Handle errors from gmail API.
print(f'An error occurred: {error}')
if __name__ == '__main__':
main()
I think you have tried to copy the code from the quickstart without trying understanding what its doing.
Your gmail_create_draft method is not building the credentials properly. So its looking for it in the default env var which you dont have set which is the cause of your error message.
I have tested this code and it works.
# To install the Google client library for Python, run the following command:
# pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
from __future__ import print_function
import os.path
import base64
from email.message import EmailMessage
import google.auth
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
# If modifying these scopes, delete the file token.json.
SCOPES = ['https://mail.google.com/']
def main():
"""Shows basic usage of the Gmail API.
Lists the user's Gmail labels.
"""
creds = None
# The file token.json stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists('tokenSend.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('tokenSend.json', 'w') as token:
token.write(creds.to_json())
# You don't have to care about anything on top of this comment
try:
# Call the Gmail API
service = build('gmail', 'v1', credentials=creds)
message = EmailMessage()
message.set_content('This is automated draft mail')
message['To'] = 'xxxx#gmail.com'
message['From'] = 'xxxx#gmail.com'
message['Subject'] = 'Automated draft'
# encoded message
encoded_message = base64.urlsafe_b64encode(message.as_bytes()).decode()
create_message = {
'message': {
'raw': encoded_message
}
}
# pylint: disable=E1101
draft = service.users().drafts().create(userId="me",
body=create_message).execute()
print(F'Draft id: {draft["id"]}\nDraft message: {draft["message"]}')
except HttpError as error:
# TODO(developer) - Handle errors from gmail API.
print(f'An error occurred: {error}')
if __name__ == '__main__':
main()
Results in
Draft id: r4575751609218968324
Draft message: {'id': '182fcd72a7a06a96', 'threadId': '182fcd72a7a06a96', 'labelIds': ['DRAFT']}
I want to download them with as few API calls as possible. https://github.com/googleapis/google-api-python-client/tree/master/samples doesn't have Gmail.
Start by following Python quickstart it will give you an idea of how to get the Auth part working
from __future__ import print_function
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
# If modifying these scopes, delete the file token.pickle.
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']
def main():
"""Shows basic usage of the Gmail API.
Lists the user's Gmail labels.
"""
creds = None
# The file token.pickle stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists('token.pickle'):
with open('token.pickle', 'rb') as token:
creds = pickle.load(token)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.pickle', 'wb') as token:
pickle.dump(creds, token)
service = build('gmail', 'v1', credentials=creds)
# Call the Gmail API
results = service.users().labels().list(userId='me').execute()
labels = results.get('labels', [])
if not labels:
print('No labels found.')
else:
print('Labels:')
for label in labels:
print(label['name'])
if __name__ == '__main__':
main()
Once you understand what that is doing you should be able to consult user message list to get an idea of how to alter it for listing a messages.
I am using the Google Admin SDK - Directory API, I have a successful connection to the API but no OUs are being stored in my array.
Result:
Getting the OUs in the domain
No OUs found in the domain.
I tried modifying the code to list the first 10 users instead and it works.
from __future__ import print_function
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
# If modifying these scopes, delete the file token.pickle.
SCOPES = ['https://www.googleapis.com/auth/admin.directory.orgunit']
def main():
creds = None
# The file token.pickle stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists('token.pickle'):
with open('token.pickle', 'rb') as token:
creds = pickle.load(token)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file('credentials.json', SCOPES)
creds = flow.run_local_server()
# Save the credentials for the next run
with open('token.pickle', 'wb') as token:
pickle.dump(creds, token)
service = build('admin', 'directory_v1', credentials=creds)
# Call the Admin SDK Directory API
print('Getting the OUs in the domain')
results = service.orgunits().list(customerId='my_customer').execute()
ou_list = results.get('orgunits', [])
if not ou_list:
print('No OUs found in the domain.')
else:
print('OU List:')
# for ou in ou_list:
# print(u'{0} ({1})'.format(ou_list['name'], ou_list['orgUnitPath']))
if __name__ == '__main__':
main()
No error messages are displayed but, OUs are not being stored.
The key is not orgunits, it is orgazinationalUnits:
ou_list = results.get('orgunits', [])