Cómo liberar o rechazar mensajes en lotes

Cuando necesites realizar acciones en muchos mensajes en cuarentena a la vez, usa los métodos por lotes del recurso customers.quarantinedMessages en la API de Mail Admin Quarantine:

Ambos métodos son asíncronos. La API acepta la solicitud, devuelve una operación de larga duración y procesa los mensajes en segundo plano. Luego, sondeas el método get del recurso customers.operations hasta que se complete la operación y lees los resultados por mensaje de la respuesta.

En comparación con llamar a los métodos de un solo mensaje en un bucle, los métodos por lotes se consideran como una solicitud de escritura en tu uso de cuota, independientemente de la cantidad de mensajes que contengan.

Requisitos previos

Inicia una operación por lotes

Para liberar mensajes en un lote, envía una solicitud POST al método personalizado :batchRelease en el recurso customers.quarantinedMessages. El array requests contiene un objeto por mensaje, cada uno con el nombre del recurso del mensaje:

POST https://mailadminquarantine.googleapis.com/v1/customers/CUSTOMER_ID/quarantinedMessages:batchRelease
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json

{
  "requests": [
    {"name": "customers/CUSTOMER_ID/quarantinedMessages/user1@example.com:18d3ef45a8b2c1d0"},
    {"name": "customers/CUSTOMER_ID/quarantinedMessages/user2@example.com:18d3ef45a8b2c1d1"}
  ]
}

Para rechazar mensajes en un lote, envía el mismo cuerpo de la solicitud al método personalizado :batchDeny en el recurso customers.quarantinedMessages:

POST https://mailadminquarantine.googleapis.com/v1/customers/CUSTOMER_ID/quarantinedMessages:batchDeny

Cada solicitud debe contener entre 1 y 500 entradas. Cada mensaje debe pertenecer al cliente en la ruta de la solicitud. Una solicitud con más de 500 entradas devuelve un error 400 INVALID_ARGUMENT.

La API responde de inmediato con un recurso Operation:

{
  "name": "customers/01abc23de/operations/7f1c2a0e-5b7d-4d3a-9c1e-2f4b6a8d0e13",
  "metadata": {
    "@type": "type.googleapis.com/google.gmail.mailadminquarantine.v1.BatchReleaseQuarantinedMessagesMetadata",
    "state": "PROCESSING",
    "processedCount": 0,
    "totalCount": 2
  },
  "done": false
}

Almacena el name de la operación. Lo necesitas para verificar el progreso de la operación.

Verifica el estado de una operación por lotes

Para verificar el progreso de una operación por lotes, envía una solicitud GET al método get en el nombre del recurso de la operación:

GET https://mailadminquarantine.googleapis.com/v1/customers/CUSTOMER_ID/operations/OPERATION_ID
Authorization: Bearer ACCESS_TOKEN

El método get acepta cualquier permiso de la API de Cuarentena de administrador, por lo que una integración de solo lectura puede supervisar las operaciones que inició otro sistema.

Mientras se ejecuta la operación, el campo done se establece en false y el campo metadata informa el progreso:

Campo de metadatos Descripción
state PROCESSING mientras se procesan los mensajes y, luego, SUCCEEDED o FAILED.
processedCount Es la cantidad de mensajes procesados hasta el momento.
totalCount Es la cantidad total de mensajes del lote.

Cuando finaliza la operación, el campo done se establece en true y el campo response contiene un resultado para cada mensaje del lote:

{
  "name": "customers/01abc23de/operations/7f1c2a0e-5b7d-4d3a-9c1e-2f4b6a8d0e13",
  "metadata": {
    "@type": "type.googleapis.com/google.gmail.mailadminquarantine.v1.BatchReleaseQuarantinedMessagesMetadata",
    "state": "SUCCEEDED",
    "processedCount": 2,
    "totalCount": 2
  },
  "done": true,
  "response": {
    "@type": "type.googleapis.com/google.gmail.mailadminquarantine.v1.BatchReleaseQuarantinedMessagesResponse",
    "results": [
      {
        "name": "customers/01abc23de/quarantinedMessages/user1@example.com:18d3ef45a8b2c1d0",
        "status": {},
        "quarantinedMessage": {
          "name": "customers/01abc23de/quarantinedMessages/user1@example.com:18d3ef45a8b2c1d0",
          "messageId": "18d3ef45a8b2c1d0",
          "messageOwner": "user1@example.com",
          "state": "RELEASED"
        }
      },
      {
        "name": "customers/01abc23de/quarantinedMessages/user2@example.com:18d3ef45a8b2c1d1",
        "status": {
          "code": 5,
          "message": "Quarantined message not found"
        }
      }
    ]
  }
}

Cada entrada en results describe el resultado de un mensaje:

Campo de resultado Descripción
name Es el nombre del recurso del mensaje.
status Un google.rpc.Status. Un objeto vacío (código 0, OK) significa que la acción se realizó correctamente. De lo contrario, code y message explican por qué se omitió el mensaje.
quarantinedMessage El mensaje actualizado con su nuevo state. Solo está presente cuando status es OK.

Una operación por lotes se completa correctamente incluso si fallan algunos mensajes individuales. Siempre inspecciona el status de cada resultado en lugar de depender solo del state de la operación.

Si falla toda la operación, por ejemplo, porque el backend no está disponible, el campo done se establece en true y el campo error contiene un google.rpc.Status en lugar de response.

Ejemplo: Liberación por lotes y sondeo para la finalización

En el siguiente ejemplo de Python, se inicia una versión por lotes y se sondea la operación cada pocos segundos hasta que se completa:

import time
import requests

BASE_URL = 'https://mailadminquarantine.googleapis.com/v1'
CUSTOMER_ID = '01abc23de'  # Your customer ID without the leading 'C'.
headers = {
    'Authorization': f'Bearer {access_token}',
    'Content-Type': 'application/json',
}

# message_names is a list of up to 500 quarantined message resource names.
batch_url = f'{BASE_URL}/customers/{CUSTOMER_ID}/quarantinedMessages:batchRelease'
body = {'requests': [{'name': name} for name in message_names]}
operation = requests.post(batch_url, headers=headers, json=body)
operation.raise_for_status()
operation_name = operation.json()['name']

while True:
  status = requests.get(f'{BASE_URL}/{operation_name}', headers=headers)
  status.raise_for_status()
  operation = status.json()
  if operation.get('done'):
    break
  metadata = operation.get('metadata', {})
  print(f"Processed {metadata.get('processedCount', 0)} of "
        f"{metadata.get('totalCount', 0)} messages...")
  time.sleep(5)

if 'error' in operation:
  raise RuntimeError(f"Batch failed: {operation['error']}")

for result in operation['response'].get('results', []):
  if result.get('status', {}).get('code', 0) == 0:
    print(f"Released: {result['name']}")
  else:
    print(f"Skipped {result['name']}: {result['status'].get('message')}")

Próximos pasos