Download Attachments from gmail using Gmail API

2019-01-19 00:20发布

I am using Gmail API to access my gmail data and google python api client.

According to documentation to get the message attachment they gave one sample for python

https://developers.google.com/gmail/api/v1/reference/users/messages/attachments/get

but the same code i tried then i am getting error:

AttributeError: 'Resource' object has no attribute 'user'

line where i am getting error:

message = service.user().messages().get(userId=user_id, id=msg_id).execute()

So i tried users() by replacing user()

message = service.users().messages().get(userId=user_id, id=msg_id).execute()

but i am not getting part['body']['data'] in for part in message['payload']['parts']

5条回答
三岁会撩人
2楼-- · 2019-01-19 00:51

i tested codes above and doesn't worked. And i updated some stuff for other posts. WriteFileError

    import base64
    from apiclient import errors


    def GetAttachments(service, user_id, msg_id, prefix=""):
       """Get and store attachment from Message with given id.

       Args:
       service: Authorized Gmail API service instance.
       user_id: User's email address. The special value "me"
       can be used to indicate the authenticated user.
       msg_id: ID of Message containing attachment.
       prefix: prefix which is added to the attachment filename on saving
       """
       try:
           message = service.users().messages().get(userId=user_id, id=msg_id).execute()

           for part in message['payload'].get('parts', ''):
              if part['filename']:
                  if 'data' in part['body']:
                     data=part['body']['data']
                  else:
                     att_id=part['body']['attachmentId']
                     att=service.users().messages().attachments().get(userId=user_id, messageId=msg_id,id=att_id).execute()
                     data=att['data']
            file_data = base64.urlsafe_b64decode(data.encode('UTF-8'))
            path = prefix+part['filename']

            with open(path, 'wb') as f:
                f.write(file_data)

        except errors.HttpError as error:
            print('An error occurred: %s' % error)
查看更多
家丑人穷心不美
3楼-- · 2019-01-19 00:57

You can still miss attachments by following @Ilya V. Schurov or @Cam T answers, the reason is because the email structure can be different based on the mimeType.

Inspired by this answer, here is my approach to the problem.

import base64
from apiclient import errors

def GetAttachments(service, user_id, msg_id, store_dir=""):
    """Get and store attachment from Message with given id.
        Args:
            service: Authorized Gmail API service instance.
            user_id: User's email address. The special value "me"
                can be used to indicate the authenticated user.
            msg_id: ID of Message containing attachment.
            store_dir: The directory used to store attachments.
    """
    try:
        message = service.users().messages().get(userId=user_id, id=msg_id).execute()
        parts = [message['payload']]
        while parts:
            part = parts.pop()
            if part.get('parts'):
                parts.extend(part['parts'])
            if part.get('filename'):
                if 'data' in part['body']:
                    file_data = base64.urlsafe_b64decode(part['body']['data'].encode('UTF-8'))
                    #self.stdout.write('FileData for %s, %s found! size: %s' % (message['id'], part['filename'], part['size']))
                elif 'attachmentId' in part['body']:
                    attachment = service.users().messages().attachments().get(
                        userId=user_id, messageId=message['id'], id=part['body']['attachmentId']
                    ).execute()
                    file_data = base64.urlsafe_b64decode(attachment['data'].encode('UTF-8'))
                    #self.stdout.write('FileData for %s, %s found! size: %s' % (message['id'], part['filename'], attachment['size']))
                else:
                    file_data = None
                if file_data:
                    #do some staff, e.g.
                    path = ''.join([store_dir, part['filename']])
                    with open(path, 'w') as f:
                        f.write(file_data)
    except errors.HttpError as error:
        print 'An error occurred: %s' % error
查看更多
不美不萌又怎样
4楼-- · 2019-01-19 00:58

Expanding @Eric answer, I wrote the following corrected version of GetAttachments function from the docs:

# based on Python example from 
# https://developers.google.com/gmail/api/v1/reference/users/messages/attachments/get
# which is licensed under Apache 2.0 License

import base64
from apiclient import errors

def GetAttachments(service, user_id, msg_id, prefix=""):
    """Get and store attachment from Message with given id.

    Args:
    service: Authorized Gmail API service instance.
    user_id: User's email address. The special value "me"
    can be used to indicate the authenticated user.
    msg_id: ID of Message containing attachment.
    prefix: prefix which is added to the attachment filename on saving
    """
    try:
        message = service.users().messages().get(userId=user_id, id=msg_id).execute()

        for part in message['payload']['parts']:
            if part['filename']:
                if 'data' in part['body']:
                    data=part['body']['data']
                else:
                    att_id=part['body']['attachmentId']
                    att=service.users().messages().attachments().get(userId=user_id, messageId=msg_id,id=att_id).execute()
                    data=att['data']
                file_data = base64.urlsafe_b64decode(data.encode('UTF-8'))
                path = prefix+part['filename']

                with open(path, 'w') as f:
                    f.write(file_data)
    except errors.HttpError, error:
        print 'An error occurred: %s' % error
查看更多
仙女界的扛把子
5楼-- · 2019-01-19 00:58

It's definitely "users()". The format of the response Message is largely dependent on the format parameter you use. If you use the default (FULL) then parts will either have part['body']['data'] or, when data is large, with an "attachment_id" field that you can pass to messages().attachments().get().

If you look at the attachments docs you'll see this: https://developers.google.com/gmail/api/v1/reference/users/messages/attachments

(Would be nice if this was also mentioned on the main messages docs page also.)

查看更多
男人必须洒脱
6楼-- · 2019-01-19 01:04

I made the following changes for the code above and works totally fine for every email id contains attachment documents, I hope this can help because with the API example you will get an error Key.

def GetAttachments(service, user_id, msg_id, store_dir):

"""Get and store attachment from Message with given id.

Args:
service: Authorized Gmail API service instance.
user_id: User's email address. The special value "me"
can be used to indicate the authenticated user.
msg_id: ID of Message containing attachment.
prefix: prefix which is added to the attachment filename on saving
"""
try:
    message = service.users().messages().get(userId=user_id, id=msg_id).execute()
    for part in message['payload']['parts']:
        newvar = part['body']
        if 'attachmentId' in newvar:
            att_id = newvar['attachmentId']
            att = service.users().messages().attachments().get(userId=user_id, messageId=msg_id, id=att_id).execute()
            data = att['data']
            file_data = base64.urlsafe_b64decode(data.encode('UTF-8'))
            print(part['filename'])
            path = ''.join([store_dir, part['filename']])
            f = open(path, 'wb')
            f.write(file_data)
            f.close()
except errors.HttpError, error:
    print 'An error occurred: %s' % error

Google Official API for Attachments

查看更多
登录 后发表回答