E-mail

https://api.mail.asender.net · API key (Bearer sk_…) · 58 operações · openapi.yaml

Mail API

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.

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).

Envie a chave em Authorization:

Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxx

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).

Chave ausente ou inválida devolve 401:

{ "error": "AuthorizationError", "message": "API key inválida." }

Escopos da API key (obrigatórios)

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:

{ "error": "InsufficientScope", "message": "API key lacks the required scope: email:send." }
escoporotas
email:sendPOST /v1/emails, POST /mailboxes/{id}/send
email:readGET /mailboxes/{id}/messages, GET /mailboxes/{id}/messages/{msgId}, …/raw, …/attachments/{attId}, GET /mailboxes/{id}/threads/{threadId}
mail:adminadministraçã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:

Antes do primeiro envio: crie a caixa remetente

O envio exige duas coisas na mesma conta da API key:

  1. Domínio verificado (MX, SPF, DKIM e DMARC) — pela tela Domínios do e-mail ou por POST /orgs/{orgID}/domains + verificação.
  2. 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 403 InsufficientScope 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:

headersignificado
X-Quota-Limitteto do plano na janela que barrou
X-Quota-Useddisparos já consumidos
X-Quota-Remainingdisparos restantes
X-Quota-Escaladia ou mes — qual janela barrou (o corporativo tem as duas)
Retry-Aftersegundos 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 HTTPerror típicoquando
400ValidationErrorcorpo inválido, from/to ausentes, injeção de cabeçalho, anexo inválido
401AuthorizationErrorAPI key ausente ou inválida
403InsufficientScopea 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
404NotFoundrecurso fora do escopo da chave (não revela existência alheia)
422CaixaRemetenteInexistentePOST /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)
429QuotaExceededteto de disparos do plano (ver cabeçalhos X-Quota-*)
502SendFailedentrega recusada (piso 18) ou falha no relay; a quota é estornada
503InternalErrorenvio 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

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

datamudançaquem é afetado
2026-10-07Novo 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-07Quebra 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 é usadaGET /mailboxes/{id}/signature — a aba Assinatura das configurações e o compositor, que a injeta numa composição nova.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).

Respostas

códigosignificado
200ok
404Recurso 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 é usadaPUT /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

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).

Respostas

códigosignificado
200gravada
404Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).

Exemplo

curl -X PUT 'https://api.mail.asender.net/mailboxes/id_AQUI/signature' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'

Contatos

GET /mailboxes/{id}/contacts

Listar a agenda da caixa

Onde é usadaGET /mailboxes/{id}/contacts. q casa nome OU e-mail (substring, case-insensitive); ausente devolve tudo.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).

Respostas

códigosignificado
200ok

Exemplo

curl -X GET 'https://api.mail.asender.net/mailboxes/id_AQUI/contacts' \
  -H 'Authorization: Bearer SEU_TOKEN'
POST /mailboxes/{id}/contacts

Adicionar contato à agenda da caixa

Onde é usadaPOST /mailboxes/{id}/contacts. E-mail repetido na caixa -> 409.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).

Respostas

códigosignificado
201criado
404Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).

Exemplo

curl -X POST 'https://api.mail.asender.net/mailboxes/id_AQUI/contacts' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'
DELETE /mailboxes/{id}/contacts/{contatoId}

Apagar contato

Onde é usadaDELETE /mailboxes/{id}/contacts/{contatoId}. Contato inexistente ou de outra caixa -> 404 (o mesmo da leitura; não deixa sondar contato alheio).

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).
contatoIdpath sim

Respostas

códigosignificado
204apagado
404Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).

Exemplo

curl -X DELETE 'https://api.mail.asender.net/mailboxes/id_AQUI/contacts/contatoId_AQUI' \
  -H 'Authorization: Bearer SEU_TOKEN'
PATCH /mailboxes/{id}/contacts/{contatoId}

Atualizar contato

Onde é usadaPATCH /mailboxes/{id}/contacts/{contatoId}. Contato de outra caixa (ou id que não é contato) -> 404; novo e-mail que colide -> 409.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).
contatoIdpath sim

Respostas

códigosignificado
200ok
404Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).

Exemplo

curl -X PATCH 'https://api.mail.asender.net/mailboxes/id_AQUI/contacts/contatoId_AQUI' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'
GET /mailboxes/{id}/recipients/suggest

Autocomplete de destinatários (catálogo + histórico)

Onde é usadaGET /mailboxes/{id}/recipients/suggest?q=. Combina o catálogo e o histórico de mensagens da caixa (ver store.SugerirDestinatarios).

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).
qquery nãoprefixo digitado

Respostas

códigosignificado
200sugestões
404Recurso 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 é usadaas duas rotas de registrar.

Parâmetros

nomeemobrigatóriodescrição
emailaddressquery nãoo endereço digitado no cliente (alternativa ao Host `autoconfig.<domínio>`)

Respostas

códigosignificado
200XML clientConfig 1.1
404domínio não verificado ou desconhecido (corpo idêntico)
429muitos pedidos
503consulta 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 é usadaas duas rotas de registrar.

Parâmetros

nomeemobrigatóriodescrição
emailaddressquery nãoo endereço digitado no cliente (alternativa ao Host `autoconfig.<domínio>`)

Respostas

códigosignificado
200XML clientConfig 1.1
404domínio não verificado ou desconhecido (corpo idêntico)
429muitos pedidos
503consulta 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 é usadaPUT /mailboxes/{id}/tipo (a tela da caixa no admin, U6).

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).

Respostas

códigosignificado
200caixa atualizada (com tipo e origem)
400tipo inválido
403não é uma pessoa admin do e-mail
404caixa inexistente ou de outra conta
422inelegível ou assinada

Exemplo

curl -X PUT 'https://api.mail.asender.net/mailboxes/id_AQUI/tipo' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'

Envio

POST /mailboxes/{id}/send

Enviar a partir de uma caixa específica

Onde é usadaPOST /mailboxes/{id}/send. Fluxo: JSON -> outbound.Service.Enviar (assina d=domínio) -> relay /raw.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).

Respostas

códigosignificado
202enviado
401API key ausente ou inválida.
404Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
422malware num anexo (`AnexoInfectado`); nada foi enviado (ADR-0087)
503mensagem com anexo e antivírus fora (`AntivirusIndisponivel`, Retry-After); o rascunho fica

Exemplo

curl -X POST 'https://api.mail.asender.net/mailboxes/id_AQUI/send' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'
POST /v1/emails

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 é usadaPOST /v1/emails. Fluxo: API key -> tenant -> caixa por endereço -> outbound -> relay /raw.

Parâmetros

nomeemobrigatóriodescrição
Idempotency-Keyheader nãorepita a mesma chave para tornar seguro o retry de uma resposta perdida.

Respostas

códigosignificado
200replay idempotente (já enviado antes).
202aceito e entregue.
400validação (from inválido, to vazio, header-injection em endereço, anexo inválido).
401API 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).
422o antivírus encontrou malware num anexo (`AnexoInfectado`); nada foi enviado (ADR-0087).
429Limite de disparos do plano atingido no período. Os cabeçalhos dizem qual janela barrou e quando reabre.
502envio recusado (piso 18 fora de prd) ou a entrega falhou; a quota é estornada.
503envio 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.

Exemplo

curl -X POST 'https://api.mail.asender.net/v1/emails' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'

Etiquetas

GET /mailboxes/{id}/labels

Listar etiquetas da caixa (M-E)

Onde é usadaGET /mailboxes/{id}/labels.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).

Respostas

códigosignificado
200ok
404Recurso 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/labels' \
  -H 'Authorization: Bearer SEU_TOKEN'
POST /mailboxes/{id}/labels

Criar etiqueta na caixa

Onde é usadaPOST /mailboxes/{id}/labels.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).

Respostas

códigosignificado
201criada
400nome inválido
404Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
409nome já existe na caixa

Exemplo

curl -X POST 'https://api.mail.asender.net/mailboxes/id_AQUI/labels' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'
DELETE /mailboxes/{id}/labels/{labelId}

Apagar uma etiqueta (as mensagens perdem só o vínculo)

Onde é usadaDELETE /mailboxes/{id}/labels/{labelId}.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).
labelIdpath sim

Respostas

códigosignificado
200ok
404Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
409etiqueta de sistema não se apaga

Exemplo

curl -X DELETE 'https://api.mail.asender.net/mailboxes/id_AQUI/labels/labelId_AQUI' \
  -H 'Authorization: Bearer SEU_TOKEN'
PATCH /mailboxes/{id}/labels/{labelId}

Renomear/recolorir uma etiqueta

Onde é usadaPATCH /mailboxes/{id}/labels/{labelId}.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).
labelIdpath sim

Respostas

códigosignificado
200ok
404Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
409nome já existe na caixa, ou etiqueta de sistema (só a cor muda)

Exemplo

curl -X PATCH 'https://api.mail.asender.net/mailboxes/id_AQUI/labels/labelId_AQUI' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'
GET /mailboxes/{id}/labels/resumo

Etiquetas da caixa com origem e contagens (a lateral)

GET /mailboxes/{id}/labels continua compatível; esta rota acrescenta origem/sistema, total e não lidas.

Onde é usadaGET /mailboxes/{id}/labels/resumo -> EtiquetasNav do mail_front.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).

Respostas

códigosignificado
200ok
404Recurso 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/labels/resumo' \
  -H 'Authorization: Bearer SEU_TOKEN'
POST /mailboxes/{id}/messages/{msgId}/labels

Aplicar uma etiqueta a uma mensagem (idempotente)

Etiqueta e mensagem têm de ser da caixa; caso contrário 404 (anti cross-caixa).

Onde é usadaPOST /mailboxes/{id}/messages/{msgId}/labels {label_id}.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).
msgIdpath sim

Respostas

códigosignificado
200aplicado
404Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).

Exemplo

curl -X POST 'https://api.mail.asender.net/mailboxes/id_AQUI/messages/msgId_AQUI/labels' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'
DELETE /mailboxes/{id}/messages/{msgId}/labels/{labelId}

Remover uma etiqueta de uma mensagem (idempotente)

Onde é usadaDELETE /mailboxes/{id}/messages/{msgId}/labels/{labelId}.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).
msgIdpath sim
labelIdpath sim

Respostas

códigosignificado
200removido
404Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).

Exemplo

curl -X DELETE 'https://api.mail.asender.net/mailboxes/id_AQUI/messages/msgId_AQUI/labels/labelId_AQUI' \
  -H 'Authorization: Bearer SEU_TOKEN'
POST /mailboxes/{id}/messages/labels

Aplicar/remover etiquetas em lote (até 500 mensagens × 20 etiquetas)

Posse dupla por caixa na própria consulta: id de outra caixa é ignorado e não conta. aplicado_por = usuario:<id> com sessão.

Onde é usadaPOST /mailboxes/{id}/messages/labels (barra de lote e atalho l).
Saídas200 {vinculadas, desvinculadas}; 400 lote inválido; 404 caixa alheia.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).

Respostas

códigosignificado
200feito
400lote vazio, grande demais, id malformado ou a mesma etiqueta nos dois lados
404Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).

Exemplo

curl -X POST 'https://api.mail.asender.net/mailboxes/id_AQUI/messages/labels' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'
POST /mailboxes/{id}/threads/{threadId}/labels

Aplicar/remover etiquetas em todas as mensagens de uma conversa

Onde é usadaPOST /mailboxes/{id}/threads/{threadId}/labels (leitura em conversa).
Saídas200 {vinculadas, desvinculadas}; 400; 404 (caixa ou conversa alheia).

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).
threadIdpath sim

Respostas

códigosignificado
200feito
400pedido malformado
404Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).

Exemplo

curl -X POST 'https://api.mail.asender.net/mailboxes/id_AQUI/threads/threadId_AQUI/labels' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'

Identidades

GET /mailboxes/{id}/identities

Listar identidades de envio da caixa (M-E)

Onde é usadaGET /mailboxes/{id}/identities.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).

Respostas

códigosignificado
200ok
404Recurso 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 é usadaPOST /mailboxes/{id}/identities.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).

Respostas

códigosignificado
201criada
400endereço inválido
404Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
409endereço já existe na caixa

Exemplo

curl -X POST 'https://api.mail.asender.net/mailboxes/id_AQUI/identities' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'
DELETE /mailboxes/{id}/identities/{identityId}

Apagar uma identidade de envio

Onde é usadaDELETE /mailboxes/{id}/identities/{identityId}.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).
identityIdpath sim

Respostas

códigosignificado
200ok
404Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).

Exemplo

curl -X DELETE 'https://api.mail.asender.net/mailboxes/id_AQUI/identities/identityId_AQUI' \
  -H 'Authorization: Bearer SEU_TOKEN'
PATCH /mailboxes/{id}/identities/{identityId}

Editar uma identidade de envio

Onde é usadaPATCH /mailboxes/{id}/identities/{identityId}.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).
identityIdpath sim

Respostas

códigosignificado
200ok
404Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
409endereço já existe na caixa

Exemplo

curl -X PATCH 'https://api.mail.asender.net/mailboxes/id_AQUI/identities/identityId_AQUI' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'

mailboxes

DELETE /mailboxes/{id} sem schema na spec

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.

Onde é usadaDELETE /mailboxes/{id}.
Saídas200 {removed, address}; 403; 404; 409.

Exemplo

curl -X DELETE 'https://api.mail.asender.net/mailboxes/id_AQUI' \
  -H 'Authorization: Bearer SEU_TOKEN'
DELETE /mailboxes/{id}/avatar sem schema na spec

ApagarAvatarDaCaixa remove a foto.

Onde é usadaDELETE /mailboxes/{id}/avatar (admin).

Exemplo

curl -X DELETE 'https://api.mail.asender.net/mailboxes/id_AQUI/avatar' \
  -H 'Authorization: Bearer SEU_TOKEN'
GET /mailboxes/{id}/avatar sem schema na spec

exigirCaixa (tenant + grant/admin, 404 para quem não pode) e os bytes com os cabeçalhos que impedem a imagem de virar documento na origem do webmail.

Onde é usadaGET /mailboxes/{id}/avatar.

Exemplo

curl -X GET 'https://api.mail.asender.net/mailboxes/id_AQUI/avatar' \
  -H 'Authorization: Bearer SEU_TOKEN'
PUT /mailboxes/{id}/avatar sem schema na spec

só ADMIN do mail no tenant da caixa (exigirAdminNaCaixa); a imagem é decodificada e recodificada em PNG ≤ 256 px ANTES de tocar o blob.

Onde é usadaPUT /mailboxes/{id}/avatar.

Exemplo

curl -X PUT 'https://api.mail.asender.net/mailboxes/id_AQUI/avatar' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'
DELETE /mailboxes/{id}/folders/{fid} sem schema na spec

authz por caixa + DELETE restrito a `custom` e sem conteúdo.

Onde é usadaDELETE /mailboxes/{id}/folders/{fid}.

Exemplo

curl -X DELETE 'https://api.mail.asender.net/mailboxes/id_AQUI/folders/fid_AQUI' \
  -H 'Authorization: Bearer SEU_TOKEN'
PATCH /mailboxes/{id}/folders/{fid} sem schema na spec

authz por caixa + UPDATE restrito a `custom`.

Onde é usadaPATCH /mailboxes/{id}/folders/{fid}.

Exemplo

curl -X PATCH 'https://api.mail.asender.net/mailboxes/id_AQUI/folders/fid_AQUI' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'
GET /mailboxes/{id}/forwarding sem schema na spec

LerForward devolve a regra de encaminhamento da caixa.

Onde é usadaGET /mailboxes/{id}/forwarding.

Exemplo

curl -X GET 'https://api.mail.asender.net/mailboxes/id_AQUI/forwarding' \
  -H 'Authorization: Bearer SEU_TOKEN'
PUT /mailboxes/{id}/forwarding sem schema na spec

valida o destino (net/mail, no store) e faz UPSERT.

Onde é usadaPUT /mailboxes/{id}/forwarding. Ligar sem destino é recusado (400). O encaminhamento em si é um ENVIO no recebimento (guard do piso 18).

Exemplo

curl -X PUT 'https://api.mail.asender.net/mailboxes/id_AQUI/forwarding' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'
POST /mailboxes/{id}/import sem schema na spec

decodifica o arquivo, separa nas mensagens, e grava cada uma que a caixa ainda não tem (por Message-ID).

Onde é usadaPOST /mailboxes/{id}/import.
Saídas{imported, skipped, total}. Uma mensagem que falha ao gravar é contada em errors e NÃO derruba o import inteiro — o resto é aproveitado.

Exemplo

curl -X POST 'https://api.mail.asender.net/mailboxes/id_AQUI/import' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'
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 é usadaGET /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-verify sem schema na spec

carrega a mensagem (da caixa), acha a chave do From e verifica o clearsign do corpo.

Onde é usadaPOST /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.

Exemplo

curl -X POST 'https://api.mail.asender.net/mailboxes/id_AQUI/messages/msgId_AQUI/pgp-verify' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'
GET /mailboxes/{id}/pgp/keys sem schema na spec

ListarChavesPGP devolve as chaves públicas da caixa (fingerprint + uid, sem o

Onde é usadaGET /mailboxes/{id}/pgp/keys.

Exemplo

curl -X GET 'https://api.mail.asender.net/mailboxes/id_AQUI/pgp/keys' \
  -H 'Authorization: Bearer SEU_TOKEN'
POST /mailboxes/{id}/pgp/keys sem schema na spec

valida o bloco armored no servidor (é chave PÚBLICA? qual a fingerprint?), deriva fingerprint/uid e faz UPSERT por (caixa, endereço).

Onde é usadaPOST /mailboxes/{id}/pgp/keys {email, public_key, is_own}. A fingerprint devolvida é a DERIVADA aqui — a pessoa a confere fora de banda.

Exemplo

curl -X POST 'https://api.mail.asender.net/mailboxes/id_AQUI/pgp/keys' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'
DELETE /mailboxes/{id}/pgp/keys/{keyId} sem schema na spec

ApagarChavePGP remove uma chave da caixa.

Onde é usadaDELETE .../pgp/keys/{keyId}.

Exemplo

curl -X DELETE 'https://api.mail.asender.net/mailboxes/id_AQUI/pgp/keys/keyId_AQUI' \
  -H 'Authorization: Bearer SEU_TOKEN'
POST /mailboxes/{id}/restaurar sem schema na spec

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.

Onde é usadaPOST /mailboxes/{id}/restaurar.
Saídas200 {restored, mailbox}.

Exemplo

curl -X POST 'https://api.mail.asender.net/mailboxes/id_AQUI/restaurar' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'
GET /mailboxes/{id}/vacation sem schema na spec

LerFerias devolve a regra de férias da caixa (o padrão quando não há).

Onde é usadaGET /mailboxes/{id}/vacation.

Exemplo

curl -X GET 'https://api.mail.asender.net/mailboxes/id_AQUI/vacation' \
  -H 'Authorization: Bearer SEU_TOKEN'
PUT /mailboxes/{id}/vacation sem schema na spec

valida a janela e faz UPSERT.

Onde é usadaPUT /mailboxes/{id}/vacation. A auto-resposta em si é um ENVIO no recebimento e passa pelo guard do piso 18; aqui só se guarda a REGRA.

Exemplo

curl -X PUT 'https://api.mail.asender.net/mailboxes/id_AQUI/vacation' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'

Mensagens

GET /mailboxes/{id}/folders

Pastas da caixa, com total e não-lidas

Onde é usadaGET /mailboxes/{id}/folders, que desenha o rail.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).

Respostas

códigosignificado
200ok
404Recurso 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/folders' \
  -H 'Authorization: Bearer SEU_TOKEN'
POST /mailboxes/{id}/folders

Criar pasta do usuário (kind=custom)

Onde é usadaPOST /mailboxes/{id}/folders.
Saídas201 com a pasta; 400/409 conforme o nome; 404 se a caixa não é de quem pediu.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).

Respostas

códigosignificado
201criada
404Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).

Exemplo

curl -X POST 'https://api.mail.asender.net/mailboxes/id_AQUI/folders' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'
GET /mailboxes/{id}/messages

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 é usadaGET /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

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).
folderquery nãokind (inbox/sent/archive/spam/trash/drafts) ou uuid da pasta; ausente = todas
unreadquery nãosó não-lidas
starredquery nãosó estreladas
qquery nãoLinguagem 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`.
labelquery nãoid de uma etiqueta; só as mensagens que a carregam (eixo ortogonal à pasta)
todasquery nãoTodos os e-mails: todas as pastas menos Rascunhos (e menos Spam/Lixeira/Quarentena sem `ocultas`); ignora `folder`; a busca vale dentro
ocultasquery nãocom `todas`: inclui Spam, Lixeira e Quarentena
limitquery não
cursorquery nãoo next_cursor da página anterior (opaco)

Respostas

códigosignificado
200ok
400busca inválida (BuscaInvalida
404Recurso 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 é usadaGET /mailboxes/{id}/messages/{msgId}. Cross-tenant/outra caixa -> 404.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).
msgIdpath sim

Respostas

códigosignificado
200ok
404Recurso 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 é usadaPATCH /mailboxes/{id}/messages/{msgId}.
Errospatch 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

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).
msgIdpath sim

Respostas

códigosignificado
200aplicado
400corpo sem nenhum campo
404Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
409mover PARA a Quarentena, ou tirar dela por aqui — a saída é POST …/quarantine/release (ADR-0087)

Exemplo

curl -X PATCH 'https://api.mail.asender.net/mailboxes/id_AQUI/messages/msgId_AQUI' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'
POST /mailboxes/{id}/messages/{msgId}/quarantine/release

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 é usadaPOST /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

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).
msgIdpath sim

Respostas

códigosignificado
200liberada
400sem a confirmação
403achado de assinatura e quem pede não é admin
404Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
409a mensagem não está na Quarentena

Exemplo

curl -X POST 'https://api.mail.asender.net/mailboxes/id_AQUI/messages/msgId_AQUI/quarantine/release' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'
GET /mailboxes/{id}/messages/{msgId}/raw

Baixar o .eml original (ADR-0028)

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 é usadaGET /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

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).
msgIdpath sim

Respostas

códigosignificado
200message/rfc822
404Recurso 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 é usadaPOST /mailboxes/{id}/messages/{msgId}/rescan.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).
msgIdpath sim

Respostas

códigosignificado
200veredito
404Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).
409já verificada
429teto de 10 reexames por minuto na caixa (Retry-After)
503antivírus desligado neste ambiente ou indisponível (Retry-After)

Exemplo

curl -X POST 'https://api.mail.asender.net/mailboxes/id_AQUI/messages/msgId_AQUI/rescan' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'
POST /mailboxes/{id}/messages/batch

Aplicar a mesma alteração a várias mensagens

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 é usadaPOST /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

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).

Respostas

códigosignificado
200aplicado (possivelmente em parte)
400lista vazia, mais de 500, ou patch sem campo
404Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).

Exemplo

curl -X POST 'https://api.mail.asender.net/mailboxes/id_AQUI/messages/batch' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'
POST /mailboxes/{id}/messages/parecidos

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

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).

Respostas

códigosignificado
200critérios
400sem ids
404Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).

Exemplo

curl -X POST 'https://api.mail.asender.net/mailboxes/id_AQUI/messages/parecidos' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'
GET /mailboxes/{id}/threads/{threadId}

Conversa agrupada (threading, M-C)

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 é usadaGET /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

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).
threadIdpath sim

Respostas

códigosignificado
200ok
404Recurso 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 é usadaPOST /mailboxes/{id}/drafts.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).

Respostas

códigosignificado
201criado
404Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).

Exemplo

curl -X POST 'https://api.mail.asender.net/mailboxes/id_AQUI/drafts' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'
DELETE /mailboxes/{id}/drafts/{draftId}

Descartar rascunho

Onde é usadaDELETE /mailboxes/{id}/drafts/{draftId}.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).
draftIdpath sim

Respostas

códigosignificado
204descartado
404Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).

Exemplo

curl -X DELETE 'https://api.mail.asender.net/mailboxes/id_AQUI/drafts/draftId_AQUI' \
  -H 'Authorization: Bearer SEU_TOKEN'
GET /mailboxes/{id}/drafts/{draftId}

Retomar rascunho

Onde é usadaGET /mailboxes/{id}/drafts/{draftId}, disparado ao abrir um item da pasta Rascunhos. Não-rascunho/outra caixa -> 404.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).
draftIdpath sim

Respostas

códigosignificado
200ok
404Recurso 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/drafts/draftId_AQUI' \
  -H 'Authorization: Bearer SEU_TOKEN'
PUT /mailboxes/{id}/drafts/{draftId}

Atualizar rascunho

Onde é usadaPUT /mailboxes/{id}/drafts/{draftId}.

Parâmetros

nomeemobrigatóriodescrição
idpath simid da caixa; o acesso é conferido contra a chave (deny-default).
draftIdpath sim

Respostas

códigosignificado
200ok
404Recurso inexistente ou fora do escopo da chave (não revela existência em outra conta).

Exemplo

curl -X PUT 'https://api.mail.asender.net/mailboxes/id_AQUI/drafts/draftId_AQUI' \
  -H 'Authorization: Bearer SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: <uuid-v4>' \
  -d '{ }'

Resumo

GET /v1/resumo

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 é usadahub (asender_plataforma_bff /api/resumo) e a Visão geral do webmail.
Efeitosduas leituras (store.ResumoDoUsuario), nenhuma escrita. Tenant e usuário vêm do principal que o middleware verificou — nunca da query.

Parâmetros

nomeemobrigatóriodescrição
periodoquery nãojanela dos indicadores — os N últimos dias fechados em hoje (UTC). Padrão 30d.

Respostas

códigosignificado
200o resumo da ferramenta `mail`.
400Parâmetro de query fora do conjunto aceito.
401API key ausente ou inválida.
403membro da conta sem acesso a esta ferramenta.
404Recurso 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'