La API de Gmail te permite subir datos de archivos cuando creas o actualizas un borrador, o cuando insertas o envías un mensaje.
Opciones de carga
La API de Gmail te permite subir ciertos tipos de datos binarios o multimedia. Las características específicas de los datos que puedes cargar se describen en la página de referencia de cualquier método compatible con cargas de contenido multimedia:
- Tamaño máximo de carga de archivos: La cantidad máxima de datos que puedes almacenar con este método.
- Tipos de MIME multimedia aceptados: Los tipos de datos binarios que puedes almacenar con este método.
Puedes realizar solicitudes de carga de cualquiera de las siguientes formas. Especifica el método que estás usando con el parámetro de solicitud uploadType
.
- Carga simple:
uploadType=media
. Se usa para lograr una transferencia rápida de archivos más pequeños, por ejemplo, de 5 MB o menos. - Carga multiparte:
uploadType=multipart
. Para una transferencia rápida de metadatos y archivos pequeños, transfiere el archivo con los metadatos que lo describen en una única solicitud. - Carga reanudable:
uploadType=resumable
. Para una transferencia confiable, es importante en particular para archivos más grandes. Con este método, utilizas una solicitud de inicio de sesión, que puede incluir metadatos. Esta es una buena estrategia para la mayoría de las aplicaciones, ya que también funciona para archivos más pequeños al costo de una solicitud HTTP adicional por carga.
Cuando subes contenido multimedia, utilizas un URI específico. De hecho, los métodos compatibles con cargas de este tipo de contenido tienen dos extremos de URI:
El URI /upload, para elementos multimedia. El formato del extremo de carga es el URI de recurso estándar con el prefijo “/upload”. Usa este URI cuando transfieras los datos del contenido multimedia.
Ejemplo:
POST /upload/gmail/v1/users/userId/messages/send
El URI de recurso estándar, para los metadatos. Si el recurso contiene campos de datos, esos campos se usan para almacenar metadatos que describen el archivo subido. Puedes usar este URI cuando creas o actualizas valores de metadatos.
Ejemplo:
POST /gmail/v1/users/userId/messages/send
Carga simple
El método más sencillo para subir un archivo es realizar una solicitud de carga simple. Esta es una buena opción en los siguientes casos:
- Cuando el archivo es lo suficientemente pequeño como para volver a subirlo por completo si falla la conexión
- Si no hay metadatos para enviar (esto podría ocurrir si tienes pensado enviar metadatos para este recurso en una solicitud independiente o si no se admiten metadatos o estos no están disponibles)
Para usar una carga simple, realiza una solicitud POST
o PUT
al URI /upload del método y agrega el parámetro de consulta uploadType=media
. Por ejemplo:
POST https://www.googleapis.com/upload/gmail/v1/users/userId/messages/send?uploadType=media
Entre los encabezados HTTP que se deben usar cuando se realiza una solicitud de carga simple, se incluyen los siguientes:
Content-Type
. Se establece como uno de los tipos de datos multimedia aceptados del método, según se especifica en la referencia de la API.Content-Length
. Se establece como la cantidad de bytes que estás subiendo. No es necesario si usas la codificación de transferencia fragmentada.
Ejemplo: Carga simple
En el siguiente ejemplo, se muestra el uso de una solicitud de carga simple para la API de Gmail.
POST /upload/gmail/v1/users/userId/messages/send?uploadType=media HTTP/1.1 Host: www.googleapis.com Content-Type: message/rfc822 Content-Length: number_of_bytes_in_file Authorization: Bearer your_auth_token Email Message data
Si la solicitud se realiza correctamente, el servidor muestra el código de estado HTTP 200 OK
junto con los metadatos:
HTTP/1.1 200 Content-Type: application/json {
"id": string,
"threadId": string,
"labelIds": [
string
],
"snippet": string,
"historyId": unsigned long,
"payload": {
"partId": string,
"mimeType": string,
"filename": string,
"headers": [
{
"name": string,
"value": string
}
],
"body": users.messages.attachments Resource,
"parts": [
(MessagePart)
]
},
"sizeEstimate": integer,
"raw": bytes
}
Carga multiparte
Si tienes metadatos que deseas enviar junto con los datos que vas a cargar, puedes realizar una única solicitud multipart/related
. Esta es una buena opción si los datos que vas a enviar son pequeños como para volver a subirlos en su totalidad si la conexión falla.
Para usar la carga multiparte, realiza una solicitud POST
o PUT
al URI /upload del método y agrega el parámetro de consulta uploadType=multipart
. Por ejemplo:
POST https://www.googleapis.com/upload/gmail/v1/users/userId/messages/send?uploadType=multipart
Entre los encabezados HTTP de nivel superior que se deben usar cuando se realiza una solicitud de carga multiparte, se incluyen los siguientes:
Content-Type
. Configurado como multiparte/relacionado; incluye la string de límite que usas para identificar las partes de la solicitud.Content-Length
. Configurado como la cantidad total de bytes en el cuerpo de la solicitud. La parte de medios de la solicitud debe ser menor que el tamaño máximo del archivo especificado para este método.
El cuerpo de la solicitud tiene el formato de un tipo de contenido multipart/related
[RFC2387] y contiene dos partes. Las partes se identifican mediante una string de límite, y la última string de límite está seguida por dos guiones.
Cada parte de la solicitud multiparte necesita un encabezado Content-Type
adicional:
- Parte de metadatos: Debe ir primero, y
Content-Type
debe coincidir con uno de los formatos de metadatos aceptados. - Parte de elementos multimedia: debe ir en segundo lugar y
Content-Type
debe coincidir con uno de los tipos MIME de contenido multimedia aceptados del método.
Consulta la referencia de la API para conocer la lista de tipos MIME de medios aceptados del método y los límites de tamaño de los archivos subidos.
Nota: Para crear o actualizar solo la parte de metadatos, sin subir los datos relacionados, envía una solicitud POST
o PUT
al extremo de recurso estándar: https://www.googleapis.com/gmail/v1/users/userId/messages/send
Ejemplo: Carga multiparte
En el siguiente ejemplo, se muestra una solicitud de carga multiparte para la API de Gmail.
POST /upload/gmail/v1/users/userId/messages/send?uploadType=multipart HTTP/1.1 Host: www.googleapis.com Authorization: Bearer your_auth_token Content-Type: multipart/related; boundary=foo_bar_baz Content-Length: number_of_bytes_in_entire_request_body --foo_bar_baz Content-Type: application/json; charset=UTF-8 {
"id": string,
"threadId": string,
"labelIds": [
string
],
"snippet": string,
"historyId": unsigned long,
"payload": {
"partId": string,
"mimeType": string,
"filename": string,
"headers": [
{
"name": string,
"value": string
}
],
"body": users.messages.attachments Resource,
"parts": [
(MessagePart)
]
},
"sizeEstimate": integer,
"raw": bytes
} --foo_bar_baz Content-Type: message/rfc822 Email Message data --foo_bar_baz--
Si la solicitud se realiza con éxito, el servidor muestra el código de estado HTTP 200 OK
junto con los metadatos:
HTTP/1.1 200 Content-Type: application/json {
"id": string,
"threadId": string,
"labelIds": [
string
],
"snippet": string,
"historyId": unsigned long,
"payload": {
"partId": string,
"mimeType": string,
"filename": string,
"headers": [
{
"name": string,
"value": string
}
],
"body": users.messages.attachments Resource,
"parts": [
(MessagePart)
]
},
"sizeEstimate": integer,
"raw": bytes
}
Carga reanudable
Para cargar archivos de datos de manera más confiable, puedes usar el protocolo de carga reanudable. Con este protocolo, puedes reanudar una operación de carga si una falla de comunicación interrumpe el flujo de datos. Esto resulta útil cuando transfieres archivos grandes, y existe una probabilidad alta de que se interrumpa la conexión de red o de que se genere alguna otra falla de transmisión, como puede ocurrir, por ejemplo, cuando subes archivos desde una app cliente para dispositivos móviles. Además, se puede reducir tu uso del ancho de banda ante fallas en la red, ya que no necesitas reiniciar la carga de archivos grandes desde el principio.
Entre los pasos para usar cargas reanudables se incluyen los siguientes:
- Inicia una sesión reanudable. Realiza una solicitud inicial al URI de carga que incluya los metadatos, si corresponde.
- Guarda el URI de la sesión reanudable. Guarda el URI de la sesión que se muestra en la respuesta de la solicitud inicial; lo utilizarás para las solicitudes restantes en esta sesión.
- Sube el archivo. Envía el archivo de medios al URI de la sesión reanudable.
Además, las aplicaciones que usan carga reanudable deben tener un código para reanudar una carga interrumpida. Si se interrumpe una carga, averigua cuántos datos se recibieron de forma correcta y, a continuación, reanuda la carga desde ese punto.
Nota: Un URI de carga expira en una semana.
Paso 1: Inicia una sesión reanudable
Para iniciar una carga reanudable, realiza una solicitud POST
o PUT
al URI /upload del método y agrega el parámetro de consulta uploadType=resumable
. Por ejemplo:
POST https://www.googleapis.com/upload/gmail/v1/users/userId/messages/send?uploadType=resumable
Para esta solicitud de inicio, el cuerpo está vacío o contiene solo los metadatos; transferirás el contenido real del archivo que deseas cargar en solicitudes posteriores.
Usa los siguientes encabezados HTTP con la solicitud inicial:X-Upload-Content-Type
. Configurado como el tipo MIME de contenido multimedia de los datos de carga que se transferirán en solicitudes posteriores.X-Upload-Content-Length
. Configurado como la cantidad de bytes de datos de carga que se transferirán en solicitudes posteriores. Si no se conoce la longitud en el momento que se realiza esta solicitud, puedes omitir este encabezado.- Si se proporcionan metadatos:
Content-Type
. Configurado de acuerdo con el tipo de datos de los metadatos. Content-Length
. Configurado como la cantidad de bytes que se proporcionaron en el cuerpo de esta solicitud inicial. No es necesario si usas la codificación de transferencia fragmentada.
Consulta la referencia de la API para conocer la lista de tipos MIME de medios aceptados del método y los límites de tamaño de los archivos subidos.
Ejemplo: Solicitud de inicio de sesión reanudable
En el siguiente ejemplo, se muestra cómo iniciar una sesión reanudable para la API de Gmail.
POST /upload/gmail/v1/users/userId/messages/send?uploadType=resumable HTTP/1.1 Host: www.googleapis.com Authorization: Bearer your_auth_token Content-Length: 38 Content-Type: application/json; charset=UTF-8 X-Upload-Content-Type: message/rfc822 X-Upload-Content-Length: 2000000 {
"id": string,
"threadId": string,
"labelIds": [
string
],
"snippet": string,
"historyId": unsigned long,
"payload": {
"partId": string,
"mimeType": string,
"filename": string,
"headers": [
{
"name": string,
"value": string
}
],
"body": users.messages.attachments Resource,
"parts": [
(MessagePart)
]
},
"sizeEstimate": integer,
"raw": bytes
}
Nota: En una solicitud de actualización reanudable inicial sin metadatos, deja el cuerpo de la solicitud vacío y configura el encabezado Content-Length
como 0
.
En la próxima sección, se describe cómo manejar la respuesta.
Paso 2: Guarda el URI de la sesión reanudable
Si la solicitud de inicio de sesión tiene éxito, el servidor de la API responde con un código de estado HTTP 200 OK
. Además, proporciona un encabezado Location
que especifica el URI de la sesión reanudable. El encabezado Location
, que se muestra a continuación, incluye una parte del parámetro de búsqueda upload_id
que proporciona el ID de carga único que se debe usar en esta sesión.
Ejemplo: Respuesta de inicio de sesión reanudable
A continuación, se muestra la respuesta a la solicitud presentada en el paso 1:
HTTP/1.1 200 OK Location: https://www.googleapis.com/upload/gmail/v1/users/userId/messages/send?uploadType=resumable&upload_id=xa298sd_sdlkj2 Content-Length: 0
El valor del encabezado Location
, como se muestra en la respuesta de ejemplo anterior, es el URI de sesión que usarás como extremo HTTP para cargar el archivo o consultar el estado de carga.
Copia y guarda el URI de sesión para poder usarlo en solicitudes posteriores.
Paso 3: carga el archivo
Para cargar el archivo, envía una solicitud PUT
al URI de carga que obtuviste en el paso anterior. El formato de la solicitud de carga es el siguiente:
PUT session_uri
Los encabezados HTTP que se deben usar cuando se realizan solicitudes de carga de archivos reanudables incluyen Content-Length
. Configúralo como la cantidad de bytes que cargarás en esta solicitud, que suele ser el tamaño del archivo que se carga.
Ejemplo: Solicitud de carga de archivo reanudable
Esta es una solicitud reanudable para subir el archivo de mensaje de correo electrónico de 2,000,000 de bytes del ejemplo actual.
PUT https://www.googleapis.com/upload/gmail/v1/users/userId/messages/send?uploadType=resumable&upload_id=xa298sd_sdlkj2 HTTP/1.1 Content-Length: 2000000 Content-Type: message/rfc822 bytes 0-1999999
Si la solicitud tiene éxito, el servidor responde con HTTP 201 Created
y con todos los metadatos asociados a ese recurso. Si la solicitud inicial de la sesión reanudable hubiera sido PUT
, para actualizar un recurso existente, la respuesta que indica que se realizó con éxito sería 200 OK
, junto con todos los metadatos asociados a este recurso.
Si se interrumpe la solicitud de carga, o si recibes una respuesta HTTP 503 Service Unavailable
o cualquier otra respuesta 5xx
por parte del servidor, sigue el procedimiento que se detalla en la sección sobre cómo reanudar una carga interrumpida.
Sube el archivo en partes
Con las cargas reanudables, puedes fragmentar un archivo y enviar diferentes solicitudes para cargar cada parte en secuencia. No se recomienda este enfoque, ya que tiene costos de rendimiento asociados con las solicitudes adicionales y, por lo general, no es necesario. Sin embargo, es posible que necesites usar la fragmentación para reducir la cantidad de datos que se transfieren en una sola solicitud. Esto es útil cuando hay un límite de tiempo fijo para las solicitudes individuales, como ocurre con ciertas clases de solicitudes de Google App Engine. Además, te permite realizar acciones como proporcionar indicaciones del progreso de una carga a los navegadores heredados que no cuentan con asistencia de progreso de carga de forma predeterminada.
Reanuda una carga interrumpida
Si una solicitud de carga se interrumpe antes de que recibas una respuesta, o si recibes una respuesta HTTP 503 Service Unavailable
por parte del servidor, debes reanudar la carga interrumpida. Para ello, sigue estos pasos:
- Estado de la solicitud. Consulta el estado actual de la carga mediante una solicitud
PUT
vacía al URI de carga. En esta solicitud, los encabezados HTTP deben incluir un encabezadoContent-Range
que indique que se desconoce la posición actual en el archivo. Por ejemplo, configuraContent-Range
como*/2000000
si la longitud total del archivo es 2,000,000. Si desconoces el tamaño original del archivo, configuraContent-Range
como*/*
.Nota: Puedes solicitar el estado entre partes, no solo si se interrumpe la carga. Eso es útil, por ejemplo, si deseas mostrar indicaciones de progreso de carga para los navegadores heredados.
- Obtén la cantidad de bytes cargados. Procesa la respuesta de la consulta de estado. El servidor usa el encabezado
Range
en su respuesta para especificar qué bytes recibió hasta el momento. Por ejemplo, un encabezadoRange
de0-299999
indica que se recibieron los primeros 300,000 bytes del archivo. - Sube los datos restantes. Por último, ahora que sabes dónde reanudar la solicitud, envía los datos restantes o la parte actual. Ten en cuenta que, en cualquiera de ambos casos, debes tratar a los datos restantes como partes separadas, por lo que necesitarás enviar el encabezado
Content-Range
cuando reanudes la carga.
Ejemplo: Reanuda una carga interrumpida
1) Solicita el estado de la carga.
En la siguiente solicitud, se usa el encabezado Content-Range
para indicar que se desconoce la posición actual en el archivo de 2,000,000 bytes.
PUT {session_uri} HTTP/1.1 Content-Length: 0 Content-Range: bytes */2000000
2) Extrae de la respuesta la cantidad de bytes cargados hasta el momento.
En la respuesta del servidor, se usa el encabezado Range
para indicar que se recibieron los primeros 43 bytes del archivo hasta el momento. Usa el valor superior del encabezado Range
para determinar dónde comenzar la carga reanudada.
HTTP/1.1 308 Resume Incomplete Content-Length: 0 Range: 0-42
Nota: Es posible que la respuesta de estado sea 201 Created
o 200 OK
si se completó la carga. Esto podría suceder si la conexión falló después de que se hayan cargado todos los bytes, pero antes de que el cliente haya recibido una respuesta del servidor.
3) Reanuda la carga desde el punto en que se detuvo.
La siguiente solicitud reanuda la carga; para ello, envía los bytes restantes del archivo a partir del byte 43.
PUT {session_uri} HTTP/1.1 Content-Length: 1999957 Content-Range: bytes 43-1999999/2000000 bytes 43-1999999
Prácticas recomendadas
Cuando cargues contenido multimedia, es útil conocer algunas de las prácticas recomendadas relacionadas con el manejo de errores:
- Reanuda o reintenta cargas que no se realizaron de forma correcta debido a interrupciones en la conexión o cualquier error
5xx
, incluidos los siguientes:500 Internal Server Error
502 Bad Gateway
503 Service Unavailable
504 Gateway Timeout
- Usa una estrategia de retirada exponencial si se muestra cualquier error de servidor
5xx
cuando reanudas o reintentas solicitudes de carga. Estos errores pueden ocurrir si un servidor se está sobrecargando. La retirada exponencial puede ayudarte a aliviar este tipo de problemas durante períodos de gran volumen de solicitudes o de tráfico de red intenso. - No deben manejarse otros tipos de solicitudes mediante retirada exponencial, pero igual puedes reintentar varias de ellas. Cuando reintentes estas solicitudes, limita la cantidad de veces que lo haces. Por ejemplo, tu código podría limitarse a diez reintentos o menos antes de informar un error.
- Maneja los errores
404 Not Found
y410 Gone
cuando realices cargas reanudables; para ello, vuelve a iniciar toda la carga desde el principio.
Retirada exponencial
La retirada exponencial es una estrategia estándar de manejo de errores para aplicaciones de red en la que el cliente reintenta de forma periódica una solicitud con errores durante un período creciente. Si el servidor presenta errores debido a un gran volumen de solicitudes o tráfico de red, la retirada exponencial puede ser una buena estrategia para manejar estos errores. Por el contrario, esta estrategia no se recomienda para lidiar con errores que no estén relacionados con el volumen de la red o los tiempos de respuesta, como credenciales de autorización no válidas o errores de archivos no encontrados.
Si se la utiliza de forma correcta, la retirada exponencial aumenta la eficiencia del uso del ancho de banda, reduce la cantidad de solicitudes que se requieren para obtener una respuesta correcta y maximiza la capacidad de procesamiento de las solicitudes en entornos simultáneos.
A continuación, se muestra el flujo para implementar una retirada exponencial simple:
- Realizar una solicitud a la API
- Recibir una respuesta
HTTP 503
, que indica que debes reintentar la solicitud - Esperar 1 segundo + random_number_milliseconds y reintentar la solicitud
- Recibir una respuesta
HTTP 503
, que indica que debes reintentar la solicitud - Esperar 2 segundos + random_number_milliseconds y reintentar la solicitud
- Recibir una respuesta
HTTP 503
, que indica que debes reintentar la solicitud - Esperar 4 segundos + random_number_milliseconds y reintentar la solicitud
- Recibir una respuesta
HTTP 503
, que indica que debes reintentar la solicitud - Esperar 8 segundos + random_number_milliseconds y reintentar la solicitud
- Recibir una respuesta
HTTP 503
, que indica que debes reintentar la solicitud - Esperar 16 segundos + random_number_milliseconds y reintentar la solicitud
- Detenerse. Informar o registrar un error
En el flujo anterior, random_number_milliseconds es una cantidad aleatoria de milisegundos menor o igual que 1,000. Esta es necesaria, ya que agregar un pequeño retraso aleatorio ayuda a distribuir la carga de manera más uniforme y a evitar la posibilidad de marcar el servidor. El valor de random_number_milliseconds se debe volver a definir tras cada espera.
Nota: La espera siempre es (2 ^ n) + random_number_milliseconds, en la que n es un número entero, que crece de forma monotónica, definido en un inicio como 0. El número entero n aumenta de a 1 por cada iteración (cada solicitud).
El algoritmo está configurado para terminar cuando n sea 5. Este límite impide que los clientes reintenten las solicitudes de forma infinita y genera una demora total de alrededor de 32 segundos antes de que una solicitud se considere “un error irrecuperable”. Un límite de reintentos mayor es aceptable, sobre todo si hay una carga larga en progreso. Solo asegúrate de limitar la demora de reintentos a un valor razonable, por ejemplo, menos de un minuto.