Importation des pièces jointes

L'API Gmail vous permet d'importer des données de fichier lorsque vous créez ou modifiez un brouillon, ou lorsque vous insérez ou envoyez un message.

Options d'importation

L'API Gmail vous permet d'importer certains types de données binaires ou de médias. Les caractéristiques spécifiques des données que vous pouvez importer sont spécifiées sur la page de référence pour toutes les méthodes compatibles avec l'importation de médias :

  • Taille maximale du fichier d'importation : quantité maximale de données que vous pouvez stocker à l'aide de cette méthode.
  • Types MIME de médias acceptés : types de données binaires que vous pouvez stocker à l'aide de cette méthode.

Vous pouvez effectuer des requêtes d'importation via l'une des méthodes exposées ci-dessous. Spécifiez la méthode que vous utilisez avec le paramètre de requête uploadType.

  • Importation simple : uploadType=media. Permet de transférer rapidement des fichiers de petite taille, par exemple de 5 Mo ou moins.
  • Importation en plusieurs parties : uploadType=multipart. Pour un transfert rapide de petits fichiers et métadonnées ; transfère le fichier avec les métadonnées qui le décrivent dans une seule requête.
  • Importation avec reprise : uploadType=resumable. Pour un transfert fiable, particulièrement important avec des fichiers plus volumineux. Avec cette méthode, vous utilisez une requête de lancement de session qui peut éventuellement inclure des métadonnées. Il s'agit d'une bonne stratégie à utiliser pour la plupart des applications, car elle fonctionne également pour des fichiers plus petits au prix d'une requête HTTP supplémentaire par importation.

Lorsque vous importez un média, vous utilisez un URI spécial. Concrètement, les méthodes compatibles avec l'importation de médias possèdent deux points de terminaison URI :

  • URI /upload pour les médias – Le format du point de terminaison de l'importation correspond à l'URI de ressource standard avec un préfixe "/upload". Utilisez cet URI lors du transfert des données du média.

    Exemple : POST /upload/gmail/v1/users/userId/messages/send

  • URI de ressource standard pour les métadonnées – Si la ressource contient des champs de données, ces champs sont utilisés pour stocker les métadonnées décrivant le fichier importé. Vous pouvez utiliser cet URI pour créer ou mettre à jour des valeurs de métadonnées.

    Example : POST /gmail/v1/users/userId/messages/send

Importation simple

La méthode la plus simple pour importer un fichier consiste à effectuer une requête d'importation simple. Cette option est recommandée dans les cas suivants:

  • Le fichier est suffisamment petit pour être réimporté dans son intégralité en cas d'échec de connexion.
  • Aucune métadonnée ne doit être envoyée. Par exemple, vous prévoyez d'envoyer des métadonnées pour cette ressource dans une requête distincte, ou les métadonnées ne sont pas disponibles ou prises en charge.

Pour utiliser l'importation simple, envoyez une requête POST ou PUT à l'URI /upload de la méthode, puis ajoutez le paramètre de requête uploadType=media. Exemple :

POST https://www.googleapis.com/upload/gmail/v1/users/userId/messages/send?uploadType=media

Voici les en-têtes HTTP à utiliser lors d'une requête d'importation simple :

  • Content-Type : spécifiez-y l'un des types de données de médias d'importation acceptés par la méthode, comme indiqué dans la documentation de référence de l'API.
  • Content-Length : spécifiez-y le nombre d'octets que vous importez. Cet en-tête n'est pas requis si vous utilisez l'encodage de transfert fragmenté.

Exemple: Importation simple

L'exemple suivant illustre l'utilisation d'une requête d'importation simple pour l'API 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 requête aboutit, le serveur affiche le code d'état HTTP 200 OK avec toutes les métadonnées :

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
}

Importation en plusieurs parties

Si vous souhaitez envoyer des métadonnées avec les données à importer, vous pouvez effectuer une seule requête multipart/related. Cette opération est judicieuse si les données que vous envoyez sont suffisamment petites pour pouvoir être importées intégralement en cas d'échec de connexion.

Pour utiliser l'importation en plusieurs parties, envoyez une requête POST ou PUT à l'URI /upload de la méthode, puis ajoutez le paramètre de requête uploadType=multipart. Exemple:

POST https://www.googleapis.com/upload/gmail/v1/users/userId/messages/send?uploadType=multipart

Les en-têtes HTTP de premier niveau à utiliser lors d'une importation en plusieurs parties incluent :

  • Content-Type. Défini sur "multipart/related" et incluant la chaîne de délimitation que vous utilisez pour identifier les parties de la requête.
  • Content-Length. Défini sur le nombre total d'octets dans le corps de la requête. La partie de médias de la requête doit être inférieure à la taille de fichier maximale spécifiée pour cette méthode.

Le corps de la requête est mis en forme en tant que type de contenu multipart/related [RFC2387] et contient exactement deux parties. Les parties sont identifiées par une chaîne de délimitation et la dernière chaîne est suivie de deux traits d'union.

Chaque partie de la requête en plusieurs parties nécessite un en-tête Content-Type supplémentaire :

  1. Partie de métadonnées : doit apparaître en premier. La valeur Content-Type doit correspondre à l'un des formats de métadonnées acceptés.
  2. Partie de médias : doit apparaître en second. La valeur Content-Type doit correspondre à l'un des types de média MIME acceptés pour la méthode.

Consultez la documentation de référence de l'API pour obtenir la liste des types MIME de médias acceptés et de limites de taille pour les fichiers importés, pour chaque méthode.

Remarque : Pour créer ou mettre à jour la partie de métadonnées uniquement, sans importer les données associées, envoyez simplement une requête POST ou PUT au point de terminaison de la ressource standard : https://www.googleapis.com/gmail/v1/users/userId/messages/send

Exemple : Importation en plusieurs parties

L'exemple ci-dessous montre une requête d'importation en plusieurs parties pour l'API 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 requête aboutit, le serveur affiche le code d'état HTTP 200 OK avec toutes les métadonnées :

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
}

Importation avec reprise

Pour importer des fichiers de données de manière plus fiable, vous pouvez utiliser le protocole d'importation avec reprise. Celui-ci vous permet de reprendre une opération d'importation après un échec de communication ayant interrompu le flux de données. Cette opération est particulièrement utile si vous transférez des fichiers volumineux et que les risques d'interruption du réseau ou d'échec de transmission sont élevés, par exemple si l'importation est réalisée depuis une application cliente mobile. Cela peut également réduire l'utilisation de la bande passante en cas de panne réseau, car cela vous évite de redémarrer les importations de fichiers volumineux depuis le début.

Pour réaliser une importation avec reprise, procédez comme suit :

  1. Démarrez une session avec reprise. Effectuez une requête initiale contenant les métadonnées à l'URI d'importation, le cas échéant.
  2. Enregistrez l'URI de la session avec reprise. Enregistrez l'URI de la session affichée dans la réponse à la requête initiale. Vous l'utiliserez pour les requêtes restantes dans cette session.
  3. Importez le fichier. Envoyez le fichier de médias à l'URI de la session avec reprise.

En outre, les applications qui utilisent l'importation avec reprise doivent posséder un code pour reprendre une importation interrompue. En cas d'interruption de l'importation, déterminez la quantité de données reçue, puis reprenez l'importation à partir de ce point.

Remarque : Une URI d'importation est valable une semaine.

Étape 1 : Démarrez une session avec reprise

Pour démarrer une importation avec reprise, envoyez une requête POST ou PUT à l'URI /upload de la méthode, puis ajoutez le paramètre de requête uploadType=resumable. Exemple:

POST https://www.googleapis.com/upload/gmail/v1/users/userId/messages/send?uploadType=resumable

Le corps de cette requête de lancement doit être vide ou ne contenir que les métadonnées. Vous allez transférer le contenu réel du fichier que vous souhaitez importer dans les requêtes ultérieures.

Utilisez les en-têtes HTTP suivants avec la requête initiale :

  • X-Upload-Content-Type. Définissez le type de média MIME des données d'importation à transférer dans les requêtes ultérieures.
  • X-Upload-Content-Length. Définissez le nombre d'octets des données d'importation à transférer dans les requêtes ultérieures. Si cette valeur est inconnue au moment de la requête, vous pouvez omettre cet en-tête.
  • Si vous fournissez des métadonnées : Content-Type. Définissez cette valeur en fonction du type de données des métadonnées.
  • Content-Length. Définissez le nombre d'octets fournis dans le corps de cette requête initiale. Cet en-tête n'est pas requis si vous utilisez l'encodage de transfert fragmenté.

Consultez la documentation de référence de l'API pour obtenir la liste des types MIME de médias acceptés et de limites de taille pour les fichiers importés, pour chaque méthode.

Exemple : Requête de lancement de session avec reprise

L'exemple suivant montre comment lancer une session avec reprise pour l'API 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
}

Remarque : Pour une requête initiale de mise à jour avec reprise sans métadonnées, ne remplissez pas le corps de la requête et définissez l'en-tête Content-Length sur 0.

La section suivante décrit comment gérer la réponse.

Étape 2 : Enregistrez l'URI de la session avec reprise

Si la requête de lancement de session aboutit, le serveur d'API répond par un code d'état HTTP 200 OK. En outre, il fournit un en-tête Location qui spécifie votre URI de session avec reprise. L'en-tête Location, illustré dans l'exemple ci-dessous, inclut une partie de paramètre de requête upload_id qui fournit l'ID d'importation unique à utiliser pour cette session.

Exemple : Réponse de lancement de session avec reprise

La réponse à la requête de l'étape 1 se présente comme suit :

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

La valeur de l'en-tête Location, comme indiqué dans l'exemple de réponse ci-dessus, correspond à l'URI de session que vous utiliserez comme point de terminaison HTTP afin d'effectuer l'importation du fichier ou d'interroger le statut de l'importation.

Copiez et enregistrez l'URI de la session afin de pouvoir l'utiliser pour les requêtes ultérieures.

Étape 3 : Importez le fichier

Pour importer le fichier, envoyez une requête PUT à l'URI d'importation obtenu lors de l'étape précédente. Le format de la requête d'importation se présente comme suit :

PUT session_uri

Les en-têtes HTTP à utiliser lors des requêtes d'importation de fichiers avec reprise incluent Content-Length. Définissez cette valeur sur le nombre d'octets que vous importez dans cette requête, qui correspond généralement à la taille du fichier à importer.

Exemple : Requête d'importation de fichier avec reprise

Voici une requête avec reprise permettant d'importer l'intégralité du fichier de message d'e-mail de 2 000 000 octets pour l'exemple actuel.

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 requête aboutit, le serveur envoie une réponse HTTP 201 Created, ainsi que toutes les métadonnées associées à cette ressource. Si la requête initiale de la session avec reprise était PUT, la réponse positive serait 200 OK pour mettre à jour une ressource existante, avec toutes les métadonnées associées à cette ressource.

Si la requête d'importation est interrompue, ou si le serveur vous envoie une réponse HTTP 503 Service Unavailable ou toute autre réponse 5xx, suivez la procédure expliquant comment reprendre une importation interrompue.


Importer un fichier fragmenté

Les importations avec reprise vous permettent de diviser un fichier en plusieurs fragments et d'envoyer une série de requêtes afin d'importer chacun de ces fragments l'un après l'autre. Cette méthode n'est pas conseillée, car des coûts de performance sont associés aux requêtes supplémentaires, ce qui n'est généralement pas nécessaire. Toutefois, vous aurez peut-être recours à la fragmentation pour réduire la quantité de données transférées dans une seule requête. Cela est utile lorsque le temps imparti à chaque requête est limité pour les requêtes individuelles, comme c'est le cas pour certaines classes de requêtes Google App Engine. Cela vous permet également de fournir des indications concernant la progression de l'importation pour les anciens navigateurs qui ne possèdent pas cette fonctionnalité par défaut.


Reprendre une importation interrompue

Si une requête d'importation se termine avant de recevoir une réponse ou si vous recevez une réponse 503 Service Unavailable du serveur, vous devez reprendre l'importation interrompue. Procédez comme suit :

  1. Interrogez l'état. Interrogez l'état actuel de l'importation en envoyant une requête PUT vide à l'URI d'importation. Pour cette requête, les en-têtes HTTP doivent inclure un en-tête Content-Range indiquant que la position actuelle dans le fichier est inconnue. Par exemple, définissez Content-Range sur */2000000 si la longueur totale de votre fichier correspond à 2 000 000. Si vous ignorez la taille totale du fichier, définissez Content-Range sur */*.

    Remarque : Vous pouvez interroger l'état entre les fragments, et pas seulement si l'importation est interrompue. Cette opération est utile si vous souhaitez afficher les indications concernant la progression de l'importation pour les navigateurs anciens, par exemple.

  2. Obtenez le nombre d'octets importés. Traitez la réponse à partir de la requête d'état. Le serveur utilise l'en-tête Range dans sa réponse pour spécifier les octets reçus jusqu'à présent. Par exemple, un en-tête Range de 0-299999 indique que les 300 000 premiers octets du fichier ont été reçus.
  3. Importez les données restantes. Enfin, maintenant que vous savez où reprendre la requête, envoyez les données restantes ou le fragment actuel. Notez que vous devez traiter les données restantes comme un fragment séparé dans tous les cas. Vous devez donc envoyer l'en-tête Content-Range au moment de la reprise de l'importation.
Exemple : Reprendre une importation interrompue

1) Interrogez l'état de l'importation.

La requête suivante utilise l'en-tête Content-Range pour indiquer que la position actuelle dans le fichier de 2 000 000 octets est inconnue.

PUT {session_uri} HTTP/1.1
Content-Length: 0
Content-Range: bytes */2000000

2) Procédez à l'extraction du nombre d'octets importés jusqu'à présent à partir de la réponse.

La réponse du serveur utilise l'en-tête Range pour indiquer qu'il a reçu les 43 premiers octets du fichier jusqu'à présent. Utilisez la valeur supérieure de l'en-tête Range pour déterminer où démarrer la reprise de l'importation.

HTTP/1.1 308 Resume Incomplete
Content-Length: 0
Range: 0-42

Remarque : Il est possible que la réponse d'état soit 201 Created ou 200 OK si l'importation est terminée. Cette situation peut se produire si la connexion s'interrompt après l'importation de tous les octets, mais avant que le client ne reçoive une réponse du serveur.

3) Reprenez l'importation là où elle s'était arrêtée.

La requête suivante reprend l'importation en envoyant les octets restants du fichier, en commençant par l'octet 43.

PUT {session_uri} HTTP/1.1
Content-Length: 1999957
Content-Range: bytes 43-1999999/2000000

bytes 43-1999999

Bonnes pratiques

En ce qui concerne l'importation de médias, il est utile de connaître certaines bonnes pratiques en matière de traitement des erreurs.

  • Reprenez ou relancez les importations qui échouent en raison d'interruptions de connexion ou d'erreurs 5xx, parmi lesquelles :
    • 500 Internal Server Error
    • 502 Bad Gateway
    • 503 Service Unavailable
    • 504 Gateway Timeout
  • Si une erreur de serveur 5xx est renvoyée lors de la reprise ou de la nouvelle tentative d'importation, utilisez une stratégie d'intervalle exponentiel entre les tentatives. Ces erreurs peuvent se produire quand un serveur est surchargé. L'intervalle exponentiel entre les tentatives peut aider à résoudre ce type de problème lors des pics de volumes de requêtes ou de trafic réseau.
  • Les autres types de requêtes ne doivent pas être traités par un intervalle exponentiel entre les tentatives, mais vous pouvez toujours essayer d'en relancer un certain nombre. Lorsque vous relancez ces requêtes, limitez le nombre de tentatives. Par exemple, votre code peut établir une limite de 10 tentatives ou moins avant de signaler une erreur.
  • Lorsque vous effectuez des importations avec reprise, traitez les erreurs 404 Not Found et 410 Gone en recommençant toute l'importation depuis le début.

Intervalle exponentiel entre les tentatives

L'intervalle exponentiel entre les tentatives est une stratégie standard en matière de traitement d'erreurs pour les applications réseau, selon laquelle le client relance périodiquement une requête ayant échoué sur une durée de plus en plus longue. Si un volume élevé de requêtes ou un trafic réseau important provoquent des erreurs sur le serveur, l'intervalle exponentiel entre les tentatives peut s'imposer comme une stratégie efficace pour traiter ces erreurs. À l'inverse, cette stratégie n'est pas pertinente pour traiter les erreurs sans rapport avec le volume réseau ou les temps de réponse, telles que les erreurs associées aux identifiants d'autorisation non valides ou aux fichiers introuvables.

Utilisé correctement, l'intervalle exponentiel entre les tentatives augmente l'efficacité de l'utilisation de la bande passante, réduit le nombre de requêtes nécessaires pour obtenir une réponse positive et optimise le débit des requêtes dans les environnements avec simultanéité.

Le fonctionnement de l'intervalle exponentiel simple entre les tentatives se présente comme suit :

  1. Vous envoyez une requête à l'API.
  2. Vous recevez une réponse HTTP 503, qui indique que vous devez relancer la requête.
  3. Vous patientez 1 seconde + "random_number_milliseconds", puis vous relancez la requête.
  4. Vous recevez une réponse HTTP 503, qui indique que vous devez relancer la requête.
  5. Vous patientez 2 secondes + "random_number_milliseconds", puis vous relancez la requête.
  6. Vous recevez une réponse HTTP 503, qui indique que vous devez relancer la requête.
  7. Vous patientez 4 secondes + "random_number_milliseconds", puis vous relancez la requête.
  8. Vous recevez une réponse HTTP 503, qui indique que vous devez relancer la requête.
  9. Vous patientez 8 secondes + "random_number_milliseconds", puis vous relancez la requête.
  10. Vous recevez une réponse HTTP 503, qui indique que vous devez relancer la requête.
  11. Vous patientez 16 secondes + "random_number_milliseconds", puis vous relancez la requête.
  12. Vous arrêtez, puis vous signalez ou consignez une erreur.

Dans le flux ci-dessus, "random_number_milliseconds" correspond à un nombre aléatoire de millisecondes inférieur ou égal à 1 000. Cette valeur est nécessaire, car l'introduction d'un petit délai aléatoire aide à répartir la charge de manière plus uniforme et à éviter la surcharge du serveur. La valeur de "random_number_milliseconds" doit être redéfinie après chaque temps d'attente.

Remarque : L'attente correspond toujours à (2 ^ n) + "random_number_milliseconds", où "n" est un entier augmentant de manière monotone défini initialement sur 0. L'entier "n" est augmenté de 1 pour chaque itération (chaque requête).

L'algorithme est configuré pour se terminer lorsque "n" vaut 5. Ce plafond empêche les clients d'effectuer des relances indéfiniment et entraîne un délai total d'environ 32 secondes avant qu'une requête ne soit considérée comme une "erreur non récupérable". Vous pouvez tout à fait définir un nombre maximal de tentatives plus élevé, surtout si une longue importation est en cours d'exécution. Veillez simplement à limiter le délai des nouvelles tentatives de manière raisonnable, par exemple à moins d'une minute.

Guides de bibliothèque cliente des API