如何使用Python通过Google API从Gmail下载附件

问题描述 投票:0回答:1

我想使用 Python 下载过去 12 小时内通过 Google API 平台从特定电子邮件 ID 收到的所有附件。我正在使用以下代码。

import base64
from datetime import datetime, timedelta
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
import json
from google.oauth2.service_account import Credentials


# Load service account credentials from JSON file
creds = Credentials.from_service_account_file(r'token.json',
                                            scopes['https://www.googleapis.com/auth/gmail.readonly'])

# Create Gmail API service
service = build('gmail', 'v1', credentials=creds)

# Calculate the date 12 hours ago from now
now = datetime.utcnow()
time_threshold = now - timedelta(hours=12)
formatted_time_threshold = time_threshold.strftime('%Y-%m-%dT%H:%M:%S.%fZ')

# Define the email address of the sender you want to filter by
sender_email = '[email protected]'

# Define the query to retrieve messages from the sender received in the last 12 hours
query = f'from:{sender_email} after:{formatted_time_threshold}'
print(query)

try:
    # Get messages that match the query
    response = service.users().messages().list(q=query, userId='me').execute()
    messages = response.get('messages', [])
    # Iterate through messages and download attachments
    for msg in messages:
        message = service.users().messages().get(userId='me', id=msg['id']).execute()
        payload = message['payload']

        # Check if message has any attachments
        if 'parts' in payload:
            for part in payload['parts']:
                # Check if part is an attachment
                if part['filename']:
                    filename = part['filename']
                    data = part['body']['data']
                    file_data = base64.urlsafe_b64decode(data.encode('UTF-8'))

                    # Save attachment to local disk
                    with open(filename, 'wb') as f:
                        f.write(file_data)
                    print(f'Saved attachment: {filename}')
except HttpError as error:
    print(f'An error occurred: {error}')

当我运行此程序时,我收到 HttpError,当我检查错误 URL 时,我收到以下消息。

  "error": {
    "code": 401,
    "message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
    "errors": [
      {
        "message": "Login Required.",
        "domain": "global",
        "reason": "required",
        "location": "Authorization",
        "locationType": "header"
      }
    ],
    "status": "UNAUTHENTICATED"}

我不确定这里的问题是什么。我是否没有正确使用 API 进行身份验证,或者我是否需要为此过程配置其他内容。

我用来建立连接的 token.json 文件具有以下结构

{
  "type": "service_account",
  "project_id": "mailer-attachments-download",
  "private_key_id": "",
  "private_key": "",
  "client_email": "attachment-downloader@mailer-attachments-download.iam.gserviceaccount.com",
  "client_id": "",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/attachment-downloader%40mailer-attachments-download.iam.gserviceaccount.com"
}

我想知道我做错了什么,或者是否有其他替代方法可以实现我的目标。

python google-api gmail-api google-api-python-client
1个回答
1
投票

由于该错误专门讨论身份验证凭据,因此我认为可以相当安全地假设问题位于此处:

creds = Credentials.from_service_account_file(r'token.json',
                                            scopes['https://www.googleapis.com/auth/gmail.readonly'])

由于这是我能够找到的唯一处理凭据的行,我相信问题在于发送的凭据实际上来自服务帐户本身,问题在于服务帐户本身没有访问权限其他人的电子邮件数据。这绝对可以解决!这是通过添加模拟来完成的,如下所示:

creds = Credentials.from_service_account_file(r'token.json',
                                            scopes['https://www.googleapis.com/auth/gmail.readonly'])

delegated_credentials = credentials.with_subject('Email_address_of_the_recipient')

在上面代码的引号内添加收件人的电子邮件地址将告诉代码代表您尝试访问其电子邮件的用户发送请求。但是,请记住,为此,您需要为服务帐户提供域范围委派

© www.soinside.com 2019 - 2024. All rights reserved.