Conecte e acompanhe uma caixa
Uma caixa de e-mail é a conexão de onde você envia ou recebe mensagens. Leia os dados dela primeiro. Estar conectada, por si só, não significa que pode enviar.
Leia o estado
import { Colding } from "colding";
const colding = new Colding("cd_your_key");
const mailboxId = "22222222-2222-4222-8222-222222222222";
const mailbox = await colding.mailboxes.get({ mailboxId });
console.log(mailbox.state, mailbox.ownership.state);mailboxes.get pede read e não muda nada. Troque mailboxId por um ID de mailboxes.list() ou de mailboxIds numa conversa. O primeiro guia mostra como conseguir uma chave de API.
connected proven
connected- A caixa não está pausada e os logins não foram marcados para troca. A confirmação do endereço e as outras conferências de envio continuam valendo.
needs_reconnect- O provedor recusou o acesso. Peça ao dono para atualizar os logins no console pela solicitação abaixo.
paused- O envio está pausado. O recebimento continua enquanto os logins funcionarem. Confira
syncpara saber se os e-mails estão sendo lidos.
A resposta completa também traz provider, purpose, dailyCap, minGapSeconds, problems, domainAuth, sync, warmup e sendState. ownership diz se o endereço remetente está confirmado. sendState é uma espera para campanhas, não uma permissão para mensagem avulsa.
Senhas nunca voltam na resposta. Uma caixa só de envio também oculta o usuário SMTP, porque ele pode ser um segredo. smtp e imap podem ser null, conforme a conexão da caixa.
Peça ao dono para conectar
Antes de pedir ao dono, consulte o endereço. mailboxes.detectSettings diz quem cuida dos e-mails dele (name), quais servidores ele usa e qual senha o dono vai usar (password): normal, app_password (uma senha separada que o provedor cria para um app), app_password_with_2fa (senha de app só quando a verificação em duas etapas está ativa) ou secure_mail_key (o nome que a AT&T dá à senha de app dela). Pede read, só consulta o DNS e nunca entra na caixa.
import { Colding } from "colding";
const colding = new Colding("cd_your_key");
const found = await colding.mailboxes.detectSettings({ email: "[email protected]" });
console.log(found.name, found.password);Google app_password
accessSwitch indica uma opção que o dono precisa ativar no provedor antes: imap (acesso IMAP) ou third_party (acesso por outros apps de e-mail). signIn indica um provedor cujo próprio login conecta a caixa no lugar da senha, e unavailable diz por que nenhum login nosso chega até ela. Quando nada é encontrado, servers vem nulo e source vem none. Aí unresolved diz o motivo: dns_unanswered (o DNS não respondeu, então tente de novo) ou not_published (o dono digita os servidores no console). Cada workspace pode consultar 20 endereços por minuto.
SMTP envia e-mails e IMAP os lê. Um agente pede essa conexão por uma solicitação com link para o console, chamada handoff na API. Criar pede operate. Passe url ao dono. Quem recebe o link entra e informa os logins no console, não no chat com o agente.
const request = await colding.handoffs.create({
kind: "connect_mailbox",
});
console.log(request.url);Leia a mesma solicitação com handoffs.get, que pede read. Uma solicitação concluída indica a caixa em resultMailboxId. Leia essa caixa para ver o estado atual.
const now = await colding.handoffs.get({ handoffId: request.id });
console.log(now.status);
if (now.status === "completed" && now.resultMailboxId) {
const mailbox = await colding.mailboxes.get({ mailboxId: now.resultMailboxId });
console.log(mailbox.ownership);
}Uma solicitação fica em pending, completed, cancelled ou expired. As pendentes expiram após 24 horas. Se expirar, crie uma nova. Para retirar uma que não precisa mais, chame handoffs.cancel com handoffId. Cancelar pede operate e nunca desconecta uma caixa que já foi conectada.
Para trocar os logins, use update_mailbox_credentials e informe mailboxId. O dono preenche os novos no console. Uma conferência aprovada troca os logins, mas não desfaz uma pausa da caixa.
const request = await colding.handoffs.create({
kind: "update_mailbox_credentials",
mailboxId,
});
console.log(request.url);Antes de salvar uma conexão ou novos logins, o worker confere os logins por conexões criptografadas. Um login recusado não salva nada e responde 400 VALIDATION_ERROR, com o campo e o motivo em details. O dono corrige o login indicado e tenta de novo no console. Passar só prova que os logins funcionaram naquele momento, não que o e-mail vai chegar ou que o endereço é seu.
Se a conferência não terminar em 15 segundos, ou o worker estiver indisponível, a resposta é 503 SERVICE_UNAVAILABLE, que permite tentar de novo, com messageKey: serverErrors.mailboxCheckUnavailable. Nada é salvo. Não há cabeçalho Retry-After. O dono pode repetir a conferência no console.
O SDK público não tem método para enviar logins, trocar senha, digitar código de confirmação ou desconectar. São ações do dono, feitas no console depois de entrar. O link de uma solicitação não aprova um envio.
Use SMTP nos e-mails do seu app
Uma caixa só de envio usa o login SMTP de um serviço de envio, sem IMAP. Na solicitação de conexão, peça ao dono para escolher Serviço de envio (só envio). Ela aparece como provider: smtp_only e purpose: transactional.
Ela envia e-mails transacionais do seu app, como um recibo ou link de login. Nunca envia campanhas, começa uma mensagem avulsa ou faz aquecimento. Precisa de um plano com e-mail transacional e conta no limite de caixas do plano. O serviço precisa pedir um login SMTP antes de salvarmos a caixa.
Não lemos e-mails enviados para esse endereço. As respostas vão para onde já vão os outros e-mails do seu domínio. Defina replyTo na caixa com mailboxes.update, ou no e-mail transacional, para escolher um endereço que alguém leia. Conecte uma caixa que receba mensagens se precisar dessas respostas nesta caixa de entrada.
Bounces e denúncias de spam que chegam depois precisam do webhook de relatórios do serviço de envio, configurado pelo dono no console. Uma caixa sem leitura não recebe esses relatórios pelo e-mail. Para pedir isso ao dono, crie uma solicitação manage_report_hook com o id da caixa: o dono cola o segredo do serviço no console, então você nunca o vê. O SDK lê o estado do webhook com mailboxes.reportHook e os relatórios recebidos com mailboxes.reports.
Confirme o endereço remetente
Logins funcionando não provam o endereço remetente. ownership.state é unproven (não confirmado), pending (aguardando código) ou proven (confirmado). Nada sai enquanto estiver unproven ou pending, nem respostas, testes, e-mails transacionais ou aquecimento. A leitura continua funcionando.
O dono confirma o endereço no console, em Endereço de envio, na Visão geral da caixa. Enviamos um código por e-mail para esse endereço, e o dono clica no botão do e-mail ou digita o código. Se o endereço não recebe e-mails, peça à nossa equipe para confirmar de outro jeito.
Peça à nossa equipe para confirmar um endereço
Se um código estiver pendente, ownership traz expiresAt e mail, o estado do e-mail desse código. Pendente não significa confirmado. Não há handoff para confirmar endereço nem método público do SDK para enviar código.
Mesmo com proven, enviar ainda pede a permissão aplicável, os limites da chave definidos pelo dono, a política de uso aceitável, o plano, o pagamento e as verificações do destinatário. Pausas e outras esperas da caixa continuam valendo. Use o guia de envio para a mensagem que quer enviar.
Confira a leitura e os e-mails importados
resync é Conferir agora. Pede ao worker para olhar a caixa antes da conferência normal (hoje, cerca de 60 segundos entre conferências). Pede operate. A resposta mostra como a caixa está naquele momento, não prova que a nova leitura terminou. Leia mailboxes.get de novo depois.
await colding.mailboxes.resync({ mailboxId });
const mailbox = await colding.mailboxes.get({ mailboxId });
console.log(mailbox.sync);
const folders = await colding.mailboxes.folders({ mailboxId });
console.log(folders);sync.startedAt é quando a leitura listou as pastas pela primeira vez. lastSuccessAt é a última leitura que terminou sem deixar nada em espera. Null significa que nenhuma leitura assim terminou, não que a caixa está vazia. nextAt diz quando será a próxima. failures conta falhas seguidas, e pending conta mensagens encontradas mas ainda não guardadas.
sync.import descreve a importação única dos e-mails que já existiam, do mais novo para o mais antigo. O status é pending, running ou complete. since e limit são o período e o limite de mensagens fixados quando começa. imported conta o que foi guardado, e completedAt diz quando terminou. Complete não significa que todo o histórico do provedor foi importado.
sync.folders conta as pastas encontradas e acompanhadas. mailboxes.folders lista o caminho no provedor, role, watched, excludedReason, pending e importDone de cada uma. Uma pasta que ficou de fora diz o motivo, sem fingir que foi lida. Esta chamada pede read.
Se a leitura parou por um login IMAP recusado, Conferir agora tenta primeiro os logins salvos. Um login ainda recusado responde 409: peça ao dono para trocá-lo. Se as conferências naquele servidor estiverem em espera, um 429 diz quando tentar de novo. Uma caixa só de envio responde 409 porque não recebe e-mails para ler.
Confira o domínio de envio
O domínio de envio é a parte depois do @. Registros DNS dizem aos servidores que recebem quem pode enviar por ele. checkDomain lê os registros agora e salva o resultado nas caixas deste workspace que usam o domínio. Pede operate.
const mailbox = await colding.mailboxes.checkDomain({ mailboxId });
console.log(mailbox.domainAuth);SPF e DMARC decidem se o domínio está em passing ou failing. Uma caixa só de envio é julgada só pelo DMARC. DKIM aparece como encontrado ou não verificado, nunca ausente: o DNS não lista todos os seletores, os nomes sob os quais as chaves DKIM são publicadas. Quando falta o SPF ou o DMARC, domainAuth.dnsHost diz onde fica o DNS do domínio, lido dos servidores de nomes dele: hosts lista os provedores de DNS que combinam (vazio quando não conhecemos o provedor), e o valor inteiro vem null quando o DNS não respondeu.
Se os registros exigidos continuarem falhando por 72 horas, campanhas e aquecimento deixam de usar essas caixas até uma conferência passar. failingSince é quando esse prazo começou. Corrija os registros com quem cuida do domínio e chame checkDomain de novo.
unknown significa sem conclusão, não aprovado nem reprovado. unknownReason diz se o DNS não respondeu ou o domínio é um nome reservado. Um timeout não apaga uma falha já registrada. Confira de novo quando o DNS responder. Esses registros nunca prometem entrega.
Alguns provedores de DNS conseguem adicionar o registro DMARC que falta: o dono vê o registro na própria página do provedor e aprova. Isso usa um padrão chamado Domain Connect. domainConnectLink devolve esse link. Pede operate.
const link = await colding.mailboxes.domainConnectLink({ mailboxId });
console.log(link.url ?? link.reason);A resposta traz a url e o nome do provedor em provider, ou a url nula e um motivo em reason: not_set_up (ainda não ligamos os links de um clique), not_offered (o provedor de DNS do domínio não oferece o nosso registro), unanswered (o DNS ou o provedor não respondeu a tempo, então tente de novo) ou nothing_to_add (um registro DMARC já cobre o domínio). Nenhum provedor oferece os nossos registros ainda, então por enquanto toda resposta traz um motivo e nenhum link. Entregue o link ao dono. Ele abre a página do provedor, e o provedor manda o dono de volta para o console, ou para a página do console que você indicar em returnTo (um caminho como /acme/mailboxes). Voltar não prova nada, então chame checkDomain depois. Cada workspace pode pedir 30 links por minuto.
O registro CNAME de um domínio de rastreamento tem o mesmo tipo de link: trackingDomains.connectLink recebe um trackingDomainId e responde do mesmo jeito, com nothing_to_add quando o domínio já está verificado.
Pause o envio ou desconecte
mailboxes.pause para o que sai da caixa. Campanhas e aquecimento esperam, e envios novos são recusados. E-mails continuam chegando e sendo lidos enquanto os logins funcionarem. Configurações e logins ficam. Não traz de volta um e-mail que já está a caminho. Pede operate.
const mailbox = await colding.mailboxes.pause({ mailboxId });
console.log(mailbox.state, mailbox.sync.lastSuccessAt);mailboxes.resume com mailboxId retira essa pausa. Também pede operate. Não conserta login recusado, confirma endereço nem retira uma espera separada.
Desconectar é uma ação do dono no console, sem método público do SDK nem tipo de handoff. Exclui a conexão, os logins, as configurações e as mensagens daquela caixa guardadas no colding. Os e-mails no provedor não são excluídos. Não dá para desfazer. Os bloqueios de aquecimento do endereço continuam, então reconectar não serve para retirá-los.
Inicie e leia o aquecimento
No aquecimento, sua caixa troca e-mails com um grupo de caixas chamado pool. Envia e-mail de verdade, então startWarmup pede send. O dono também precisa ter aceitado a política de uso aceitável. Pode ser ligado antes da confirmação do endereço remetente, mas nada sai até confirmar. Os limites da chave para caixas e fluxos continuam valendo. Uma chave limitada a e-mails transacionais não inicia aquecimento. Caixas só de envio e caixas pela API do Gmail nunca fazem aquecimento.
const mailbox = await colding.mailboxes.startWarmup({ mailboxId });
console.log(mailbox.warmup.state, mailbox.warmup.blockedBy);
console.log(mailbox.warmup.sentToday, mailbox.warmup.todayCap);
const days = await colding.mailboxes.warmupStats({ mailboxId });
console.log(days);Leia warmup.state, blockedBy, sentToday e todayCap na resposta. Running significa ligado, não que está enviando agora. todayCap é o limite real de hoje, considerando o tamanho do pool, os dias e a saúde. dailyTarget é a meta da rampa, não uma quantidade prometida de mensagens.
day conta tempo em aquecimento, não dias do calendário desde a conexão. rampHeldUntil diz quando termina uma espera por ter caído no spam. health traz a faixa de saúde e as leituras, ou null quando não há leitura. Uma leitura de denúncias ausente é sem dados, não zero. health.probation pode reduzir o aquecimento depois de uma quarentena ou bloqueio, mesmo quando a faixa diz saudável.
blockedBy indica o primeiro motivo a resolver: suspensão do workspace, bloqueio pela nossa equipe, endereço não confirmado, login recusado, pausa da caixa, espera por saúde, domínio ou falta de parceiras. O bloqueio da nossa equipe tem o motivo em staffBlock. Peça uma revisão com mailboxes.appealWarmup, passando mailboxId e reason. Pede operate e não libera o bloqueio por si só. Só um pedido de revisão pode ficar aguardando por vez.
mailboxes.pauseWarmup com mailboxId pausa o envio de aquecimento, mas mantém a caixa no pool e preserva a rampa. Parceiras ainda podem escrever para ela. Retome com startWarmup. mailboxes.stopWarmup sai do pool. A próxima rodada começa a rampa no primeiro dia. Pausar e encerrar pedem operate e mantêm os horários, dias e a taxa de resposta salvos. Nenhum dos dois retira a espera por saúde ou o bloqueio da equipe ligado ao endereço.
await colding.mailboxes.pauseWarmup({ mailboxId });
await colding.mailboxes.stopWarmup({ mailboxId: otherMailboxId });
const appealed = await colding.mailboxes.appealWarmup({
mailboxId,
reason: "We fixed the domain's records on 5 October.",
});
console.log(appealed.warmup.blockedBy);receiveOnly: true no primeiro início deixa parceiras escreverem para a caixa sem que ela envie aquecimento. Retome com o mesmo valor. Para mudar de modo, encerre primeiro. window e days usam o relógio do workspace.
warmupStats pede read e retorna 30 dias por padrão, incluindo hoje. Passe days para ler até 90. Cada dia diz o que saiu, o limite, o que as parceiras encontraram no spam e o que chegou aqui. Aquecimento não aparece na caixa de entrada nem gera eventos send.*. Não promete em qual pasta o e-mail vai cair.
Leia onde chegam os seus e-mails
deliverability.get pede read e responde numa só chamada, sem nota. Passe days como 7, 14 ou 30, contando hoje, no calendário do workspace. Se você não passar, vale 7. Ela lê todas as caixas e campanhas do workspace, então uma chave limitada a algumas caixas recebe 403 keyReads.
const answer = await colding.deliverability.get({ days: 14 });
for (const domain of answer.placement.domains) {
for (const row of domain.providers) {
console.log(domain.domain, row.provider, row.counts.arrived, row.counts.spam);
}
}
for (const mailbox of answer.attention.mailboxes) {
const worst = mailbox.reasons[0];
console.log(mailbox.email, worst?.reason, worst?.stops, worst?.until);
}placement é o aquecimento, por domínio de envio e provedor de destino. Cada linha de provedor conta os e-mails que arrived (chegaram), os que a caixa parceira achou no spam (parte dos arrived), os que neverArrived (nunca chegaram), os que o servidor da sua caixa recusou (bounced), os que ainda estão tooSoon para julgar e os que deixamos de fora (leftOut). A soma dá sent. atTestInboxes conta quantos dos e-mails que chegaram foram para uma caixa de teste nossa.
fromOurServers é o que os servidores de destino responderam sobre os e-mails que saíram dos nossos servidores, por stream (cold ou transactional) e provedor. Aceito quer dizer que o servidor recebeu o e-mail, não que ele chegou à caixa de entrada. noWordYet conta os e-mails que ainda não tiveram resposta. O valor é null quando o workspace não tem inbox de agente nem endereço de remetente e não enviou nada pelos nossos servidores na janela.
attention lista as caixas e as campanhas que uma das nossas regras pausou ou deixou mais lentas. Cada uma traz o motivo, o que o motivo impede (sending, first_contact, campaigns, warmup, nothing_yet ou slows_warmup) e quando começou e quando termina. A pausa que uma pessoa fez não aparece. As listas guardam 100 itens no máximo, e more conta o resto.
Uma porcentagem vem como { pct, of, bound }, e bound é under1 ou over99 quando o valor está perto de 0 ou de 100, mas não é exatamente esse número. A porcentagem só aparece a partir de 20 e-mails de aquecimento (placement.floor) ou de 50 mensagens (floor). Abaixo disso você recebe { tooFew, floor }.
As denúncias de spam são uma contagem, nunca uma porcentagem, porque a maioria dos provedores não manda nenhuma. source: false quer dizer um provedor que não conta nada ao remetente, e isso não é 0. days traz uma entrada por dia da janela, com zero onde nada aconteceu.
Responda a uma análise
Nossa equipe pode colocar uma caixa em análise, por exemplo depois de denúncias sobre os e-mails dela. Enquanto durar, review em mailboxes.get, mailboxes.list e nas leituras de inbox de agente não é null. Sem análise, é null.
Leia primeiro review.caseNumber e cite esse número quando falar com a gente. since diz quando a análise começou, e until é a data até a qual dissemos que iríamos analisar o caso. Nada é liberado quando until passa, e overdue vira true. reason traz as palavras da nossa equipe, ou null quando foi o sistema que colocou a caixa em análise. answeredAt é null até você contar o que aconteceu.
const mailbox = await colding.mailboxes.get({ mailboxId });
if (mailbox.review) {
const review = await colding.mailboxes.answerReview({
mailboxId,
whatHappened: "Our 3 September campaign went to a list we bought. Some people had not asked.",
whatChanged: "We deleted that list and paused the campaign.",
howItStaysFixed: "From now on we only write to people who signed up on our site.",
});
console.log(review.caseNumber, review.answeredAt);
}Conte o que aconteceu com mailboxes.answerReview. Passe mailboxId e três respostas com suas próprias palavras: whatHappened, whatChanged e howItStaysFixed. Cada uma tem de 1 a 2000 caracteres. Pede operate, e uma chave limitada a algumas caixas só responde por elas. A resposta é a análise, com answeredAt preenchido.
Nossa equipe lê as três respostas junto com o caso. Se você enviar de novo, a resposta anterior é substituída. Isso não libera nada: só nossa equipe encerra uma análise. Uma caixa que não está em análise responde 409, então leia review antes. Também funciona enquanto o workspace aguarda a exclusão.
Funciona para uma inbox de agente também. Passe o id da inbox como mailboxId. As leituras de inbox de agente trazem o mesmo campo review.
Acompanhe mudanças na caixa
Leia mailbox.failed, mailbox.recovered, mailbox.address_confirmed e mailbox.warmup_health_changed por events.list ou webhook. Eles indicam a caixa e a mudança, sem logins. Um evento de chegada é de e-mail novo depois do início da leitura, nunca de e-mail antigo importado.
const page = await colding.events.list({
types: [
"mailbox.failed",
"mailbox.recovered",
"mailbox.address_confirmed",
"mailbox.warmup_health_changed",
],
});
console.log(page.items);