Python
Enviar um lote
`emails.send_batch`: até 100 mensagens, resultados por item.
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 contém uma entrada por cada elemento enviado, pela mesma ordem, cada uma ok com a sua mensagem ou error com o envelope com que essa mensagem teria sido recusada. Nada é revertido, pelo que failed > 0 é uma lista sobre a qual agir e não um motivo para reenviar o lote.
Uma única chave de idempotência cobre o lote e o servidor estende-a por item, pelo que um lote repetido reproduz todas as mensagens em vez de as reduzir à primeira.
Parâmetros: emails.send_batch
emailsSequence[EmailSend]obrigatório- De 1 a 100 mensagens, serializadas como `{ "emails": [...] }` e aceites uma de cada vez pela ordem indicada. Uma lista vazia, mais de 100 mensagens, ou mais de 10 itens com `translate` fazem recusar a chamada inteira com um `validation_error` em `emails`. O mesmo acontece com a falta do âmbito `emails:send` e com um `idempotency_key` mal formado, ambos antes de ser enviada uma única mensagem.
idempotency_keystr- Elimina duplicados do lote entre processos. O cliente anexa sempre uma chave acabada de gerar em cada chamada, pelo que as suas próprias novas tentativas nunca enviam em duplicado, e o servidor estende a chave que receber por item como `key/0`, `key/1` e assim por diante, separadas por uma barra, um carácter que a sua própria chave não pode conter, pelo que uma chave para cem mensagens não as pode reduzir à primeira.
emails[].fromRecipientInputobrigatório- O remetente, como endereço simples, `Name <addr@host>` ou um dicionário. Não existe remetente alternativo e a chave tem de ter permissão para este endereço; uma recusa faz falhar apenas esse item, como `permission_error` com o código `from_address_forbidden`.
emails[].toRecipientInput | list[RecipientInput]obrigatório- Pelo menos um destinatário, e um único é envolvido numa lista pelo cliente. No máximo 50 endereços em `to`, `cc` e `bcc` combinados, contados por mensagem e não em todo o lote.
emails[].ccRecipientInput | list[RecipientInput]- Por predefinição, nenhum, e conta para o mesmo total de 50 endereços que `to` e `bcc`.
emails[].bccRecipientInput | list[RecipientInput]- Por predefinição, nenhum, e conta para o mesmo total de 50 endereços. `Bcc` é um dos nomes que `headers` não pode definir, pelo que esta é a única forma de enviar uma cópia oculta. A forma de cabeçalho anularia o envelope por destinatário que mantém o endereço oculto.
emails[].replyToRecipientInput- Para onde vão as respostas. É aplicado depois de `headers`, pelo que substitui um `Reply-To` que também tenha definido aí em vez de acrescentar um segundo.
emails[].subjectstr- No máximo 998 caracteres, o limite de linha do RFC 5322, e a predefinição é uma string vazia. Um assunto vazio dá lugar ao do próprio modelo quando `template` fornece um.
emails[].htmlstr- A parte HTML, com no máximo um milhão de caracteres, e a parte que os destinatários veem quando ambos os corpos são fornecidos. É obrigatório um de `html`, `text`, `template` ou `draftId`, e um item sem nenhum deles falha com um `validation_error` em `html`.
emails[].textstr- A parte em texto simples, com no máximo um milhão de caracteres. Podem ser enviadas ambas, e cada transporte neste percurso constrói um corpo a partir de uma string, pelo que `html` prevalece quando existe.
emails[].headersdict[str, str]- Apenas `X-*`, `List-*`, Reply-To, Precedence, Auto-Submitted, Importance, Priority e Feedback-ID; tudo o que o transporte define por si próprio (From, To, Bcc, Subject, Message-ID, os cabeçalhos DKIM e ARC) é recusado como `reserved_header` em vez de ser descartado silenciosamente. Os valores têm no máximo 998 caracteres e não podem conter CR, LF nem NUL, porque uma segunda linha é um segundo cabeçalho.
emails[].attachmentslist[AttachmentInput]- No máximo 20 ficheiros por mensagem, com os ficheiros inline a totalizarem 5 MB depois de descodificados, contados por mensagem e não por lote. `content` segue em base64; passe bytes e o cliente codifica-os. Uma entrada `{'fileId': ...}` refere um ficheiro que já está no espaço de trabalho e não conta para o limite inline.
emails[].threadIdstr- Responder numa conversa existente, com no máximo 256 caracteres. O transporte escreve In-Reply-To e References a partir dele, e é isso que faz a resposta ficar na conversa e não ao lado dela.
emails[].draftIdstr- Enviar o conteúdo de um rascunho guardado com este envelope, com no máximo 256 caracteres. Os destinatários, o assunto e os cabeçalhos construídos aqui são o que é efetivamente enviado.
emails[].templateEmailSendTemplate- Renderizar um modelo guardado no servidor, por id (`tpl_…`) ou slug, com `version` a fixar uma revisão e `props`/`slots` a preenchê-lo. Resolvido uma vez, quando o item é aceite, e recusado em conjunto com `html`/`text` e com `draftId`, já que cada um desses é uma segunda resposta ao que a mensagem contém.
emails[].scheduledAtdatetime | str- Um `datetime`, um instante ISO-8601 ou uma duração como `PT1H`; pelo menos um segundo no futuro e no máximo 365 dias à frente. Os itens são agendados de forma independente, pelo que um lote pode conter cem horas de envio diferentes.
emails[].cancellableForSecondsint- Uma janela para anular, em segundos, num envio imediato: um inteiro de 0 a 900, com 0 por predefinição. Qualquer valor acima de 0 é recusado em conjunto com `scheduledAt` no mesmo item, já que uma mensagem agendada já pode ser cancelada até sair.
emails[].trackingTrackingRequest- `opens` e `clicks`, cada um opcional de forma independente e cada um a substituir a definição apenas para esta mensagem. Um interruptor omitido segue o endereço a partir do qual a mensagem é enviada (ou o catch-all que o apanhou), e está inativo a menos que esse endereço o tenha ativado.
emails[].tagsdict[str, str]- No máximo 10 etiquetas, com chaves de 1 a 64 caracteres de `A-Za-z0-9_-` e valores até 256. Devolvidas na mensagem e nunca interpretadas: `emails.list` filtra por `status`, `from_`, `broadcast_id`, `scheduled_from` e `scheduled_to` e nada mais, pelo que uma etiqueta é algo a ler numa mensagem que já tem e não uma forma de a encontrar.
emails[].translateSendTranslateOptions- Enviar este item noutra língua, resolvido no momento da aceitação para que as palavras aprovadas sejam as palavras que saem. No máximo 10 itens num lote podem incluí-lo: cada um gasta várias chamadas ao modelo e os itens são executados por ordem, pelo que um lote maior seria interrompido a meio do envio. Acima disso, a chamada inteira é recusada como `too_many_items` em `emails`, antes de qualquer envio.
Resposta: BatchResultResource
itemslist[BatchItemResource]- Uma entrada por cada mensagem enviada, pela ordem em que as enviou. Nada é revertido, pelo que isto é um registo do que aconteceu a cada mensagem e não um relatório sobre uma transação. A API responde 207 quer todas as mensagens tenham sido aceites, quer algumas, quer nenhuma, pelo que a chamada devolve o resultado em qualquer caso e é o `status` de cada item que deve orientar a lógica.
sentint- Quantos itens foram ACEITES, o que não é o mesmo que quantos saíram. Um item pode ser `ok` e ter ainda assim um `email.status` de `failed` ou `partial`, porque um transporte que recusa a mensagem depois de a linha existir é um resultado de entrega e não um pedido rejeitado.
failedint- Quantas entradas têm um `error`. `failed > 0` é uma lista sobre a qual agir e não um motivo para reenviar o lote. As mensagens aceites já foram enviadas.
items[].indexint- A posição que a mensagem desta entrada ocupava na lista que enviou. Transmitida como campo e também pela ordem, para que o código que filtra ou ordena `items` consiga ainda saber que elemento falhou.
items[].statusLiteral['ok', 'error']- O discriminante da união: `ok` inclui `email`, `error` inclui `error`, e nenhuma entrada inclui ambos.
items[].emailSentEmailResource- A mensagem aceite, apenas numa entrada `ok`, com a mesma forma que um envio individual devolve. Não inclui a chave `tracking`, porque o envolvimento é reportado mais tarde e não há nada a reportar no momento da aceitação.
items[].email.replayedbool- É true quando o `Idempotency-Key` derivado correspondeu a um envio que já existia, pelo que nada de novo foi enviado e esta é a mensagem original.
items[].errorBatchItemResourceErrorError- Porque é que esta mensagem foi recusada, apenas numa entrada `error`. É o envelope de erro da API sem `docUrl` nem `requestId`: esses descrevem o pedido, e o pedido no seu conjunto foi bem-sucedido.
items[].error.typestr- A categoria em que um cliente pode basear a lógica: `validation_error`, `permission_error`, `not_found_error`, `conflict_error` e as restantes. O conjunto está fixo e não vai crescer, ao contrário de `code`.
items[].error.codestr- A falha específica: `from_address_forbidden`, `invalid_email_address`, `too_many_recipients`, `reserved_header`, `message_too_large`, `unknown_parameter`. Aberto e cumulativo, por isso trate um código que não reconheça de acordo com o seu `type`.
items[].error.messagestr- Uma frase escrita para uma pessoa, que indica o valor problemático quando existe. Não é um identificador estável. Baseie a lógica em `code`.
items[].error.paramNotRequired[str]- O campo que foi recusado, como caminho com pontos dentro DESSA mensagem: `to.0`, `from`, `attachments`. Ausente quando a falha não se refere a nenhum campo, e nunca prefixado com a posição no lote, já que é para isso que serve `index`.