Enviar um lote
`emails->sendBatch`: até 100 mensagens, resultados por item.
emails->sendBatch
$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`.