Pular para o conteúdo

Campanhas

Uma campanha (broadcast) envia uma mensagem a todos os contatos inscritos de um público. O SpacePost a divide em um e-mail personalizado por contato, adiciona os links de cancelamento de inscrição e os cabeçalhos List-Unsubscribe, ignora os endereços suprimidos e acompanha tudo como qualquer outro e-mail.

Status Significado
draft Criada, editável, não enviada.
queued send foi chamado; aguardando o horário de início (imediatamente ou scheduled_at).
sending Sendo distribuída aos contatos.
sent Todos os e-mails foram aceitos para entrega. sent_at está definido.
failed A distribuição foi interrompida, por exemplo porque uma cota foi atingida ou a equipe foi pausada.
canceled Cancelada antes do envio.
broadcast.ts
import { SpacePost } from "@spacepost/node";
const spacepost = new SpacePost(process.env.SPACEPOST_API_KEY);
const audienceId = "0192e1c4-0000-7000-8000-0000000000a1";
// 1. Create a draft
const { data: draft, error } = await spacepost.broadcasts.create({
audienceId,
name: "October newsletter",
from: "Acme <news@acme.com>",
replyTo: "support@acme.com",
subject: "What's new at Acme, {{{FIRST_NAME|friend}}}",
previewText: "Three things we shipped this month",
html: `
<h1>Hi {{{FIRST_NAME|there}}},</h1>
<p>Here is what is new.</p>
<p><a href="{{{SPACEPOST_UNSUBSCRIBE_URL}}}">Unsubscribe</a></p>
`,
});
if (error) throw new Error(error.message);
// 2. Send it now, or schedule it
const { error: sendError } = await spacepost.broadcasts.send(draft.id, { scheduledAt: "in 1 hour" });
if (sendError) throw new Error(sendError.message);
// 3. Check progress
const { data: broadcast } = await spacepost.broadcasts.get(draft.id);
console.log(broadcast?.status); // "queued" | "sending" | "sent" | "failed"

POST /broadcasts cria um rascunho e retorna { "id": "..." }.

audience_idstring (uuid)obrigatório

O público para o qual enviar.

fromstringobrigatório

Remetente em um domínio verificado.

subjectstringobrigatório

De 1 a 998 caracteres. Há suporte a placeholders.

htmlstringopcional

Corpo em HTML. Informe html, text ou ambos antes de enviar.

textstringopcional

Corpo em texto simples.

reply_tostring | string[]opcional

Até 50 endereços.

preview_textstringopcional

Até 200 caracteres. Exibido depois do assunto nas caixas de entrada; inserido como um preheader oculto.

namestringopcional

Até 100 caracteres. Um rótulo interno.

PATCH /broadcasts/{id} aceita os mesmos campos (todos opcionais) e funciona somente em rascunhos. DELETE /broadcasts/{id} funciona em rascunhos e em campanhas agendadas para o futuro.

Janela do terminal
# now
curl -X POST https://api.spacepost.dev/broadcasts/$ID/send -H "Authorization: Bearer $SPACEPOST_API_KEY"
# scheduled (ISO or natural language, up to 30 days ahead)
curl -X POST https://api.spacepost.dev/broadcasts/$ID/send \
-H "Authorization: Bearer $SPACEPOST_API_KEY" -H "Content-Type: application/json" \
-d '{ "scheduled_at": "2026-11-01T09:00:00Z" }'

Só podem ser enviados rascunhos com corpo html ou text, a partir de um domínio verificado. A resposta é { "id": "..." }.

Antes de enviar, GET /broadcasts/{id}/readiness retorna uma checklist de entregabilidade (o painel mostra a mesma lista no editor). É uma extensão do SpacePost e não faz parte da API do Resend.

{ "ready": true, "checks": [{ "id": "html_size", "level": "warn", "title": "Gmail will clip this message", "detail": "..." }] }
Verificação Nível Quando
sender_domain error O domínio de from está ausente ou não está verificado.
dmarc warn Não há registro v=DMARC1 em _dmarc.<domain>, ou a consulta falhou. p=none passa.
subject error / warn Error quando vazio. Warning para TUDO EM MAIÚSCULAS, !!! ou $$$, ou mais de 90 caracteres.
html_size warn HTML acima de 102 KB, que o Gmail corta.
images warn Apenas imagens, ou quatro ou mais imagens com pouco texto.
shorteners warn Links por bit.ly, tinyurl.com, t.co e similares.
spam_phrases warn Expressões típicas de spam no assunto ou no corpo.
unsubscribe ok Um rodapé de cancelamento de inscrição é adicionado automaticamente quando o corpo não tem o placeholder, então isso nunca bloqueia.
audience error Não há contatos inscritos.
role_addresses warn Mais de 20% dos contatos são endereços como info@ ou admin@.

ready é false quando qualquer verificação tem o nível error. O envio então falha com um validation_error (422) que lista o que corrigir. Os warnings nunca bloqueiam um envio.

Os e-mails de campanha também levam os cabeçalhos List-Id e Feedback-ID (<broadcast id>:<team id>:broadcast:spacepost) para que o Gmail Postmaster Tools possa atribuir as reclamações a uma campanha. Os e-mails transacionais não os levam.

  • A personalização é aplicada a subject, html e text (Personalização).
  • Cancelamento de inscrição: se o seu corpo não tiver o placeholder {{{SPACEPOST_UNSUBSCRIBE_URL}}} / {{{RESEND_UNSUBSCRIBE_URL}}}, um rodapé de cancelamento de inscrição é anexado automaticamente. Os cabeçalhos List-Unsubscribe e List-Unsubscribe-Post: List-Unsubscribe=One-Click são sempre adicionados.
  • O Texto de prévia vira um preheader oculto no topo do HTML.
  • Os contatos que cancelaram a inscrição e os endereços da sua lista de supressão são ignorados.

Cada destinatário conta como um e-mail na cota do seu plano, e o sandbox de 100 por dia vale para contas novas. Se a cota se esgotar durante o envio, a campanha termina como failed; os e-mails já criados continuam sendo entregues. A distribuição pode ser retomada se um worker for reiniciado.

Cada e-mail de campanha é um e-mail normal: aparece em GET /emails, leva broadcast_id nos payloads de webhook e pode ser rejeitado ou aberto.