A API do e-mail corporativo Asender: envio transacional assinado por DKIM, gestão de domínios e caixas, e a superfície de leitura/escrita do webmail (mensagens, rascunhos, contatos, assinatura). É um sistema à parte, com endereço próprio — o e-mail fora do ar é o e-mail fora do ar, e não arrasta as outras ferramentas.
Base URL:https://api.mail.asender.net
Autenticação: API key (Authorization: Bearer sk_…)
Formato: JSON (application/json; charset=utf-8)
Envelope de erro desta API:{ "error", "message" }. A Platform API (api.asender.net) usa outro: { "Error": { "Type", "Code", "Message", "Details" }, "RequestId" }. Não use o mesmo parser nas duas (Convenções).
Código de verificação (2FA/OTP) ou e-mail transacional de qualquer endereço de um domínio verificado? Use POST https://api.asender.net/v1/emails/send (Platform API, escopo email:send): ele aceita qualquer remetente de um domínio verificado, sem criar caixa. Esta API (POST /v1/emails) é para enviar a partir de uma caixa corporativa que já existe: from tem de ser uma caixa, não só um domínio verificado. O resto desta página é para quem envia dessas caixas, administra domínios e caixas ou constrói um cliente de e-mail sobre a plataforma.
Autenticação
Toda rota (fora das probes de saúde) exige uma API key da conta. A chave é uma credencial de máquina: o tenant_id é resolvido da chave, nunca de um campo do corpo ou da URL, e cada rota exige um escopo da chave (abaixo).
Só Authorization: Bearer é aceito: X-Api-Key e ?api_key= foram removidos (2026-10-07) e, sozinhos, dão 401.
Como obter uma chave. As API keys são emitidas pela Plataforma, não pela Mail API. Crie uma em POST https://api.asender.net/api/tenants/{id}/api-keys (ver a Platform API) ou pela tela de API keys do painel. Use sk_test_… fora de produção e sk_live_… em produção — a chave test é barrada pelos guardas de efeito externo (piso 18).
A chave só alcança as rotas abaixo, cada uma com o escopo indicado; chave sem escopos, full_access, send_only ou emails:* não concede nada. Falta de escopo devolve 403, nomeando o escopo exigido:
GET /mailboxes/{id}/messages, GET /mailboxes/{id}/messages/{msgId}, …/raw, …/attachments/{attId}, GET /mailboxes/{id}/threads/{threadId}
mail:admin
administração de domínios e caixas da própria conta: GET /orgs, POST/GET /orgs/{orgID}/domains, GET /domains/{id}/dns, POST /domains/{id}/verify, POST/GET /domains/{id}/mailboxes, PUT /domains/{id}/catchall, PUT /domains/{id}/autocreate, PUT /mailboxes/{id}/tipo. Não lê mensagens (isso é email:read) nem envia (email:send)
Qualquer outra rota desta API (Cloudflare, contas de caixa, concessões, filtros, rascunhos, contatos…) é plano de controle, feito pela sessão do painel, e responde 403 a uma API key. Emita a chave com os escopos mínimos da integração (o catálogo completo está na Platform API).
Envio transacional — POST /v1/emails
O coração da API. Envia de uma caixa existente da conta (em domínio verificado), assina com o DKIM do domínio e grava em Enviados.
curl -X POST 'https://api.mail.asender.net/v1/emails' \
-H 'Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxx' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: 8f7c1e2a-6b3d-4a1e-9c2f-0d5e7a1b2c3d' \
-d '{
"from": "joana@empresa.com.br",
"to": ["cliente@exemplo.test"],
"subject": "Proposta comercial",
"text": "Olá, segue a proposta que conversamos. Qualquer dúvida, é só responder."
}'
Resposta 202:
{ "message_id": "0b9c…", "status": "sent" }
Regras que valem a pena saber antes de integrar:
from tem de ser uma CAIXA que existe na conta da chave. Domínio verificado não basta: auth@empresa.com.br só envia depois que a caixa auth for criada no domínio empresa.com.br daquela conta (ver Antes do primeiro envio). Caixa inexistente — ou de outra conta — responde 422CaixaRemetenteInexistente com a dica de usar POST https://api.asender.net/v1/emails/send para remetentes de domínio (a resposta é a mesma nos dois casos, para não revelar caixa de outro tenant).
Idempotência. Repita a mesma Idempotency-Key para tornar seguro o retry de uma resposta que você não recebeu: o replay volta 200 com "idempotent_replay": true e nada é reenviado.
Anti-injeção de cabeçalho. Endereços com CR/LF são recusados na borda (400) — eles virariam cabeçalhos forjados num e-mail assinado.
Anexos vão em attachments[] como base64 (filename + content).
Antes do primeiro envio: crie a caixa remetente
O envio exige duas coisas na mesma conta da API key:
Domínio verificado (MX, SPF, DKIM e DMARC) — pela tela Domínios do e-mail ou por POST /orgs/{orgID}/domains + verificação.
A caixa do endereço from criada nesse domínio — um endereço só de envio (no-reply@, auth@, notify@) também é uma caixa.
Pela tela: mail.asender.net → Domínios → (o domínio) → Nova caixa.
Pela API, com uma chave que tenha o escopo mail:admin (administrar domínios e caixas de e-mail; emita-a na tela de API keys) — e email:send para o envio em si. Sem mail:admin a criação responde 403InsufficientScope nomeando mail:admin, mesmo com email:send; mail:admin sozinho não envia nem lê mensagens:
# 1) a organização de e-mail da conta
curl -s 'https://api.mail.asender.net/orgs' -H 'Authorization: Bearer sk_live_…'
# → {"orgs":[{"id":"<orgID>", …}]}
# 2) o id do domínio
curl -s 'https://api.mail.asender.net/orgs/<orgID>/domains' -H 'Authorization: Bearer sk_live_…'
# → {"domains":[{"id":"<domainID>","domain":"empresa.com.br","active":true, …}]}
# 3) uma caixa por remetente
curl -s -X POST 'https://api.mail.asender.net/domains/<domainID>/mailboxes' \
-H 'Authorization: Bearer sk_live_…' -H 'Content-Type: application/json' \
-d '{"local_part":"no-reply","display_name":"Empresa"}'
# → 201 com a caixa criada
Criar a caixa é idempotente do ponto de vista do envio: depois de existir, todo POST /v1/emails com aquele from passa. A API key de outra conta não enxerga o domínio (404) — gere a chave na conta onde o domínio está.
Quota do plano (429)
Cada destinatário em to/cc/bcc é um disparo e consome a quota do plano. Ao estourar o teto, a resposta é 429 e os cabeçalhos dizem qual janela barrou e quando ela reabre:
header
significado
X-Quota-Limit
teto do plano na janela que barrou
X-Quota-Used
disparos já consumidos
X-Quota-Remaining
disparos restantes
X-Quota-Escala
dia ou mes — qual janela barrou (o corporativo tem as duas)
Retry-After
segundos até a janela reabrir
{ "error": "QuotaExceeded", "message": "limite MENSAL do plano atingido — suba de plano ou compre créditos para seguir enviando neste ciclo." }
Nota de disponibilidade (fail-open deliberado). Se o contador de quota estiver indisponível no momento do envio, o e-mail passa (registra em log e segue). Um provedor de OTP não pode parar de entregar código de login porque o medidor de cobrança piscou. A autenticação continua fail-closed — a chave já foi validada antes de o envio começar.
Não-produção nunca entrega de verdade (piso 18)
Fora de prd, um destinatário fora do domínio de teste faz o envio falhar (502) por construção — não por lembrança. Use @exemplo.test (ou os TLDs reservados .test/.invalid/.example) em fixtures e testes. Nunca use @gmail.com, o domínio de um cliente ou um e-mail de pessoa real: bounce em massa queima o IP e o domínio e derruba o transacional de produção — inclusive o OTP de login.
Erros
Toda falha desta API usa o mesmo envelope ({ "error", "message" }; a Platform API usa { "Error": {…}, "RequestId" }):
{ "error": "ValidationError", "message": "campo 'to' é obrigatório." }
código HTTP
error típico
quando
400
ValidationError
corpo inválido, from/to ausentes, injeção de cabeçalho, anexo inválido
401
AuthorizationError
API key ausente ou inválida
403
InsufficientScope
a chave não tem o escopo da rota (ex.: POST /v1/emails sem email:send), não tem escopo algum, ou a rota não é de API key
404
NotFound
recurso fora do escopo da chave (não revela existência alheia)
422
CaixaRemetenteInexistente
POST /v1/emails com from que não é uma caixa da conta (para remetente de domínio verificado use POST https://api.asender.net/v1/emails/send)
429
QuotaExceeded
teto de disparos do plano (ver cabeçalhos X-Quota-*)
502
SendFailed
entrega recusada (piso 18) ou falha no relay; a quota é estornada
503
InternalError
envio não configurado / backend de auth indisponível
O corpo de requisição é lido com contrato estrito: campo desconhecido é 400, não é ignorado em silêncio; o limite é 1 MiB.
Paginação
Coleções longas (mensagens) paginam por cursor opaco, nunca por offset:
GET /mailboxes/{id}/messages?limit=50
→ { "messages": [...], "next_cursor": "eyJ…" }
GET /mailboxes/{id}/messages?limit=50&cursor=eyJ…
Passe next_cursor de volta como veio. Vazio significa que acabou. Um cursor velho ou inválido volta à primeira página em vez de virar erro. O escopo é sempre a caixa da rota — a query string recorta, nunca amplia.
Superfície da API
Envio — POST /v1/emails (transacional público), POST /mailboxes/{id}/send.
Contatos — agenda por caixa e autocomplete de destinatários.
Assinatura — HTML por caixa, sanitizado no servidor.
A referência completa de cada rota — parâmetros, corpo, respostas e um curl pronto — está logo abaixo, gerada do código e da spec.
O que não está aqui, e por quê. Domínios e caixas têm a escrita por API key descrita acima (mail:admin). O resto do plano de controle (Cloudflare, contas de caixa, concessões) e as telas do webmail (filtros, remetentes, preferências) são feitos pelo painel — não são superfície de integração por API key e por isso ficam fora desta documentação.
Registro de mudanças
data
mudança
quem é afetado
2026-10-07
Novo escopo mail:admin. Libera, para API key, a administração de domínios e caixas da própria conta (GET /orgs, domínios, DNS, verificação, caixas, catch-all/autocreate, tipo da caixa). Não lê mensagens. Sem ele, 403 InsufficientScope nomeando mail:admin.
Quem cria domínio/caixa por API key: emita a chave com mail:admin (e email:send para enviar).
2026-10-07
Quebra de contrato: chaves sem escopo deixam de funcionar.POST /v1/emails passa a exigir o escopo email:send e a leitura de mensagens email:read; chave sem escopos, full_access, send_only ou emails:* recebe 403 InsufficientScope. As rotas de plano de controle (orgs, domínios, caixas, filtros…) deixam de aceitar API key (403) — exceto domínios e caixas, devolvidos pelo escopo mail:admin (linha acima).
Quem usa chave emitida antes desta data sem escopo do catálogo, ou criava domínio/caixa por API key: gere outra chave com email:send (e mail:admin para domínios e caixas).
Referência
Toda operação registrada no código, com o que faz, o que recebe e o que devolve.
Assinatura
GET/mailboxes/{id}/signature
Ler a assinatura da caixa
Onde é usada
GET /mailboxes/{id}/signature — a aba Assinatura das configurações e o compositor, que a injeta numa composição nova.
Parâmetros
nome
em
obrigatório
descrição
id
path
sim
id da caixa; o acesso é conferido contra a chave (deny-default).
Respostas
código
significado
200
ok
404
Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
Exemplo
curl -X GET 'https://api.mail.asender.net/mailboxes/id_AQUI/signature' \
-H 'Authorization: Bearer SEU_TOKEN'
PUT/mailboxes/{id}/signature
Gravar a assinatura da caixa (sanitizada no servidor)
Onde é usada
PUT /mailboxes/{id}/signature, corpo {"signature_html": "..."}. Devolve a assinatura COMO FICOU GRAVADA (já sanitizada), para a tela mostrar exatamente o que passou a valer — e não o que a pessoa digitou.
Parâmetros
nome
em
obrigatório
descrição
id
path
sim
id da caixa; o acesso é conferido contra a chave (deny-default).
Respostas
código
significado
200
gravada
404
Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
Autocomplete de destinatários (catálogo + histórico)
Onde é usada
GET /mailboxes/{id}/recipients/suggest?q=. Combina o catálogo e o histórico de mensagens da caixa (ver store.SugerirDestinatarios).
Parâmetros
nome
em
obrigatório
descrição
id
path
sim
id da caixa; o acesso é conferido contra a chave (deny-default).
q
query
não
prefixo digitado
Respostas
código
significado
200
sugestões
404
Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
Exemplo
curl -X GET 'https://api.mail.asender.net/mailboxes/id_AQUI/recipients/suggest' \
-H 'Authorization: Bearer SEU_TOKEN'
Domínios
GET/autoconfig/mail/config-v1.1.xml
Configuração automática do Thunderbird (autoconfig, config-v1.1) do domínio
Pelo host da plataforma, com ?emailaddress=. Pública e sem sessão: devolve o XML Mozilla (IMAP 993 SSL/TLS, SMTP 465 SSL/TLS, senha de aplicativo) SÓ para domínio verificado; domínio inexistente, não verificado ou host sem relação respondem o mesmo 404 (sem oráculo). Limite de 60 pedidos por minuto por IP.
Onde é usada
as duas rotas de registrar.
Parâmetros
nome
em
obrigatório
descrição
emailaddress
query
não
o endereço digitado no cliente (alternativa ao Host `autoconfig.<domínio>`)
Respostas
código
significado
200
XML clientConfig 1.1
404
domínio não verificado ou desconhecido (corpo idêntico)
429
muitos pedidos
503
consulta de domínio indisponível
Exemplo
curl -X GET 'https://api.mail.asender.net/autoconfig/mail/config-v1.1.xml' \
-H 'Authorization: Bearer SEU_TOKEN'
GET/mail/config-v1.1.xml
Configuração automática do Thunderbird (autoconfig, config-v1.1) do domínio
Pelo Host autoconfig.<domínio>, que é o que o Thunderbird chama. Pública e sem sessão: devolve o XML Mozilla (IMAP 993 SSL/TLS, SMTP 465 SSL/TLS, senha de aplicativo) SÓ para domínio verificado; domínio inexistente, não verificado ou host sem relação respondem o mesmo 404 (sem oráculo). Limite de 60 pedidos por minuto por IP.
Onde é usada
as duas rotas de registrar.
Parâmetros
nome
em
obrigatório
descrição
emailaddress
query
não
o endereço digitado no cliente (alternativa ao Host `autoconfig.<domínio>`)
Respostas
código
significado
200
XML clientConfig 1.1
404
domínio não verificado ou desconhecido (corpo idêntico)
429
muitos pedidos
503
consulta de domínio indisponível
Exemplo
curl -X GET 'https://api.mail.asender.net/mail/config-v1.1.xml' \
-H 'Authorization: Bearer SEU_TOKEN'
PUT/mailboxes/{id}/tipo
Mudar o tipo da caixa (pessoal ↔ coletiva)
Só uma PESSOA admin do e-mail (sessão com usuário e papel mail:admin); API key e serviço sem usuário = 403. coletiva só para caixa de origem manual/legado (422 origem_automatica/origem_conta_iam). Voltar a pessoal com assinatura ativa = 422 CaixaAssinada. A origem nunca muda. Só caixa coletiva pode ser ligada a um assinante (ADR-0088 D4).
Onde é usada
PUT /mailboxes/{id}/tipo (a tela da caixa no admin, U6).
Parâmetros
nome
em
obrigatório
descrição
id
path
sim
id da caixa; o acesso é conferido contra a chave (deny-default).
Enviar e-mail a partir de uma caixa da conta (público)
Exige o escopo email:send (sem ele, 403 InsufficientScope). Envia de uma CAIXA que existe na conta da chave (o domínio verificado não basta: crie a caixa do from antes, pelo painel), assinado com o DKIM do domínio. Para remetente de qualquer endereço de um domínio verificado (incluindo OTP/2FA), use POST https://api.asender.net/v1/emails/send. Idempotente por Idempotency-Key (a mesma chave + tenant não dispara dois e-mails; o replay volta 200 com idempotent_replay:true). Consome a quota de disparos do plano — um por destinatário em to/cc/bcc — e responde 429 quando o teto (diário ou mensal) é atingido. Fora de produção, o piso 18 bloqueia destinos não-allowlistados (o e-mail não sai).
Onde é usada
POST /v1/emails. Fluxo: API key -> tenant -> caixa por endereço -> outbound -> relay /raw.
Parâmetros
nome
em
obrigatório
descrição
Idempotency-Key
header
não
repita a mesma chave para tornar seguro o retry de uma resposta perdida.
Respostas
código
significado
200
replay idempotente (já enviado antes).
202
aceito e entregue.
400
validação (from inválido, to vazio, header-injection em endereço, anexo inválido).
401
API key ausente ou inválida.
403
`InsufficientScope` — a chave não tem o escopo `email:send` (sem escopos, `full_access`, `send_only` e `emails:*` também caem aqui).
422
o antivírus encontrou malware num anexo (`AnexoInfectado`); nada foi enviado (ADR-0087).
429
Limite de disparos do plano atingido no período. Os cabeçalhos dizem qual janela barrou e quando reabre.
502
envio recusado (piso 18 fora de prd) ou a entrega falhou; a quota é estornada.
503
envio não configurado no serviço (boot sem outbound), ou mensagem COM anexo com o antivírus configurado e fora (`AntivirusIndisponivel`, com Retry-After) — nada sai sem exame.
id da caixa; o acesso é conferido contra a chave (deny-default).
Respostas
código
significado
200
ok
404
Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
Exemplo
curl -X GET 'https://api.mail.asender.net/mailboxes/id_AQUI/identities' \
-H 'Authorization: Bearer SEU_TOKEN'
POST/mailboxes/{id}/identities
Criar identidade de envio (send-as)
O par nome+endereço que a caixa pode usar como "De". O endereço é aceito aqui, mas o ENVIO por ele só passa se o domínio for da org com DKIM verificado (a trava anti-spoofing está no envio).
Onde é usada
POST /mailboxes/{id}/identities.
Parâmetros
nome
em
obrigatório
descrição
id
path
sim
id da caixa; o acesso é conferido contra a chave (deny-default).
Respostas
código
significado
201
criada
400
endereço inválido
404
Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
exige administrador e posse do tenant (404 para outro tenant ou caixa já removida, sem vazar existência). Com vínculos (catch-all, encaminhamento/regra de outra caixa que aponta para ela, assinatura do atendimento) recusa com 409 `CaixaComVinculos` + `vinculos` — NÃO limpa o roteamento alheio em silêncio. Com sucesso a caixa deixa de receber (rejeita como inexistente), de autenticar no IMAP/SMTP, some das listas e do "De"; nenhuma mensagem, anexo ou blob é tocado.
GET/mailboxes/{id}/messages/{msgId}/attachments/{attId}sem schema na spec
caixa->domínio->tenant + AcharAnexo (scopeado à mensagem/caixa); responde com o conteúdo e Content-Disposition.
Onde é usada
GET /mailboxes/{id}/messages/{msgId}/attachments/{attId}.
Exemplo
curl -X GET 'https://api.mail.asender.net/mailboxes/id_AQUI/messages/msgId_AQUI/attachments/attId_AQUI' \
-H 'Authorization: Bearer SEU_TOKEN'
POST/mailboxes/{id}/messages/{msgId}/pgp-verifysem schema na spec
carrega a mensagem (da caixa), acha a chave do From e verifica o clearsign do corpo.
Onde é usada
POST /mailboxes/{id}/messages/{msgId}/pgp-verify.
Saídas
{verified, signer_fingerprint} — verified:false (200) quando não há chave do remetente ou a assinatura não confere; a tela mostra "não verificado" em vez de tratar como erro de sistema.
exige administrador; acha a removida (404 se ativa/inexistente/outro tenant); 409 `EnderecoEmUso` se uma caixa ativa já tomou o endereço e 409 `DominioRemovido` se o domínio saiu da conta.
Listar mensagens da caixa (por pasta, marcadores e busca)
Paginada por cursor opaco. O escopo é sempre a caixa da rota — a query recorta, nunca amplia. Cursor inválido/velho volta à primeira página em vez de virar erro.
Onde é usada
GET /mailboxes/{id}/messages?folder=&unread=1&starred=1&q=&limit=N&cursor=… O recorte vem da query string, mas o ESCOPO não: a caixa sai da rota já autorizada, e é ela que a consulta usa. Um ?mailbox= no filtro seria a própria pessoa escolhendo o que pode ver.
Parâmetros
nome
em
obrigatório
descrição
id
path
sim
id da caixa; o acesso é conferido contra a chave (deny-default).
folder
query
não
kind (inbox/sent/archive/spam/trash/drafts) ou uuid da pasta; ausente = todas
unread
query
não
só não-lidas
starred
query
não
só estreladas
q
query
não
Linguagem de busca (estilo Gmail). Espaço = E; `OR` (ou vírgula dentro de um operador) = OU; `-` nega. Operadores: `de:`/`from:`, `para:`/`to:`, `cc:`, `assunto:`/`subject:`, `dominio:` (domínio do remetente OU subdomínio dele), `tem:anexo`, `etiqueta:"Nome"`, `pasta:` (entrada, arquivo, enviados, rascunhos, spam, lixeira ou o nome de uma pasta sua), `antes:`/`depois:` (AAAA-MM-DD, UTC), `lista:` (List-Id exato), `maior:`/`menor:` (tamanho do .eml: 5MB, 200KB, 1.5MB ou bytes; não medido não casa), `lida:sim|nao`, `is:read|unread`, `nao-lida`. `pasta:todas` = todo o correio menos Rascunhos/Spam/Lixeira/Quarentena. `campo:(a OR b)` = `campo:a,b`. Valor de de:/para: com `@` no meio = endereço exato; com cara de domínio = domínio/subdomínio; outro = trecho. Palavra solta com cara de domínio/endereço (`anthropic.com`) = remetente; outra palavra = texto livre (assunto, remetente, corpo; com radicais); entre aspas = sempre texto. Limites: 512 caracteres, 30 valores, 20 por OU, 5 etiquetas; 400 BuscaInvalida com a frase. Ex.: `anthropic.com,claude.com,claude.ai` ou `anthropic.com OR claude.com OR claude.ai`.
label
query
não
id de uma etiqueta; só as mensagens que a carregam (eixo ortogonal à pasta)
todas
query
não
Todos os e-mails: todas as pastas menos Rascunhos (e menos Spam/Lixeira/Quarentena sem `ocultas`); ignora `folder`; a busca vale dentro
ocultas
query
não
com `todas`: inclui Spam, Lixeira e Quarentena
limit
query
não
cursor
query
não
o next_cursor da página anterior (opaco)
Respostas
código
significado
200
ok
400
busca inválida (BuscaInvalida
404
Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
Exemplo
curl -X GET 'https://api.mail.asender.net/mailboxes/id_AQUI/messages' \
-H 'Authorization: Bearer SEU_TOKEN'
GET/mailboxes/{id}/messages/{msgId}
Ler a mensagem completa (marca como lida)
Onde é usada
GET /mailboxes/{id}/messages/{msgId}. Cross-tenant/outra caixa -> 404.
Parâmetros
nome
em
obrigatório
descrição
id
path
sim
id da caixa; o acesso é conferido contra a chave (deny-default).
msgId
path
sim
Respostas
código
significado
200
ok
404
Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
Exemplo
curl -X GET 'https://api.mail.asender.net/mailboxes/id_AQUI/messages/msgId_AQUI' \
-H 'Authorization: Bearer SEU_TOKEN'
PATCH/mailboxes/{id}/messages/{msgId}
Marcar lida, estrelar ou mover uma mensagem
Onde é usada
PATCH /mailboxes/{id}/messages/{msgId}.
Erros
patch vazio -> 400 (não é sucesso silencioso); mensagem de outra caixa -> 404, o mesmo da leitura, que não revela a existência dela.
Parâmetros
nome
em
obrigatório
descrição
id
path
sim
id da caixa; o acesso é conferido contra a chave (deny-default).
msgId
path
sim
Respostas
código
significado
200
aplicado
400
corpo sem nenhum campo
404
Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
409
mover PARA a Quarentena, ou tirar dela por aqui — a saída é POST …/quarantine/release (ADR-0087)
Liberar uma mensagem da Quarentena para a Entrada (ADR-0087)
Achado heurístico/PUA (Heuristics.*, PUA.*): quem tem a caixa libera. Achado de ASSINATURA (descoberto no reexame): só o admin (403 para os demais). Exige {"confirmo": true}. A liberação é auditada (quem, quando, qual assinatura) e NÃO muda o veredito: a mensagem continua infectado, e o download dos anexos exige aceito_risco=1. O PATCH de pasta recusa sair da Quarentena (409) — esta é a única saída.
Onde é usada
POST /mailboxes/{id}/messages/{msgId}/quarantine/release. O veredito continua infectado (liberar é decisão humana, não exame): o download dos anexos segue pedindo confirmação de risco (anexos.go).
Parâmetros
nome
em
obrigatório
descrição
id
path
sim
id da caixa; o acesso é conferido contra a chave (deny-default).
msgId
path
sim
Respostas
código
significado
200
liberada
400
sem a confirmação
403
achado de assinatura e quem pede não é admin
404
Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
O bruto guardado sai byte a byte como chegou; à FRENTE dele, numa mensagem recebida, vão cabeçalhos SINTETIZADOS do veredito gravado (ADR-0087): X-Spam-Flag (YES quando a mensagem está hoje na pasta Spam), X-Spam-Status, X-Spam-Score, X-Spam-Action e X-Spam-Symbols (quando o motor de conteúdo opinou) e o Authentication-Results que geramos. Cabeçalhos acrescentados no topo não invalidam a assinatura DKIM.
Onde é usada
GET /mailboxes/{id}/messages/{msgId}/raw. Por que a rota existe: o .eml é o único artefato fiel do que chegou ou saiu — com cabeçalhos, ordem das partes e assinatura DKIM. É o que se abre noutro cliente, o que se anexa a uma disputa e o que se reprocessa quando o parser melhora. Sem rota, ele seria um arquivo num volume que ninguém alcança. Mensagem anterior ao ADR-0028 não tem bruto: 404, que é a verdade — e não um arquivo vazio com cara de download bem-sucedido.
Parâmetros
nome
em
obrigatório
descrição
id
path
sim
id da caixa; o acesso é conferido contra a chave (deny-default).
msgId
path
sim
Respostas
código
significado
200
message/rfc822
404
Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
Exemplo
curl -X GET 'https://api.mail.asender.net/mailboxes/id_AQUI/messages/msgId_AQUI/raw' \
-H 'Authorization: Bearer SEU_TOKEN'
POST/mailboxes/{id}/messages/{msgId}/rescan
Reexaminar agora uma mensagem pendente ou não verificada (ADR-0087)
Roda o antivírus sobre o .eml guardado e grava o veredito; malware vai para a Quarentena (heurística conforme a política da org). Teto de 10 por minuto por caixa (429). Scanner fora → 503 e a mensagem continua pendente (o reexame automático tenta de novo). Mensagem já verificada (limpo/infectado) ou sem o original guardado → 409.
Onde é usada
POST /mailboxes/{id}/messages/{msgId}/rescan.
Parâmetros
nome
em
obrigatório
descrição
id
path
sim
id da caixa; o acesso é conferido contra a chave (deny-default).
msgId
path
sim
Respostas
código
significado
200
veredito
404
Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
409
já verificada
429
teto de 10 reexames por minuto na caixa (Retry-After)
503
antivírus desligado neste ambiente ou indisponível (Retry-After)
A autorização é por CAIXA; dentro dela cada id é conferido. Id que não pertence à caixa volta em negados (não é aplicado nem ignorado em silêncio). Máximo de 500 ids.
Onde é usada
POST /mailboxes/{id}/messages/batch. # A resposta diz o que NÃO foi feito Id que não é desta caixa volta em negados. Não é aplicado — e também não é ignorado em silêncio: a tela precisa poder dizer "3 de 5 movidas" em vez de mostrar cinco linhas somindo e duas voltando no próximo carregamento (piso 4). O status é 200 mesmo com negados: a operação aconteceu, parcialmente, e a lista dos dois lados é a resposta — um 4xx obrigaria o cliente a adivinhar o que foi aplicado.
Parâmetros
nome
em
obrigatório
descrição
id
path
sim
id da caixa; o acesso é conferido contra a chave (deny-default).
Respostas
código
significado
200
aplicado (possivelmente em parte)
400
lista vazia, mais de 500, ou patch sem campo
404
Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
Filtrar parecidos — o que as mensagens escolhidas têm em comum, como critérios de busca
Critérios ordenados por cobertura (quantas das escolhidas pegam) e especificidade: remetente exato, conjunto de remetentes, padrão do endereço (de:no-reply@), domínio(s), domínio registrável, List-Id, começo/palavras comuns do assunto, destinatário, Cc, anexo; Reply-To aparece sem busca (não é campo de busca), com motivo. sugerido marca a combinação pré-marcada e busca_sugerida a junta. total é quantas mensagens da caixa a busca do critério acha. Ids de outra caixa são ignorados.
Parâmetros
nome
em
obrigatório
descrição
id
path
sim
id da caixa; o acesso é conferido contra a chave (deny-default).
Respostas
código
significado
200
critérios
400
sem ids
404
Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
Todas as mensagens da thread, em ordem cronológica (mais antiga primeiro), com as imagens inline (cid:) já embutidas como data:. Escopo por caixa: a thread de outra caixa não é alcançável nem com o uuid.
Onde é usada
GET /mailboxes/{id}/threads/{threadId}. Cross-caixa/tenant -> 404 (a thread de outra caixa não é alcançável mesmo com o uuid). Marca a conversa como lida (best-effort) — abrir a thread é ler.
Parâmetros
nome
em
obrigatório
descrição
id
path
sim
id da caixa; o acesso é conferido contra a chave (deny-default).
threadId
path
sim
Respostas
código
significado
200
ok
404
Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
Exemplo
curl -X GET 'https://api.mail.asender.net/mailboxes/id_AQUI/threads/threadId_AQUI' \
-H 'Authorization: Bearer SEU_TOKEN'
Rascunhos
POST/mailboxes/{id}/drafts
Criar rascunho (auto-save do compositor)
Onde é usada
POST /mailboxes/{id}/drafts.
Parâmetros
nome
em
obrigatório
descrição
id
path
sim
id da caixa; o acesso é conferido contra a chave (deny-default).
Respostas
código
significado
201
criado
404
Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
Resumo da ferramenta para o hub e a home (contrato comum de resumo).
Sobre as caixas que a PESSOA recebeu por concessão (e-mail é por caixa, não por conta): número de caixas, não lidos da Entrada (agora), recebidos e enviados na janela (com a anterior) e as séries por dia. Com API key (máquina, sem usuário), todas as caixas ativas da conta. Tenant e usuário vêm da credencial verificada, nunca da query. Conta alheia → 404; membro sem acesso ao produto → 403.
Onde é usada
hub (asender_plataforma_bff /api/resumo) e a Visão geral do webmail.
Efeitos
duas leituras (store.ResumoDoUsuario), nenhuma escrita. Tenant e usuário vêm do principal que o middleware verificou — nunca da query.
Parâmetros
nome
em
obrigatório
descrição
periodo
query
não
janela dos indicadores — os N últimos dias fechados em hoje (UTC). Padrão 30d.
Respostas
código
significado
200
o resumo da ferramenta `mail`.
400
Parâmetro de query fora do conjunto aceito.
401
API key ausente ou inválida.
403
membro da conta sem acesso a esta ferramenta.
404
Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
Exemplo
curl -X GET 'https://api.mail.asender.net/v1/resumo' \
-H 'Authorization: Bearer SEU_TOKEN'