0

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.

srk
  • 180
  • 2
  • 17
  • Does this answer your question? [Download attachments from Gmail using Gmail API](https://stackoverflow.com/questions/25832631/download-attachments-from-gmail-using-gmail-api) – Emel Apr 11 '22 at 10:58

1 Answers1

0

There are two main issues with this code.

  1. 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']

  2. 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!

Pranav
  • 1
  • 3