Referência da API
A API HTTP do MillionSend — compatível com Resend, gerada a partir do código do servidor.
As páginas de endpoint desta seção são geradas a partir das próprias definições de rota da API no momento do build, então sempre refletem o código. A especificação bruta está em /openapi.json (OpenAPI 3.1). As páginas de endpoint estão disponíveis apenas em inglês.
URL base
https://api.millionsend.com
Autenticação
Todo endpoint exige uma chave de API criada no painel, exceto o webhook de ingestão de eventos do SES e os links de download assinados dos e-mails recebidos:
Authorization: Bearer ms_...Chaves têm um nível de permissão: chaves de acesso total podem usar todos
os endpoints, chaves de somente envio ficam confinadas a /emails*
(qualquer outra coisa retorna 403 restricted_api_key) — e mesmo ali,
GET /emails, GET /emails/{id} e DELETE /emails/{id} exigem acesso
total, já que as leituras devolvem os corpos armazenados e todo o arquivo da
equipe, e o mesmo vale para todo endpoint /emails/receiving. Uma chave
também pode ficar restrita a um único domínio, limitando de quais endereços
from ela pode enviar e quais e-mails recebidos ela lê.
Uma chave de acesso total pode, em vez disso, ficar restrita a uma
caixa de entrada (inbox_id): ela só lê e
trabalha nessa caixa, só envia pelo endereço dela e recebe
403 restricted_api_key em todas as outras rotas, inclusive a de criar
chaves. Veja
Chaves de API restritas a uma caixa.
Uma chave criada com POST /api-keys nunca é mais ampla que a chave que a
criou. Uma chave restrita a um domínio cria chaves restritas ao mesmo domínio:
um domain_id omitido ou nulo herda esse domínio, e qualquer outro domínio
retorna 403 restricted_api_key.
Compatibilidade com Resend
Os formatos de requisição e resposta correspondem aos da API do Resend, então
os SDKs oficiais do Resend funcionam contra o MillionSend apontando a URL
base para ele. O CI executa o pacote oficial resend do npm contra todos os
endpoints como um teste de conformidade. As poucas diferenças restantes são
deliberadas e explícitas:
- Anexos aceitam apenas
contentem base64 inline — uma URL empathé rejeitada com422(nunca é buscada). Um anexo comcontent_idé uma imagem inline que o HTML referencia comocid:<content_id>, e pode deixarfilenamede fora ou nulo. Os anexos podem somar até 10 MiB por e-mail (no Resend, 40 MB), e o e-mail inteiro precisa caber nos 40 MB do SES do jeito que sai; um maior é recusado com422. Arquivos de programa também são recusados; veja Anexos. - O recebimento é suportado (beta):
GET /emails/receiving,GET /emails/receiving/{id}comhtml_format, os endpoints de anexos, os links de download assinados de uma hora, o webhookemail.receivedecapabilities.receivingcom um registroReceivingnos domínios — entãoresend.emails.receiving.*,forward()incluído, funciona sem mudanças. Ocapabilities.sendingde um domínio éenabled(pedir para desligá-lo dá422), menos no subdomínio compartilhado abaixo enquanto a instância pausa o envio pelo domínio compartilhado. O recebimento exige um domínio verificado, entãoPOST /domainscomcapabilities.receiving: "enabled"dá422: verifique o domínio e depois ligue o recebimento comPATCH /domains/{id}.GET /emails/receivingsemlimitdevolve 20 e-mails, não todos, e um HTML que passaria de 40 MB com as imagens inline (no Resend, 100 MB) vem com as referênciascid:(html_format: "cid"). Diferente do Resend, um domínio de recebimento só recebe nos endereços das caixas de entrada dele, a não ser que o pega-tudo esteja ligado (receiving_catch_all, um recurso pago na nuvem); os outros endereços são recusados durante a conversa SMTP. Os e-mails recebidos ganham campos de extensão (screening,spam_verdict,virus_verdict,extracted_text,extractede outros), otextvem sem caracteres invisíveis, e o e-mail infectado fica retido, com os downloads respondendo410 email_blocked. O MillionSend acrescenta long-polling (?wait=),POST /emails/receiving/{id}/replye/forwardpelo servidor, eDELETE /emails/receiving/{id}. Veja Recebimento. - As caixas de entrada são suportadas (beta): os 26 endpoints do
pré-lançamento das Inboxes do Resend, em
/inboxes, com os mesmos caminhos e formatos, entãoresend.inboxes.*doresend@6.32.1-preview-inboxes.6funciona. Criar uma caixa ou um rascunho devolve o objeto inteiro; oemail_addresspode ficar de fora para um endereço no domínio compartilhado; okindpadrão éagent; as configurações do agente hospedado devolvem um agente vazio noGETe422noPATCH; a busca de conversas só procura nos assuntos, nos remetentes e nos destinatários; e uma resposta, um encaminhamento ou um envio de rascunho que as regras da caixa retêm responde202com o rascunho em vez de200com o e-mail. As extensões são só campos e endpoints extras, nunca valores novos nos enums do Resend. Veja Caixas de entrada → Compatibilidade com o Resend. - Numa instância com domínio compartilhado das caixas, o
GET /domainstermina com o subdomínio da sua equipe nele. Todo domínio traz oshared, e essa linha vem comshared: true, mais osending_mode(open,reply_onlyoureceive_only) e osending_mode_reason(plan,instanceounull); ocapabilities.sendingdela vemdisabledenquanto a instância pausa o envio pelo domínio compartilhado. Ela é só de leitura:PATCH, verificação eDELETErespondem403 forbidden. Como ela vem por último, um cliente que pega o primeiro domínio verificado para ofromcontinua pegando um domínio da própria equipe sempre que a equipe tem um verificado. Para uma equipe sem nenhum domínio próprio verificado, ela é o primeiro domínio verificado da lista, e só o endereço de uma caixa envia por ela, então um cliente assim deve pular as linhas comshared: true. OPOST /inboxesaceita o id dela comodomain_id. Veja Domínios → Subdomínio compartilhado. - Contatos são globais à equipe — os endpoints de audience são servidos como aliases de segments, e os endpoints de contato funcionam com ou sem id de audience (veja Contatos).
- As propriedades de contato aceitam um terceiro tipo,
date, além destringenumberdo Resend. Só uma equipe que define uma propriedade assim o vê: os valores dela voltam deGET /contacts/{id}como{ "type": "date", "value": "2026-01-08" }, um tipo que os tipos do SDK do Resend não listam. Veja Contatos → Tipos de propriedade. POST /domainsaceita umregionopcional, que precisa ser uma das regiões do SES que a instalação atende — os valores que o schema da requisição lista, a primeira sendo a padrão — e é recusado com422caso contrário. Um domínio tem uma região: para mudá-la, exclua o domínio e adicione de novo.- Transmissões (
/broadcasts) suportamcanceled, um status fora da união do Resend, e o envio de transmissão,POST /emailsePOST /emails/batchpodem retornar403 sending_pausedquando sua taxa de bounce ou reclamação cruza os limites a partir dos quais o SES age, e o envio de transmissão também enquanto o envio da equipe está pausado aguardando revisão. Só o envio de transmissão também pode retornar403 broadcasts_pausedenquanto a taxa agregada da plataforma na região SES do remetente se recupera: uma taxa de bounce recusa todas as equipes da região, uma taxa de reclamações só as equipes cuja própria taxa de reclamações nos últimos 30 dias é de 0,1% ou mais. Não afeta e-mail transacional e se resolve sozinho. - O envio de uma transmissão responde com
finishes_at(o instante estimado em que o último e-mail sai, ounull),estimated: truee, quando a audiência passa da capacidade disponível agora, umwarning(pacedouqueued_behind, comdayse uma mensagem). De um domínio com o aquecimento ligado, owarningéwarming_up, comdays: 0enquanto o aquecimento está pausado. De um domínio sob o limite de domínio novo, a estimativa segue o calendário do limite e owarningénew_domain_limit. As leituras de transmissão trazemsent_counte umfinishes_atao vivo, e um cancelamento responde comcanceled_remaining. Uma audiência que precisa de mais de 24 dias de capacidade, ou de aquecimento do domínio, é recusada com422 broadcast_too_large. O limite de domínio novo sozinho nunca recusa uma. Veja Transmissões. POST /emailsePOST /emails/batchretornam429 daily_quota_exceededem um plano diário (Free, Starter) quando a cota diária de envio acabou e a fila de espera está cheia — tente de novo depois da virada do dia em UTC — e429 monthly_quota_exceededem um plano mensal (Pro, Scale) no volume incluído com o excedente desligado, ou enquanto um pagamento está pendente (o excedente fica pausado até a fatura ser paga); ative o excedente ou pague a fatura em Cobrança, ou espere o período renovar (a mensagem informa a data). Um lote é aceito ou recusado por inteiro. Em qualquer plano, um domínio ainda sob o limite de domínio novo responde o mesmo429 daily_quota_exceeded, com uma mensagem que cita esse limite, quando já há muito e-mail aguardando. As duas recusas diárias trazem um headerRetry-Aftercom os segundos que faltam para as 00:00 UTC.- Um e-mail que o
limite de domínio novo
segura continua sendo aceito, e
POST /emails, ou o item dele emPOST /emails/batch, responde com umwarning:codenew_domain_limit, umamessageesends_after, o horário mais cedo em que ele sai.GET /emails/{id}eGET /emailsmantêmlast_event: "queued"para um e-mail que espera, como os clientes do Resend esperam, e acrescentamqueued_reason(new_domain_limit,warming_up,daily_quota,monthly_quotaoucapacity, enullquando ele não está esperando) esends_after(nullquando não há horário conhecido, como emcapacityewarming_up). Clientes que não conhecem esses campos simplesmente os ignoram. POST /contacts,POST /contacts/batche o alias de audience retornam403 plan_limit_reachedquando um contato novo levaria a equipe além do limite de contatos do plano (1.000 no Free; planos pagos são ilimitados). Contatos existentes continuam sendo atualizados; em um lote só os novos falham.GET /usageexiste (o Resend não tem endpoint de uso): o plano efetivo, seus limites (emails_per_dayem planos diários,emails_per_monthem planos mensais,domains,contacts,inboxes), o total aceito hoje e, em um plano mensal, um objetoperiod—emails_sent,included,overage_enabled,overage_usd_per_1k,starts_at,ends_at. Instâncias auto-hospedadas reportamcloud: falsecom plano, limites e period nulos.DELETE /emails/{id}existe (o Resend não tem exclusão de e-mails).headerspersonalizados seguem uma lista de permitidos: qualquer nomeX-*(excetoX-SES-*eX-MillionSend-*) maisIn-Reply-To,References,Importance,Priority,Comments,Keywords,Organization,OTP-Tokene o par de descadastro em um clique —List-Unsubscribe(um ou mais alvos<https://…>ou<mailto:…>) comList-Unsubscribe-Post(List-Unsubscribe=One-Click); qualquer outro é422. Os dois vêm juntos, eList-Unsubscribeprecisa de um alvohttps. Em um envio comtopic_id, o par que você informa substitui o gerado: os pedidos de um clique passam a chegar no seu endpoint, o MillionSend não registra opt-out por eles, e um placeholder{{{UNSUBSCRIBE_URL}}}no corpo continua apontando para a página do MillionSend. O MillionSend só gera o par e preenche o placeholder quando o envio vai para um único endereço que é um contato: o link descadastra esse contato, e todo mundo emto,ccebccrecebe a mesma mensagem. Um envio para mais de um endereço sai sem o par gerado, e os placeholders são removidos.- Valores de header e assuntos em ASCII imprimível saem como você mandou,
aspas incluídas, então um valor estruturado como
OTP-Token: "123456"; origin="https://example.com"chega intacto na caixa de entrada. Um valor com texto fora do ASCII, ou com uma palavra longa demais para uma linha de header de 998 caracteres, é codificado (RFC 2047), eIn-Reply-ToeReferencessaem como<msg-id>. Um nome da lista só pode aparecer uma vez: o mesmo nome duas vezes, com maiúsculas e minúsculas diferentes, é422. - Um envio em que todos os destinatários de
toestão na lista de supressão ou saíram dotopic_idé recusado com422 all_recipients_suppressed(mensagemAll recipients are suppressed), e não com o200do Resend; destinatários removidos de um envio que ainda tem alguém são simplesmente omitidos. Quando a lista de supressão sozinha deixatovazio, oPOST /emailsguarda um e-mailsuppressedsó com os metadados e, como no Resend, dispara oemail.suppressed; cada nova tentativa com o mesmoIdempotency-Keydeixa mais um. Se quem deixatovazio é a saída do tópico, ou se a recusa vem de um item de lote ou do relay SMTP, nada fica guardado. Entradas de descadastro só contam em envios comtopic_id; bounces, reclamações e entradas manuais contam sempre. to,ccebccjuntos não podem passar de 50 destinatários, e cada endereço precisa ser uma única caixa postal — um nome de exibição contendo@é rejeitado, e endereços aceitos voltam na forma canônicaNome <usuario@host>.subjectaceita até 998 caracteres, o limite de linha da RFC 5322, emPOST /emails,POST /emails/batch, transmissões e templates: um assunto maior é recusado com422 validation_error, e o relay SMTP responde554. O Resend não documenta limite nesses casos. Respostas, encaminhamentos e rascunhos das caixas aceitam até 2.000, como no Resend.- Um destinatário cujo domínio nunca recebe e-mail, como
x@example.com,x@foo.testoux@gmail.con, é recusado com422 validation_error, tanto nos envios quanto nos contatos novos; veja Erros. - O remetente de onboarding da instância (
ONBOARDING_EMAIL_FROM;hello@mail.millionsend.comna nuvem) leva só o e-mail de onboarding do próprio MillionSend: comofromemPOST /emails,POST /emails/batchou no envio de uma transmissão ele é recusado com422 reserved_sender, com qualquer caixa de letras e qualquer nome de exibição. Envie de um domínio que você verificou. - Nomes de tag que começam com
millionsend_, com qualquer caixa de letras, são do próprio MillionSend: uma entrada detagscom um deles emPOST /emailsouPOST /emails/batché recusada com422 validation_error. - Qualquer coisa não suportada é rejeitada com
422em vez de descartada em silêncio (ex.:tlsna atualização de domínio).
Anexos
Alguns arquivos são recusados para todas as equipes, com
422 validation_error e uma mensagem com o nome do arquivo e o motivo:
-
Um tipo que o SES ou o Gmail recusam. Vale a última extensão, em maiúsculas ou minúsculas e sem pontos ou espaços no fim, e também a de dentro de um arquivo compactado (
fatura.exe.gzconta como.exe):ade adp apk app appx appxbundle asp bas bat cab cer chm cmd com cpl crt csh der diagcab diagcfg diagpkg dll dmg ex ex_ exe fxp gadget hlp hta img inf ins iso isp its jar jnlp js jse ksh lib lnk mad maf mag mam maq mar mas mat mau mav maw mda mdb mde mdt mdw mdz mjs msc msh msh1 msh1xml msh2 msh2xml mshxml msi msix msixbundle msp mst nsh ops pcd pif plg prf prg ps1 ps1xml ps2 ps2xml psc1 psc2 reg scf scr sct shb shs sys tmp url vb vbe vbs vhd vps vsmacros vss vst vsw vxd ws wsc wsf wsh xll xnk -
Um programa com qualquer nome: um executável de Windows, Linux ou macOS, ou um atalho do Windows.
-
Um ZIP, inclusive arquivos do Office, que contenha um arquivo com uma dessas extensões.
-
Um
content_typede programa:application/x-msdownload application/x-msdos-program application/x-dosexec application/x-ms-dos-executable application/vnd.microsoft.portable-executable application/x-executable application/x-elf application/x-mach-binary application/x-msi application/x-ms-installer application/x-ms-shortcut application/x-mswinurl application/hta application/x-bat application/x-csh application/javascript application/x-javascript text/javascript application/ecmascript text/ecmascript text/vbscript application/java-archive application/x-java-archive application/x-java-jnlp-file application/vnd.android.package-archive application/x-apple-diskimage application/x-iso9660-image application/vnd.ms-cab-compressed application/x-msaccess application/vnd.ms-htmlhelp -
Um nome de arquivo com um caractere que muda a direção do texto (U+202A a U+202E, U+2066 a U+2069, U+200E, U+200F, U+061C), como o que inverte o texto e faz um
.exeaparecer como.pdf. Outros caracteres invisíveis, como os que unem letras em nomes persas e em emoji, são aceitos.
Enquanto a equipe é nova (nos primeiros 1.000 envios ou 72 horas, ou abaixo de 10.000 envios nos 7 dias seguintes ao primeiro), um e-mail com qualquer um destes é aceito, mas fica em espera até ser revisado antes do envio:
- Páginas web e imagens SVG (
htm html shtml xhtml xht mht mhtml svg svgz), pelo nome, pelocontent_typeou pelo conteúdo. - Arquivos compactados (
zip zipx rar 7z gz tgz bz2 tbz tbz2 xz txz tar zst lz lzh lha arj ace z cpio), e conteúdo compactado com qualquer nome. - Imagens de disco
vhdx; arquivos do Office com macros (docm dotm xlsm xltm xlam xlsb pptm potm ppam ppsm sldm) e qualquer arquivo do Office com um projeto VBA; OneNote (one onepkg),rtfe e-mails anexados (eml msg). - Um arquivo cujo nome não bate com o conteúdo, como um
.pdfque na verdade é um ZIP ou uma página web. - Um PDF que pede senha para abrir, ou que traz scripts, ações que abrem programas, arquivos embutidos ou formulários XFA; itens criptografados dentro de um arquivo compactado, e compactados dentro de compactados.
- Um arquivo que não dá para ler: danificado, com mais de 50 páginas ou com mais de 50 megapixels.
Equipes mais antigas enviam os mesmos arquivos sem espera; os e-mails delas são avaliados com mais frequência.
Erros
Erros usam o formato do Resend:
{ "statusCode": 422, "name": "validation_error", "message": "..." }Um corpo que não é JSON válido recebe 400 invalid_parameter, e um corpo
enviado com Content-Type diferente de application/json recebe 415.
Todo 429 traz um header Retry-After com os segundos inteiros que faltam
para a requisição passar:
| Recusa | O Retry-After conta até |
|---|---|
rate_limit_exceeded, "Too many requests" ou "Too many failed authentication attempts" | O próximo minuto. Uma chave de API faz até 600 requisições por minuto por padrão, e uma equipe 3.000; o servidor MCP permite 600 por pessoa; um IP pode errar a autenticação 20 vezes. |
rate_limit_exceeded, "Too many domains created" | A próxima hora cheia (UTC). Uma equipe adiciona até 10 domínios por hora, ou 100 no Scale. |
rate_limit_exceeded, "Too many inboxes created in the last hour" | Quando a caixa mais antiga criada na última hora completa uma hora. |
rate_limit_exceeded, "Too many names were reviewed today" ou "refused today" (POST /inboxes, PATCH /inboxes/{id}) | 00:00 UTC, quando as revisões de nomes do dia no domínio compartilhado zeram. |
daily_quota_exceeded | 00:00 UTC, quando o limite diário zera. |
monthly_quota_exceeded | O fim do período de cobrança, quando o volume mensal renova. |
As recusas de caixas de entrada na tabela abaixo dizem o próprio valor. Para um limite diário, fica assim:
HTTP/1.1 429 Too Many Requests
Retry-After: 8880
{
"statusCode": 429,
"name": "daily_quota_exceeded",
"message": "nova.example sends up to 300 emails a day for now, and 5,000 are already waiting. Retry after 00:00 UTC."
}Um caminho que a API não tem, ou um método que o caminho não aceita, recebe
404 not_found com a mensagem The requested endpoint does not exist. (o
Resend responde 405 method_not_allowed a um método errado). Um método errado
num caminho que também bate com uma rota que leva um id cai nessa rota:
GET /emails/batch vira GET /emails/{id} com o id batch e recebe
422 validation_error.
Um caractere NUL (U+0000) num texto que o banco de dados guarda, como um nome,
uma propriedade, um filtro ou um id na URL, e uma data fora dos anos 1 a 9999
recebem 422 validation_error: o banco de dados não consegue guardar esses
valores. O html e o text de um e-mail ficam guardados criptografados, então
podem ter esse caractere.
Um destinatário cujo domínio nunca recebe e-mail é recusado com
422 validation_error, e a mensagem cita o endereço:
{
"statusCode": 422,
"name": "validation_error",
"message": "x@gmail.con can never receive mail: .con is not a top-level domain. To test sending without emailing anyone, use success@simulator.amazonses.com."
}- Nomes reservados: um domínio terminado em
.test,.invalid,.example,.localhost,.local,.onion,.altou.internal, e ohome.arpacom os subdomínios dele. - Domínios de documentação:
example.com,example.neteexample.org, com os subdomínios deles. - TLDs que não existem, como
.con, ou um TLD só de números. O MillionSend conhece os TLDs reais pela Public Suffix List e consulta qualquer outro na raiz do DNS; se essa consulta falha ou demora demais, o endereço passa, então um problema de DNS nunca recusa um destinatário.
Os envios pela API, pelo servidor MCP, pelas caixas de entrada e pelo
relay SMTP checam to, cc e bcc, mas
nunca o reply_to: um item de lote falha como qualquer item inválido, um
rascunho de caixa de entrada é checado quando é enviado, e o relay responde
550 5.1.2 no RCPT TO. POST /contacts, POST /contacts/batch e o alias
de audience recusam os mesmos endereços para um contato novo. Nada do que já
está salvo muda: contatos e e-mails na fila ou agendados continuam como
estão. Uma transmissão vai para os contatos salvos sem checar os endereços
deles.
Além dos nomes do Resend, os e-mails recebidos, as caixas de entrada e o subdomínio compartilhado respondem estes:
| Status, nome | Quando |
|---|---|
403 restricted_api_key | Uma chave restrita a uma caixa fora da caixa dela, ou enviando de outro endereço; include_quarantined vindo de uma chave restrita ou do servidor MCP. |
403 inbox_send_policy | As regras de uma caixa recusam um envio: um endereço do domínio compartilhado começando uma conversa quando só pode responder (no plano Free, ou pela configuração da instância), qualquer envio por um deles enquanto a instância os pausa, um envio pelo endereço de uma caixa de agente no POST /emails, no POST /emails/batch ou no relay SMTP que as regras reteriam, ou uma transmissão por um endereço do domínio compartilhado. A mensagem diz a regra, ou lista os motivos de um envio retido. |
429 inbox_send_cap_reached | O limite diário de envios da caixa acabou, ou o limite diário da equipe para e-mails do domínio compartilhado; o retry-after conta até a meia-noite UTC. |
503 name_review_unavailable | Não deu para revisar agora um username escolhido ou um from_name no domínio compartilhado (retry-after: 60), ou o subdomínio da sua equipe no domínio compartilhado ainda espera a revisão de nomes e, até lá, nenhum endereço pode ser criado nele (retry-after: 300). |
403 approval_required | Um agente enviando um rascunho que espera aprovação. |
403 email_quarantined | Um agente lendo, respondendo ou encaminhando um e-mail retido, ou qualquer encaminhamento de e-mail infectado. |
409 held_by_screening | Uma liberação em que a análise achou injeção de prompt ou phishing: o e-mail continua na quarentena. |
403 trust_not_allowed | trust_sender na liberação de qualquer coisa que não seja um e-mail retido como not_allowlisted de um remetente verificado. |
503 screening_unavailable | A liberação feita por um cliente MCP quando a análise não pode rodar: a instância não tem avaliador, o avaliador falhou ou demorou demais, ou o limite diário de análises acabou. retry-after: 60, ou até a meia-noite UTC quando o limite acabou. |
410 email_blocked | Um download de e-mail infectado. |
429 too_many_waits | Long-polls demais ao mesmo tempo de uma equipe; retry-after: 1. |
403 validation_error | O limite de caixas do plano, com a mensagem do Resend. |
403 plan_limit_reached | Pega-tudo no plano Free. |
403 forbidden | Uma mudança, verificação ou exclusão do subdomínio compartilhado da sua equipe, que é só de leitura; um cliente MCP liberando e-mail retido por injeção de prompt, phishing, vírus ou falha na autenticação. |
404 not_found | Uma caixa, conversa, etiqueta, rascunho ou cursor de paginação desconhecido, com as mensagens do Resend (Inbox not found.). |
Idempotência
POST /emails e POST /emails/batch aceitam um header Idempotency-Key, e
os envios dos e-mails recebidos e das caixas também: respostas,
encaminhamentos e envios de rascunho das caixas, e
POST /emails/receiving/{id}/reply e /forward. Repetir com a mesma chave e
o mesmo payload retorna a resposta original em vez de enviar de novo; a mesma
chave com payload diferente retorna 409. Um envio que ficou retido para
aprovação responde à repetição com o mesmo rascunho, como 202. Um
POST /emails recusado não prende a chave: a repetição roda de novo e,
quando a lista de supressão sozinha deixa to vazio, fica guardado mais um
e-mail suppressed.
Paginação
Endpoints de listagem aceitam limit (1–100, padrão 20) e cursores after /
before carregando o id de um item de uma página anterior. As respostas
incluem has_more. As listagens vêm do mais novo para o mais antigo, como no
Resend: o after recebe o último id de uma página e avança para itens mais
antigos, o before recebe o primeiro id e volta para os mais novos, e o
has_more diz se ainda há mais itens nessa direção. Para buscar o que foi
criado desde a sua última leitura, passe no before o id mais novo que você
guardou e, depois, o primeiro id de cada página enquanto o has_more for
true. Com wait, o /emails/receiving devolve os e-mails mais novos, e
não os que vêm logo depois do cursor; veja
Esperar por e-mails novos.
Estas listagens seguem outra ordem:
| Listagem | Ordem |
|---|---|
GET /inboxes/{id}/threads e /threads/search | Da atividade mais recente para a mais antiga. |
GET /inboxes/{id}/threads/{thread_id}/emails | Do mais antigo para o mais novo: o after avança para e-mails mais novos. |
GET /inboxes/{id}/drafts | Dos atualizados mais recentemente para os mais antigos. |
GET /inboxes/{id}/labels | Das mais antigas para as mais novas, todas de uma vez, sem has_more. |
GET /topics e /contacts/{id}/topics | Dos mais antigos para os mais novos, todos de uma vez; o has_more é sempre false. |
GET /emails/receiving/{id}/attachments | Na ordem em que estão no e-mail, todos de uma vez, a não ser que você passe limit. |
O GET /domains coloca o
subdomínio compartilhado
da sua equipe depois de todos os seus domínios, como se ele fosse o mais
antigo, e o id dele é um cursor como qualquer outro: um after com ele
devolve uma página vazia, e um before com ele devolve os seus domínios
mais antigos, a página logo acima dele. Buscar o que é novo funciona do
mesmo jeito.
Um cursor que não aponta nenhum item da listagem responde
422 validation_error; em /inboxes, responde 404, como no Resend. Isso
vale também quando o item do id que você guardou foi apagado ou revogado
depois e, em /emails/receiving, quando ele não bate mais com os seus
filtros: para retomar, leia de novo do começo, sem cursor, até chegar aos
itens que você já tem.
Links de download assinados
E-mails recebidos trazem links de download em vez dos bytes:
raw.download_url em GET /emails/receiving/{id} e download_url em cada
anexo que os endpoints de anexos devolvem. São URLs GET comuns na origem
da API, /receiving/raw/{email_id} e
/receiving/attachments/{email_id}/{attachment_id}, com expires (segundos
Unix) e signature na query. Não precisam de chave de API, valem por uma
hora (expires_at) para um e-mail e um anexo de uma equipe, e respondem 403
depois de expirar ou se forem alterados; peça links novos à API. Uma mensagem
com vírus responde 410 email_blocked no lugar, para sempre. Veja
Recebimento → Downloads.