Sign inGet Started

Envio agendado

Defina scheduled_at para reter uma mensagem até um horário específico. Quando esse horário chega, a mensagem entra no ciclo de vida normal de entrega e produz os mesmos eventos de um envio imediato. Sua aplicação não precisa rodar seu próprio agendador.

Agendando um envio

Adicione um timestamp scheduled_at a um envio POST /v1/email/messages normal. Nada mais no payload muda.

const msg = await bird.email.send({
  from: "news@yourdomain.com",
  to: ["delivered@messagebird.dev"],
  subject: "Your weekly digest",
  html: '<p>Here is what happened this week...</p><p><a href="{{ bird.unsubscribe_url }}">Unsubscribe</a></p>',
  category: "marketing",
  scheduled_at: "2027-01-15T09:00:00Z",
});
console.log(msg.id, msg.status); // "em_…", "accepted"

A chamada retorna 202 Accepted com o ID da mensagem prefixado por em_ e status: accepted imediatamente. É o mesmo objeto de mensagem que um envio imediato retorna, mais scheduled_at ecoado em UTC, para que você confirme o horário de envio sem uma leitura adicional. A aceitação é síncrona; a entrega é adiada. Omita scheduled_at da solicitação e a mensagem sai na hora, e a resposta não traz a chave scheduled_at.

As leituras são atualizadas de forma assíncrona. Uma mensagem que você acabou de agendar pode inicialmente retornar 404 em Obter uma mensagem e não aparecer na lista de mensagens nem no painel. Conteúdo volumoso ou anexos podem prolongar essa espera enquanto os armazenamos. Guarde o ID e scheduled_at da resposta 202 e repita as leituras com esse ID, deixando um intervalo entre as tentativas. Você também pode cancelar com esse ID antes de a mensagem aparecer.

Quando uma mensagem aparece enquanto ainda aguarda o envio, as leituras mostram status: scheduled e seu scheduled_at:

Exemplo de código
{
  "id": "em_01ky7q24hafjgvzfg02v3m177p",
  "status": "scheduled",
  "scheduled_at": "2027-01-15T09:00:00Z",
  "category": "marketing"
}

Quando o horário chega, liberamos a mensagem e seu status avança pelos estados habituais (accepted, depois processed, depois delivered, e assim por diante). scheduled_at permanece definido depois disso, para que você sempre veja para quando a mensagem foi agendada.

O envio de uma mensagem pode começar antes que as leituras sejam atualizadas, então você pode ver primeiro um status posterior. Não há um prazo fixo que garanta que a mensagem apareça em uma leitura.

O agendamento consome uma unidade da cota de e-mails agendados da sua organização no período de faturamento. Exceder essa cota é rejeitado com um 422 (E10003).

Agende conteúdo inline ou um modelo

Use scheduled_at com conteúdo inline ou um modelo salvo, montado como um envio com modelo imediato. Fixamos a versão publicada, o idioma selecionado e os valores dos parâmetros ao aceitar a solicitação e enviamos essa versão no horário agendado. Publicar uma versão mais recente não altera a seleção. Se o modelo for excluído antes do horário agendado, a mensagem será rejeitada sem ser enviada.

Uma mensagem da categoria marketing recebe um link de cancelamento de assinatura como um pequeno rodapé no final do corpo. Para posicionar o link você mesmo, coloque {{ bird.unsubscribe_url }} em cada corpo fornecido ou, em um envio com modelo, nos corpos do modelo.

Um item de batch aceita scheduled_at nos mesmos termos, então um batch pode misturar mensagens agendadas e imediatas. Cada item agendado consome sua própria unidade da cota, e o batch inteiro é rejeitado se o horário de qualquer item estiver fora do intervalo permitido. Cada item agendado traz seu próprio scheduled_at na resposta do batch, e um item de envio imediato não tem a chave scheduled_at; a referência do batch mostra ambos em uma mesma resposta.

Um payload de envio imediato ainda pode ser grande demais para agendar. Se o corpo, a lista de destinatários ou os metadados excederem o limite de agendamento, API retorna 422. Reduza esses campos ou envie a mensagem imediatamente.

Escolhendo o horário de envio

scheduled_at é um timestamp absoluto RFC 3339. Duas regras o governam:

  • Precisa estar entre 30 segundos e 30 dias no futuro. Menos de 30 segundos ou mais de 30 dias é rejeitado com um 422. O limite mínimo impede que um agendamento dispute com um envio imediato. Trinta dias é o horizonte máximo pelo qual retemos uma mensagem.
  • Forneça um instante exato. Inclua um Z UTC (2027-01-15T09:00:00Z) ou um offset explícito (2026-07-30T09:00:00-04:00, o mesmo instante que 13:00:00Z). Comparamos o instante com o horário atual e nunca interpretamos um horário local sem offset nem aplicamos o fuso horário do destinatário. Para enviar às 9h no horário local de cada destinatário, calcule esses instantes você mesmo e agende um envio por fuso horário.

Expressões relativas como "in 2 hours" não são aceitas. Envie um timestamp resolvido.

Listando mensagens agendadas

Filtre a lista de mensagens por status para ver as mensagens que já apareceram e ainda aguardam o envio. Um agendamento recém-aceito pode não aparecer enquanto o conteúdo é carregado ou as leituras são atualizadas:

for await (const message of bird.email.list({ status: "scheduled" })) {
  console.log(message.id, message.scheduled_at);
}

status=canceled lista as que você cancelou antes do envio. Quando uma mensagem agendada dispara, ela entra no pipeline e aparece com os status de entrega, igual a qualquer outro envio. O log de e-mails do dashboard oferece os mesmos filtros Scheduled e Canceled.

Cancelando um envio agendado

Cancele uma mensagem a qualquer momento antes de ela começar a ser enviada com POST /v1/email/messages/{message_id}/cancel:

await bird.email.cancel("em_abc123");

Um cancelamento bem-sucedido retorna 204 No Content. O status da mensagem passa a ser canceled, ela nunca é enviada, e um webhook email.canceled dispara. Quatro coisas importantes:

  • Só uma mensagem ainda agendada pode ser cancelada. Uma mensagem que já começou a ser enviada, já foi enviada ou já foi cancelada retorna 409:

    Exemplo de código
    {
      "error": {
        "type": "conflict_error",
        "code": "E10005",
        "name": "EmailNotCancelable",
        "message": "This message cannot be canceled.",
        "remediation": "Only a scheduled message that has not started sending can be canceled. Once sending begins there is no way to pull it back."
      }
    }

    Quando o horário de envio chega, um cancelamento também pode perder a corrida para o próprio envio e retornar 409 pelo mesmo motivo.

  • Você pode cancelar enquanto o conteúdo ainda está sendo carregado. Um envio agendado com anexos ou um corpo de mensagem grande pode ainda estar armazenando conteúdo após a resposta 202. Um cancelamento bem-sucedido mantém o envio cancelado, mesmo que o carregamento termine mais tarde.

  • Cancelar não devolve a cota de e-mails agendados. A unidade consumida no momento do agendamento permanece consumida, e é isso que impede que um loop de agendar e cancelar contorne a cota. Sua cota de envio regular não é afetada, porque ela só é cobrada quando a mensagem é realmente enviada.

  • O cancelamento pode ser repetido com segurança usando um Idempotency-Key, como qualquer outra escrita.

Para mover um envio agendado para outro horário, cancele-o e envie uma nova solicitação com o novo scheduled_at. Você recebe um novo ID em_.

O que acontece no horário de envio

O agendamento muda apenas quando a mensagem é liberada. Sua construção e governança permanecem as mesmas. Anexos, categoria, tags e metadados se comportam exatamente como em um envio imediato e são ecoados nos eventos de webhook da mesma forma. Cinco verificações se dividem entre os dois momentos:

  • Validação de payload e domínio acontece na hora. Um envio agendado malformado falha na chamada API com um 422, então você descobre agora e não às 9h.
  • O domínio do remetente é verificado novamente no horário de envio. Se o domínio from não estiver mais verificado quando o horário agendado chegar, a mensagem não é enviada. Seus destinatários retornam como rejected com um motivo, em vez de receberem e-mail de um domínio não verificado. Mantenha o domínio verificado durante toda a janela.
  • Sua cota de envio é cobrada no horário de envio. A cota de envio regular é consumida quando a mensagem dispara. O agendamento não altera a cota. Se a cota estiver esgotada no horário de envio, os destinatários são rejeitados.
  • A supressão é avaliada no horário de envio, com base na sua lista de supressão como ela estiver naquele momento, então alguém que cancelar a inscrição entre o agendamento e o envio ainda será respeitado.
  • Um modelo salvo precisa continuar existindo no horário de envio. Se você excluir o modelo depois de agendar, a mensagem não é enviada. Seus destinatários retornam como rejected com generation_failure.

Erros

StatusCódigoQuando
422E10003A cota de e-mails agendados da sua organização para o período de faturamento foi esgotada
422scheduled_at está a menos de 30 segundos ou a mais de 30 dias
422O payload é grande demais para estacionar; reduza o corpo, os destinatários ou os metadados, ou envie agora
409E10005A mensagem não pode mais ser cancelada: já começou a ser enviada, já foi enviada ou já foi cancelada
404A leitura da mensagem ainda não reflete a aceitação, ou não existe mensagem com esse ID neste espaço de trabalho

Webhooks

Dois eventos são específicos do agendamento, além dos eventos de entrega habituais:

  • email.scheduled informa sobre uma mensagem que aguarda o horário futuro definido em scheduled_at. Nos envios com modelo, a versão selecionada é carregada novamente e seu conteúdo é preparado no momento do envio. Esse evento pode chegar antes que esse trabalho seja concluído.
  • email.canceled dispara quando uma mensagem agendada é cancelada antes do envio.

Quando a mensagem dispara, a cadeia normal de email.accepted segue sem alterações.

Os eventos de agendamento são publicados de forma assíncrona. Uma mensagem pode sair do status agendado antes que email.scheduled seja publicado. Receber um webhook não significa que os endpoints de leitura já mostrem esse estado.

Próximos passos

Continue com a documentação, guias e exemplos sobre este tópico.