Search code examples
pythonpython-3.xgmailgmail-api

Gmail API reads all messages instead of the UNREAD ones


I am trying to fetch all the unread messages from a gmail account using below code

msgs = service.users().messages().list(userId='me',q='in:inbox is:unread').execute()

flag=1
while flag==1:
    for i in range(0,len(msgs['messages'])):
        message = service.users().messages().get(userId='me', id=msgs['messages'][i]['id']).execute()
        print(message['snippet'])
    if 'nextPageToken' in msgs.keys():
            msgs = service.users().messages().list(userId='me',pageToken= msgs['nextPageToken']).execute()
    else:
        flag=0

The logic for above code

The API returns 100 message IDs and an ID for next page called nextPageToken. We use this token to fetch next 100 message IDs and so forth so on. If there is no next page, it won't have the token and hence my last 4 line of code checks for it's existence. If it doesn't exists, it sets the flag to 0 and the while loop completes.

Problem

The above code fetches ALL the messages (READ and UNREAD)

Other methods tried

msgs = service.users().messages().list(userId='me',labelIds=['UNREAD']).execute()

and

msgs = service.users().messages().list(userId='me',q='in:inbox is:unread').execute()

Possible Root Cause

I've noticed that if the unread messages are <100 then it fetches them correctly. However, if the unread messages are >100 then it pulls all the messages (READ+UNREAD)

I have looked into this stackoverflow answer, but it didn't help either.


Solution

  • The thing that bothers me about your code is that you only filter your messages in the first API call.

    So without filtering the messages make sense that you are getting all the messages (READ or UNREAD). Except for the first call (the only you are filtering).

    msgs = service.users().messages().list(userId='me',q='in:inbox is:unread').execute()
    
    flag=1
    while flag==1:
        for i in range(0,len(msgs['messages'])):
            message = service.users().messages().get(userId='me', id=msgs['messages'][i]['id']).execute()
            print(message['snippet'])
        if 'nextPageToken' in msgs.keys():
                msgs = service.users().messages().list(userId='me',
                                                       q='in:inbox is:unread', # Add this to subsequent calls
                                                       pageToken= msgs['nextPageToken']
                                                      ).execute()
        else:
            flag=0
    

    Take a look at the examples of pagination in the official documentation. There you can see how the query is passed for every call (not just the first one).

     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, error:
        print 'An error occurred: %s' % error