Saltar para a documentação
PHP

Enviar um lote

`emails->sendBatch`: até 100 mensagens, resultados por item.

emails->sendBatch

send_batch.php
$invoices = [    ['number' => 'INV-1042', 'email' => '[email protected]'],    ['number' => 'INV-1043', 'email' => '[email protected]'],]; $messages = []; foreach ($invoices as $invoice) {    $messages[] = [        'from' => '[email protected]',        'to' => $invoice['email'],        'subject' => 'Invoice ' . $invoice['number'],        'text' => 'Your invoice is attached.',    ];} $result = $client->emails->sendBatch($messages, idempotencyKey: 'invoices:2026-09'); echo $result->sent, ' sent, ', $result->failed, ' failed', PHP_EOL; foreach ($result as $item) {    if ($item['status'] === 'error') {        error_log($item['index'] . ' ' . $item['error']['code'] . ' ' . $item['error']['message']);    } else {        echo $item['index'], ' ', $item['email']['id'], PHP_EOL;    }}

sendBatch aceita uma lista de arrays de mensagem, cada um com exatamente a forma do array que emails->send aceita, e devolve um OpenEmail\Result\BatchResult. O seu items contém um array por cada mensagem, pela mesma ordem, cada um ok com a sua mensagem ou error com o envelope com que essa mensagem teria sido recusada, e percorrer o resultado percorre-os. Nada é revertido, pelo que uma contagem failed acima de 0 é uma lista sobre a qual agir e não um motivo para reenviar o lote.

Uma só chave de idempotência cobre o lote e o servidor estende-a para cada item, por isso um lote repetido reproduz cada mensagem em vez de as reduzir à primeira. Envie a mesma lista pela mesma ordem quando o repetir: um item que mudou de lugar fica ligado à chave de outra posição e volta como um erro idempotency_key_reuse.

Uma mensagem recusada não lança exceção. Só um problema com o lote no seu conjunto lança: uma lista vazia, mais de 100 mensagens, mais de 10 com translate, uma falha de chave ou de âmbito, ou uma falha do servidor. Uma falha do servidor a meio chega depois de os itens anteriores terem saído, e o cliente repete-a com a mesma chave, o que reproduz esses itens em vez de os enviar duas vezes.

Os itens são enviados um a seguir ao outro dentro de um único pedido, por isso um lote grande de envios imediatos demora bastante mais do que um único send. Mantenha generoso o timeout: do cliente.

Parâmetros: emails->sendBatch

emailsarrayobrigatório
De 1 a 100 mensagens, enviadas como `{"emails": [...]}` e aceites uma de cada vez pela ordem indicada. Cada uma passa pelo mesmo tratamento que `emails->send`, por isso um destinatário único é envolvido, um `DateTimeInterface` torna-se um instante e os bytes dos anexos são codificados, e uma entrada que não seja um array lança `InvalidArgumentException` antes de qualquer envio. Uma lista vazia, mais de 100, ou mais de 10 mensagens com `translate` fazem recusar a chamada inteira com um `validation_error` em `emails`. A falta do âmbito `emails:send` e um `idempotencyKey:` mal formado também fazem recusar a chamada inteira, antes de ser enviada uma única mensagem.
idempotencyKeystring
Elimina duplicados do lote entre processos. O cliente anexa sempre uma chave acabada de gerar em cada chamada, pelo que as suas próprias repetições nunca enviam em duplicado, e o servidor estende a chave que receber para cada 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.
apiKeystring
Envia o lote com esta chave em vez da do cliente.

Cada mensagem em emails

fromstring or arrayobrigatório
O remetente, como endereço simples, `Name <addr@host>` ou um array com `email` e `name`. 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`.
tostring or arrayobrigató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.
ccstring or array
Por predefinição, nenhum, e conta para o mesmo total de 50 endereços que `to` e `bcc`.
bccstring or array
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.
replyTostring or array
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.
subjectstring
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.
htmlstring
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`.
textstring
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.
headersarray
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.
attachmentsarray
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 pela rede. Passe um stream de `fopen`, um `SplFileInfo` ou um stream PSR-7 e o cliente lê-o e codifica-o, ou uma string que já esteja em base64. Um array só com `fileId` refere um ficheiro que já está no espaço de trabalho e não conta para o limite inline.
threadIdstring
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.
draftIdstring
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.
templatearray
Renderizar um modelo guardado no servidor, por id (`tpl_…`) ou slug, com `version` a fixar uma revisão e `props` e `slots` a preenchê-lo. Resolvido uma vez, quando o item é aceite, e recusado em conjunto com `html` ou `text` e com `draftId`, já que cada um desses é uma segunda resposta ao que a mensagem contém.
scheduledAtDateTimeInterface or string
Um `DateTimeInterface`, um instante ISO 8601 ou uma duração como `PT1H`, pelo menos um segundo no futuro e no máximo 365 dias à frente. Uma string de data sem hora significa meia-noite UTC desse dia. Os itens são agendados de forma independente, pelo que um lote pode conter cem horas de envio diferentes.
cancellableForSecondsint
Uma janela para anular, em segundos, num envio imediato, de 0 a 900 e 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.
trackingarray
`opens` e `clicks`, cada um opcional e cada um a substituir a definição apenas para esta mensagem. Uma chave omitida segue o endereço a partir do qual a mensagem é enviada (ou o catch-all que o apanhou), em que o rastreio está inativo a menos que esse endereço o tenha ativado.
tagsarray
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:`, `broadcastId:` e pela janela de agendamento e nada mais, pelo que uma etiqueta é algo a ler numa mensagem que já tem e não uma forma de a encontrar.
translatearray
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: OpenEmail\Result\BatchResult

O resultado é só de leitura, IteratorAggregate sobre items e Countable, por isso foreach ($result as $item) percorre os itens e count($result) conta-os.

itemsarray
Um array por cada mensagem, 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 or null
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` cujo `status` é `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. É null apenas quando a resposta não trouxe contagem.
failedint or null
Quantos itens têm um `error`. Uma contagem acima de 0 é uma lista sobre a qual agir e não um motivo para reenviar o lote. As mensagens aceites já foram enviadas.

Cada item

indexint
A posição que a mensagem deste item ocupava na lista que enviou. Transmitida como chave e também pela ordem, para que o código que filtra ou ordena `items` consiga ainda saber que mensagem falhou.
statusstring
`ok` ou `error`. `ok` traz `email`, `error` traz `error`, e nenhum item traz ambos.
emailarray
A mensagem aceite, apenas num item `ok`, com a mesma forma que um envio individual devolve. O seu `replayed` é true quando a `Idempotency-Key` derivada correspondeu a um envio que já existia, por isso nada de novo foi enviado e esta é a mensagem original. Não inclui a chave `tracking`, porque o envolvimento é reportado mais tarde e não há nada a reportar no momento da aceitação.
errorarray
Porque é que esta mensagem foi recusada, apenas num item `error`. É o envelope de erro da API sem `docUrl` nem `requestId`: esses descrevem o pedido, e o pedido no seu conjunto foi bem-sucedido.

O erro de um item

typestring
A categoria em que 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`.
codestring
A falha específica: `from_address_forbidden`, `invalid_email_address`, `too_many_recipients`, `reserved_header`, `message_too_large`, `unknown_parameter`. É aberto e aditivo, por isso trate um código que não reconheça como o seu `type`. Aqui chama-se `code` porque este é o envelope descodificado, ao passo que uma exceção traz o mesmo valor em `errorCode`.
messagestring
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`.
paramstring
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`.