Enviar e-mail
Um POST em /v1/messages com JSON. O corpo precisa de destinatário, assunto e pelo menos um de html ou text.
Dois caminhos para enviar
Para código que você escreve.
Devolve o id da mensagem na hora e aceita idempotência, duas coisas que o SMTP não tem.
Para software que não é seu e só fala SMTP.
Logto, Postfix, msmtp, sendmail, ou o backend de e-mail padrão do Laravel, do Django e do WordPress.
Os dois usam a mesma chave de API, respeitam os mesmos limites do plano e aparecem no mesmo painel, com a mesma linha do tempo de eventos. O que sai por SMTP vem marcado com via=smtp.
O caminho da mensagem
Quatro partes participam de um envio, e cada uma responde por um trecho. Quando uma mensagem não chega, a primeira pergunta é em qual faixa ela parou: o que você controla, o que nós controlamos, e o que nenhum dos dois controla.
Você
Até a chamada sair do seu servidor.
Publica o DNS
Os registros que provam o domínio e assinam a mensagem. Sem eles, o envio é recusado.
Monta a chamada
Destinatário, assunto e
htmloutext.Guarda a chave
Ela aparece uma vez. Perdida, cria-se outra.
JetSend
Da chamada até a AWS aceitar, e o registro do que voltar.
Valida e aceita
Confere a chave, o domínio e a lista de bloqueio. Devolve um
id.Entrega à AWS
Na região de São Paulo, com a reputação isolada por conta.
Registra o desfecho
Entregue, devolvida ou reclamada, no painel e no seu webhook.
AWS SES
Do aceite até o servidor do destinatário responder.
Faz a entrega
Conversa com o servidor do outro lado e aguarda a resposta dele.
Devolve o evento
Aceite, devolução ou reclamação, que é o que vira o seu registro.
Destinatário
Fora do alcance de todos os anteriores.
Aceita ou recusa
Caixa cheia, endereço inexistente e regra de spam própria decidem aqui.
Marca como spam
Vira reclamação, e é o evento mais caro para a reputação do seu domínio.
O caminho acima termina no destinatário. O que acontece depois, e como você fica sabendo, está em Webhooks e eventos.
Exemplo completo
curl -X POST https://api.jetsend.com.br/v1/messages \ -H "Authorization: Bearer $JETSEND_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "from": "faturas@suaempresa.com.br", "fromName": "Sua Empresa", "to": "cliente@exemplo.com", "replyTo": "financeiro@suaempresa.com.br", "subject": "Sua fatura de setembro", "html": "<p>Segue a fatura.</p>", "text": "Segue a fatura." }'Campos
| Campo | Tipo | Observação |
|---|---|---|
to | string | Obrigatório. Um endereço. |
subject | string | Obrigatório, até 998 caracteres. |
html / text | string | Pelo menos um dos dois. Pode mandar os dois. |
from | string | Precisa pertencer a um domínio verificado seu. Sem ele, usamos o remetente padrão da conta. |
fromName | string | Nome de exibição, até 120 caracteres. Não aceita quebra de linha, aspas, barra invertida nem < >. |
replyTo | string | Para onde vai a resposta, se for diferente do remetente. |
cc / bcc | array | Até 50 endereços em cada. |
headers | objeto | Cabeçalhos seus. Os reservados são recusados, ver abaixo. |
idempotencyKey | string | Até 255 caracteres. Ver abaixo. |
enableTracking | boolean | Ligado por padrão. false desliga abertura e clique nesta mensagem. |
scheduledAt | string | Data e hora ISO 8601 com fuso, até 30 dias à frente. O e-mail sai nessa hora, e não agora. Ver abaixo. |
templateId | string | Id de um template salvo no painel. Assunto e corpo saem dele, e aí html e text não vão. Ver abaixo. |
variables | objeto | Valores dos {{nome}} do template. Texto, número ou booleano. |
listUnsubscribe | boolean | Desligado por padrão. true põe o botão "Cancelar inscrição" do Gmail. Ver abaixo. |
Cabeçalhos reservados
headers não aceita From, Sender, Reply-To, To, Cc, Bcc, Subject, Date, Message-ID, Return-Path, DKIM-Signature nem Received. Cada um deles tem campo próprio, ou é assinatura que o provedor precisa controlar. A rota recusa em vez de ignorar em silêncio: cabeçalho aceito e descartado é pior, porque o envio parece ter funcionado.
Agendar o envio
Com scheduledAt, a API responde 202 com status: "scheduled" e guarda o e-mail até a hora marcada, com uma tolerância de até 30 segundos. Mande a hora com fuso: 2026-10-20T09:00:00-03:00 sai às 9h de Brasília. Sem fuso, a API recusa, para 9h não virar 6h.
{ "from": "contato@suaempresa.com.br", "to": "cliente@exemplo.com", "subject": "Sua fatura vence amanhã", "text": "...", "scheduledAt": "2026-10-20T09:00:00-03:00"}Remetente, template e cota são conferidos na hora do pedido, quando você ainda vê a recusa. Na hora de sair, o JetSend confere de novo se a conta está ativa e se o destinatário não entrou na lista de bloqueio nesse meio tempo. Se entrou, o e-mail fica failed e não sai.
Para desistir antes da hora:
curl -X POST https://api.jetsend.com.br/v1/messages/ID_DA_MENSAGEM/cancel \ -H "Authorization: Bearer $JETSEND_API_KEY"Se o e-mail já começou a sair, a resposta é 409: daí em diante não dá mais para segurar.
Enviar em lote
POST /v1/messages/batch recebe até 100 e-mails numa chamada, cada um com os mesmos campos do envio avulso, inclusive templateId e idempotencyKey:
{ "emails": [ { "from": "contato@suaempresa.com.br", "to": "ana@exemplo.com", "subject": "Seu pedido saiu", "text": "..." }, { "from": "contato@suaempresa.com.br", "to": "bruno@exemplo.com", "subject": "Seu pedido saiu", "text": "..." } ]}Cada item volta com o próprio status, na mesma ordem do pedido: um endereço bloqueado no meio não segura os outros. A resposta é 200 quando o lote foi processado, então confira recusados antes de dar o lote por enviado.
{ "data": [ { "index": 0, "status": 202, "message": { "id": "...", "status": "sent" } }, { "index": 1, "status": 422, "error": { "code": "recipient_suppressed", "message": "..." } } ], "aceitos": 1, "recusados": 1}O lote conta como um envio por e-mail na cota do plano e no limite por minuto. Se não couber inteiro, nada sai e a API responde 429, com restantes dizendo quantos ainda cabem. O corpo inteiro vai até 10 MB.
Enviar por template
Em Templates, no painel, você guarda assunto e corpo com variáveis no formato {{nome}}. O envio passa só o id e os valores:
{ "from": "contato@suaempresa.com.br", "to": "cliente@exemplo.com", "templateId": "0b6c9a52-7f1e-4d3a-9c8b-2a1e5f4d3c2b", "variables": { "nome": "Ana", "plano": "Pro" }}Faltou uma variável que o template usa? A API responde 422 com variaveis_faltando e a lista delas, em vez de mandar "Olá, !" para o cliente. No HTML o valor é escapado: um nome com < não vira código no e-mail. Mandar subject junto troca só o assunto do template.
Descadastro de um clique
Gmail e Yahoo exigem, de quem envia newsletter e aviso em volume, um jeito de sair da lista com um clique. Com "listUnsubscribe": true, o JetSend põe os cabeçalhos List-Unsubscribe e List-Unsubscribe-Post, e o Gmail mostra o botão "Cancelar inscrição" ao lado do remetente.
Quem clica entra na lista de bloqueio da sua conta, com origem list-unsubscribe, e os próximos envios para o endereço são recusados. Por isso o campo vem desligado: em e-mail de senha, de pagamento ou de nota fiscal, a pessoa precisa continuar recebendo.
O link vale para o destinatário de to, então a API recusa listUnsubscribe junto com cc ou bcc: quem estivesse em cópia tiraria outra pessoa da lista. Os dois cabeçalhos são da plataforma e não podem ir em headers.
Não mandar duas vezes
Se a sua chamada cair na rede depois que a API já aceitou, repetir a requisição manda o e-mail de novo. O campo idempotencyKey resolve: com a mesma chave, a segunda chamada devolve a mesma mensagem em vez de criar outra.
{ "to": "cliente@exemplo.com", "subject": "Pagamento confirmado", "html": "<p>Recebemos seu pagamento.</p>", "idempotencyKey": "pagamento-8421"}Use um identificador do seu domínio de negócio, como o id do pedido ou do pagamento, e não um valor aleatório novo a cada tentativa.
Listar o que saiu
curl "https://api.jetsend.com.br/v1/messages?limit=20" \ -H "Authorization: Bearer $JETSEND_API_KEY"Devolve as mensagens da conta, da mais recente para a mais antiga, com id, destinatário, assunto e status.
Para mandar de novo uma que já saiu, POST /v1/messages/ID/resend. É um envio novo, com outro id, e passa pelas mesmas checagens: quem entrou na lista de bloqueio desde o original não recebe, e o reenvio conta na cota.
Erros
| Código | O que houve |
|---|---|
400 | Corpo inválido. A resposta diz qual campo e por quê. |
401 | Chave ausente, malformada ou revogada. |
402 | Cota do plano estourada, ou assinatura em aberto. |
403 | Papel sem permissão de envio, ou chave de envio chamando outra rota. |
413 | html ou text acima do teto de bytes. |
422 | O from não pertence a um domínio verificado seu. |
503 | descadastro_indisponivel: o descadastro de um clique não está ligado no ambiente. O e-mail não sai sem o cabeçalho que você pediu. |
Para exercitar o seu tratamento de devolução e de reclamação sem sujar a sua reputação, use os apelidos de teste.
