Python
Envoyer un lot
`emails.send_batch` : jusqu'à 100 messages, un résultat par élément.
emails.send_batch
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`.