Aller à la documentation
Python

Envoyer un lot

`emails.send_batch` : jusqu'à 100 messages, un résultat par élément.

emails.send_batch

send_batch.py
import sys from openemail import openemailfrom openemail.types import EmailSend invoices = {'[email protected]': 'INV-4021', '[email protected]': 'INV-4022'} messages: list[EmailSend] = [    {'from': '[email protected]', 'to': to, 'subject': f'Invoice {number}', 'text': 'Attached.'}    for to, number in invoices.items()] result = openemail.emails.send_batch(messages) print(result['sent'], 'sent,', result['failed'], 'failed') for item in result['items']:    if item['status'] == 'error':        print(item['index'], item['error']['code'], item['error']['message'], file=sys.stderr)    else:        print(item['index'], item['email']['id'])

items contient une entrée par élément transmis, dans l'ordre, chacune soit ok avec son message, soit error avec l'enveloppe qui aurait servi à refuser ce message. Rien n'est annulé : failed > 0 est donc une liste sur laquelle agir, pas une raison de renvoyer le batch.

Une seule clé d'idempotence couvre le batch et le serveur l'étend par élément : un batch réessayé rejoue donc chaque message au lieu de les réduire tous au premier.

Paramètres : emails.send_batch

emailsSequence[EmailSend]obligatoire
De un à 100 messages, sérialisés en `{ "emails": [...] }` et acceptés un par un dans l'ordre donné. Une liste vide, plus de 100 éléments, ou plus de 10 éléments portant `translate` font refuser tout l'appel avec un `validation_error` sur `emails`. Il en va de même pour une portée `emails:send` manquante et un `idempotency_key` malformé, tous deux refusés avant qu'un seul message ne soit envoyé.
idempotency_keystr
Déduplique le batch entre processus. Le client attache de toute façon une clé fraîchement générée à chaque appel, si bien que ses propres retentatives n'envoient jamais deux fois, et le serveur étend la clé qu'il reçoit par élément en `key/0`, `key/1` et ainsi de suite, séparés par une barre oblique, un caractère que votre propre clé ne peut pas contenir : une seule clé portant sur cent messages ne peut donc pas les réduire tous au premier.
emails[].fromRecipientInputobligatoire
L'expéditeur, sous forme d'adresse nue, de `Name <addr@host>` ou d'un dictionnaire. Il n'y a pas d'expéditeur de repli et la clé doit être autorisée sur cette adresse ; un refus fait échouer ce seul élément, sous la forme d'un `permission_error` avec le code `from_address_forbidden`.
emails[].toRecipientInput | list[RecipientInput]obligatoire
Au moins un destinataire ; un destinataire seul est enveloppé dans une liste par le client. 50 adresses au maximum pour `to`, `cc` et `bcc` réunis, comptées par message et non sur l'ensemble du lot.
emails[].ccRecipientInput | list[RecipientInput]
Vide par défaut, et compte dans le même total de 50 adresses que `to` et `bcc`.
emails[].bccRecipientInput | list[RecipientInput]
Vide par défaut, et compte dans le même total de 50 adresses. `Bcc` fait partie des noms que `headers` ne peut pas définir : c'est donc le seul moyen de mettre en copie cachée. La forme en-tête annulerait l'enveloppe par destinataire qui garde l'adresse cachée.
emails[].replyToRecipientInput
Où vont les réponses. Appliqué après `headers`, il écrase donc un `Reply-To` que vous y auriez également défini au lieu d'en ajouter un deuxième.
emails[].subjectstr
998 caractères au maximum, la limite de ligne RFC 5322, et une chaîne vide par défaut. Un objet vide laisse la place à celui du template quand `template` en fournit un.
emails[].htmlstr
La partie HTML, un million de caractères au maximum, et celle que voient les destinataires quand les deux corps sont fournis. `html`, `text`, `template` ou `draftId` : l'un des quatre est obligatoire, et un élément qui n'en a aucun échoue avec un `validation_error` sur `html`.
emails[].textstr
La partie en texte brut, un million de caractères au maximum. Les deux peuvent être envoyées, et tout transport sur ce chemin construit un seul corps à partir d'une seule chaîne : `html` l'emporte donc quand il y en a un.
emails[].headersdict[str, str]
`X-*`, `List-*`, Reply-To, Precedence, Auto-Submitted, Importance, Priority et Feedback-ID uniquement ; tout ce que le transport définit lui-même (From, To, Bcc, Subject, Message-ID, les en-têtes DKIM et ARC) est refusé avec `reserved_header` plutôt qu'ignoré en silence. Les valeurs font au maximum 998 caractères et ne peuvent porter ni CR, ni LF, ni NUL, car une deuxième ligne est un deuxième en-tête.
emails[].attachmentslist[AttachmentInput]
20 fichiers au maximum par message, les fichiers inline totalisant 5 Mo une fois décodés, comptés par message et non par lot. `content` circule en base64 ; transmettez des octets et le client les encode. Une entrée `{'fileId': ...}` désigne un fichier déjà présent dans l'espace de travail et n'est pas décomptée du plafond inline.
emails[].threadIdstr
Répond dans un thread existant, 256 caractères au maximum. Le transport en déduit In-Reply-To et References, ce qui fait atterrir la réponse dans la conversation plutôt qu'à côté.
emails[].draftIdstr
Envoie le contenu d'un brouillon enregistré sous cette enveloppe, 256 caractères au maximum. Ce sont les destinataires, l'objet et les en-têtes construits ici qui partent sur le réseau.
emails[].templateEmailSendTemplate
Rend un template stocké côté serveur, par id (`tpl_…`) ou par slug, `version` épinglant une révision et `props`/`slots` le remplissant. Résolu une seule fois, au moment où l'élément est accepté, et refusé en présence de `html`/`text` comme de `draftId`, puisque chacun d'eux est une deuxième réponse à la question du contenu du message.
emails[].scheduledAtdatetime | str
Un `datetime`, un instant ISO-8601, ou une durée comme `PT1H` ; au moins une seconde dans le futur et au plus 365 jours à l'avance. Les éléments se planifient indépendamment : un même batch peut donc contenir cent heures d'envoi différentes.
emails[].cancellableForSecondsint
Une fenêtre d'annulation en secondes sur un envoi immédiat, un integer de 0 à 900, 0 par défaut. Toute valeur supérieure à 0 est refusée en présence de `scheduledAt` sur le même élément, puisqu'un message planifié est déjà annulable jusqu'à son départ.
emails[].trackingTrackingRequest
`opens` et `clicks`, chacun optionnel indépendamment et chacun surchargeant le réglage pour ce seul message. Un interrupteur omis suit l'adresse depuis laquelle le message part (ou le catch-all qui l'a attrapée), qui est désactivé sauf si cette adresse l'a activé.
emails[].tagsdict[str, str]
10 libellés au maximum, des clés de 1 à 64 caractères pris dans `A-Za-z0-9_-` et des valeurs jusqu'à 256. Renvoyés tels quels sur le message et jamais interprétés : `emails.list` filtre sur `status`, `from_`, `broadcast_id`, `scheduled_from` et `scheduled_to` et rien d'autre, un tag est donc une chose à lire sur un message que vous détenez déjà, pas un moyen de le retrouver.
emails[].translateSendTranslateOptions
Envoie cet élément dans une autre langue, résolu au moment de l'acceptation pour que les mots approuvés soient les mots qui partent. 10 éléments au maximum peuvent le porter dans un même batch : chacun consomme plusieurs appels au modèle et les éléments s'exécutent dans l'ordre, si bien qu'un batch plus grand serait interrompu en plein envoi. Au-delà, tout l'appel est refusé avec `too_many_items` sur `emails`, avant que quoi que ce soit ne soit envoyé.

Réponse : BatchResultResource

itemslist[BatchItemResource]
Une entrée par élément transmis, dans l'ordre où vous les avez envoyés. Rien n'est annulé : c'est donc le relevé de ce qui est arrivé à chaque message, pas le compte rendu d'une transaction. L'API répond 207 que tous les messages aient été acceptés, quelques-uns seulement ou aucun : l'appel retourne donc dans tous les cas, et c'est le `status` de chaque élément qui doit guider le code.
sentint
Combien d'éléments ont été ACCEPTÉS, ce qui n'est pas la même chose que combien sont partis. Un élément peut être `ok` et porter malgré tout un `email.status` `failed` ou `partial`, car un transport qui refuse le message une fois la ligne créée est un résultat de distribution, pas une requête rejetée.
failedint
Combien d'entrées portent un `error`. `failed > 0` est une liste sur laquelle agir, pas une raison de renvoyer le batch. Les messages acceptés sont déjà partis.
items[].indexint
La position qu'occupait le message de cette entrée dans la liste que vous avez envoyée. Portée comme champ en plus de l'ordre, pour qu'un code qui filtre ou trie `items` puisse toujours dire quel élément d'entrée a échoué.
items[].statusLiteral['ok', 'error']
Le discriminant de l'union : `ok` porte `email`, `error` porte `error`, et aucune entrée ne porte les deux.
items[].emailSentEmailResource
Le message accepté, uniquement sur une entrée `ok`, dans la même forme que celle renvoyée par un envoi unitaire. Il ne porte pas de clé `tracking`, car l'engagement est rapporté plus tard et il n'y a rien à rapporter au moment de l'acceptation.
items[].email.replayedbool
Vrai quand l'`Idempotency-Key` dérivée correspondait à un envoi qui existait déjà : rien de nouveau n'a été envoyé et voici le message d'origine.
items[].errorBatchItemResourceErrorError
Pourquoi ce message précis a été refusé, uniquement sur une entrée `error`. C'est l'enveloppe d'erreur de l'API, moins `docUrl` et `requestId` : ceux-ci décrivent la requête, et la requête dans son ensemble a réussi.
items[].error.typestr
La catégorie sur laquelle un client peut se brancher : `validation_error`, `permission_error`, `not_found_error`, `conflict_error` et les autres. L'ensemble est figé et ne s'agrandira pas, contrairement à `code`.
items[].error.codestr
L'échec précis : `from_address_forbidden`, `invalid_email_address`, `too_many_recipients`, `reserved_header`, `message_too_large`, `unknown_parameter`. Ouvert et additif : traitez donc un code que vous ne reconnaissez pas comme son `type`.
items[].error.messagestr
Une phrase écrite pour un humain, qui nomme la valeur fautive quand il y en a une. Ce n'est pas un identifiant stable. Branchez-vous sur `code`.
items[].error.paramNotRequired[str]
Le champ qui a été refusé, sous forme de chemin pointé à l'intérieur de CE message : `to.0`, `from`, `attachments`. Absent quand l'échec ne nomme aucun champ, et jamais préfixé par la position dans le batch, ce à quoi sert `index`.

Référence