使用Gmail API从gmail下载附件

时间:2014-09-14 11:13:08

标签: python email gmail gmail-api

我正在使用Gmail API访问我的Gmail数据和google python api客户端。

根据获取消息附件的文档,他们为python提供了一个示例

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

但我尝试的代码相同,我收到错误:

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

我遇到错误的地方:

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

所以我通过替换users()

来尝试user()
message = service.users().messages().get(userId=user_id, id=msg_id).execute()

但我未在part['body']['data']

中获得for part in message['payload']['parts']

7 个答案:

答案 0 :(得分:33)

扩展@Eric答案,我从文档中写了以下更正版本的GetAttachments函数:

# 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

答案 1 :(得分:6)

您仍然可以通过 @Ilya V. Schurov @Cam T 答案错过附件,原因是因为电子邮件结构可能因{{{ 1}}。

this answer的启发,这是解决问题的方法。

mimeType

答案 2 :(得分:5)

我测试了上面的代码并且没有工作。我为其他帖子更新了一些内容。 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 :(得分:3)

绝对是“用户()”。响应Message的格式在很大程度上取决于您使用的格式参数。如果使用默认值(FULL),那么部件将具有part ['body'] ['data'],或者,当数据很大时,可以使用“attachment_id”字段传递给messages()。attachments()。得到()。

如果查看附件文档,您会看到: https://developers.google.com/gmail/api/v1/reference/users/messages/attachments

(如果在主消息文档页面上也提到过这样会很好。)

答案 4 :(得分:2)

感谢 @Ilya V. Schurov @Todor 。如果存在包含相同搜索字符串的带附件和不带附件的邮件,您仍然可能会错过邮件。这是我获取两种邮件的邮件正文的方法,即带附件和不带附件的邮件。

def get_attachments(service, msg_id):
try:
    message = service.users().messages().get(userId='me', 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='me', messageId=msg_id,id=att_id).execute()
                data = att['data']
            file_data = base64.urlsafe_b64decode(data.encode('UTF-8'))
            path = part['filename']

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

except errors.HttpError as error:
    print ('An error occurred: %s') % error

def get_message(service,msg_id):
try:
    message = service.users().messages().get(userId='me', id=msg_id).execute()
    if message['payload']['mimeType'] == 'multipart/mixed':
        for part in message['payload']['parts']:
            for sub_part in part['parts']:
                if sub_part['mimeType'] == 'text/plain':
                    data = sub_part['body']['data']
                    break
            if data:
                break           
    else:
        for part in message['payload']['parts']:
            if part['mimeType'] == 'text/plain':
                data = part['body']['data']
                break
    
    content = base64.b64decode(data).decode('utf-8')
    print(content)

    return content    

except errors.HttpError as error:
    print("An error occured : %s") %error

答案 5 :(得分:1)

from __future__ import print_function
import base64
import os.path
import oauth2client
from googleapiclient.discovery import build
from oauth2client import file,tools
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']
store_dir=os.getcwd()

def attachment_download():

store = oauth2client.file.Storage('credentials_gmail.json')
creds = store.get()
if not creds or creds.invalid:
    flow = oauth2client.client.flow_from_clientsecrets('client_secrets.json', SCOPES)
    creds = oauth2client.tools.run_flow(flow, store)


try:
    service = build('gmail', 'v1', credentials=creds)
    results = service.users().messages().list(userId='me', labelIds=['XXXX']).execute() # XXXX is label id use INBOX to download from inbox
    messages = results.get('messages', [])
    for message in messages:
        msg = service.users().messages().get(userId='me', id=message['id']).execute()
        for part in msg['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='me', messageId=message['id'],id=att_id).execute()
                    data = att['data']
                file_data = base64.urlsafe_b64decode(data.encode('UTF-8'))

                filename = part['filename']
                print(filename)
                path = os.path.join(store_dir + '\\' 'Downloaded files' + '\\' + filename)

                with open(path, 'wb') as f:
                    f.write(file_data)
                    f.close()
except Exception as error:
    print(error)

请参阅: 获取标签ID https://developers.google.com/gmail/api/v1/reference/users/labels/list

答案 6 :(得分:0)

我对上面的代码进行了以下更改,并且对于每个包含附件文档的电子邮件ID都完全正常,我希望这可以提供帮助,因为使用API​​示例您将获得错误密钥。

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