Как загружать вложения из Gmail через Google API с помощью Python

Я хочу загрузить любые вложения, полученные с определенного адреса электронной почты за последние 12 часов, через платформу Google API с использованием Python. Я использую следующий код.

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"
}

Я хотел бы знать, что я делаю неправильно, или есть ли другие альтернативные средства, с помощью которых я могу достичь своей цели.

В ответе прямо говорится: В запросе отсутствуют необходимые учетные данные для аутентификации. Ожидаемый токен доступа OAuth 2, файл cookie для входа или другие действительные учетные данные для аутентификации. См. Developers.google.com/identity/sign-in/web/devconsole-projec‌​t.

Cow 24.04.2023 08:24
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
1
99
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')

Добавление адреса электронной почты получателя в кавычки приведенного выше кода сообщит коду о необходимости отправки запроса от имени пользователя, электронные письма которого вы пытаетесь получить. Однако имейте в виду, что для этого вам необходимо предоставить сервисному аккаунту широкое делегирование домена

Я предоставил широкое делегирование домена, но, похоже, это не решает мою проблему.

Marvin 25.04.2023 09:05

Делегирование на уровне домена предназначено только для того, чтобы разрешить учетным записям службы отправлять запросы от имени других пользователей, чтобы сообщить скрипту, от кого будет отправляться запрос. Этого можно добиться, добавив параметр with_subject в строки аутентификации, например: creds = Credentials.from_service_account_file(r'token.json', scopes['https://www.googleapis.com/auth/gmail.readonly']) delegated_credentials = credentials.with_subject('[email protected]') Пожалуйста, не забудьте заменить «[email protected]» на получателя писем.

Rene Olivo 25.04.2023 14:55

Другие вопросы по теме