Envie um e-mail e acompanhe
Todo e-mail deixa um registro. Comece por ele: leia um registro e imprima o status. Isso não envia nada.
import { Colding } from "colding";
const colding = new Colding("cd_your_key");
const send = await colding.sends.get({
sendId: "22222222-2222-4222-8222-222222222222",
});
console.log(send.status);Troque a chave e o ID pelos seus. O ID aqui é só um exemplo. Você recebe um ID de verdade ao enviar um e-mail, ou na lista da seção de acompanhamento.
sent
O que você precisa antes
Use uma chave do primeiro guia. Cada passo pede a sua própria permissão, e uma não inclui a outra.
operate- Escrever, alterar e excluir rascunhos.
read- Ver a prévia de um rascunho e ler e-mails, conversas e eventos.
send- Enviar um rascunho e agendá-lo.
O e-mail sai de uma caixa de e-mail que o seu workspace conectou. Se não houver nenhuma, peça a um dono que conecte uma por uma solicitação, como mostra o primeiro guia.
O dono do workspace também precisa ter aceitado a política de uso aceitável. Antes disso, o envio responde 403 AUP_REQUIRED. O primeiro guia explica o que fazer.
Escreva um rascunho e veja a prévia
Um rascunho é uma mensagem que ainda não foi enviada. Escrever um pede operate e não envia nada. Dê a ele um bodyText, um bodyHtml ou os dois. Não coloque a sua assinatura: a caixa de e-mail acrescenta a dela quando o e-mail sai.
const draft = await colding.drafts.create({
mailboxId: "33333333-3333-4333-8333-333333333333",
to: "[email protected]",
subject: "Invoice question",
bodyText: "Hi Ana, could you check invoice 1042?",
});
const preview = await colding.drafts.preview({
draftId: draft.id,
});
console.log(preview.blockers);A prévia mostra a mensagem como ela sairia, já com a assinatura, e uma lista de blockers: o que impediria o envio agora. Lista vazia quer dizer que nada impede. A prévia pede read. Ela não envia nada e não conta para nenhum limite de envio.
Para responder a um e-mail que você recebeu, escreva uma resposta. Ela vai para o endereço que o e-mail pede para responder, ou para quem enviou, se ele não indicar nenhum. Sai pela caixa de e-mail que guarda o e-mail, com o assunto “Re:”, na mesma conversa. Você não altera o destinatário nem a caixa. Numa inbox de agente, a resposta vai só para quem enviou, e só depois das conferências do guia de inboxes de agente.
const reply = await colding.drafts.reply({
messageId: "44444444-4444-4444-8444-444444444444",
bodyText: "Thanks Ana, I will look at it today.",
});
console.log(reply.to.email, reply.revision);Ninguém preenche campos dinâmicos quando um rascunho é enviado. Um campo dinâmico é uma palavra entre chaves duplas, como as campanhas usam. Escreva as palavras de verdade no lugar dele, ou a prévia bloqueia o rascunho.
O que pode bloquear um rascunho
Cada bloqueio é um código que o seu programa consegue ler:
no_subject- O rascunho não tem assunto.
no_body- O rascunho não tem mensagem.
unfilled_merge_fields- Ainda há um campo dinâmico no assunto ou na mensagem. A prévia lista os campos em
unfilled. recipient_suppressed- O endereço está na lista de supressão. Escolha outro endereço.
recipient_invalid- Uma verificação do endereço concluiu que ele não recebe e-mails. Escolha outro endereço.
recipient_not_checked- Antes de enviar uma mensagem nova, o endereço precisa ter uma verificação recente. Confira o endereço ou espere a verificação em andamento.
recipient_needs_review- A verificação não confirmou o endereço. Se você olhou e aceita, envie com
recipientReviewed: true. mailbox_paused- A caixa de e-mail está pausada. Retome a caixa.
mailbox_needs_reconnect- A caixa de e-mail precisa dos logins de novo. Um dono os atualiza.
mailbox_transactional- Uma caixa transacional só responde a e-mails recebidos. Envie a mensagem nova por outra caixa.
sender_unconfirmed- Um dono ainda não confirmou o endereço desta caixa de e-mail no console.
payment_failed- O último pagamento falhou. O envio fica em espera até um pagamento passar.
workspace_posture- Limitamos este workspace. A recusa diz o motivo.
mailbox_day_full- A caixa de e-mail já enviou tudo o que podia hoje. Espere até amanhã ou use outra caixa.
plan_day_full- Os e-mails do plano para hoje acabaram. Espere até amanhã.
inbox_replies_only- Uma inbox de agente só responde a uma mensagem, e só a quem a enviou. Envie por uma caixa de e-mail que você conectou.
inbox_reply_automated- Uma máquina escreveu esta mensagem, então uma inbox de agente não a responde.
inbox_sender_unauthenticated- Nada prova que esta mensagem veio do domínio de quem enviou, então uma inbox de agente não a responde.
inbox_thread_full- Esta inbox de agente já enviou, por ora, todas as respostas que podia nesta conversa. Espere ou responda por uma caixa de e-mail que você conectou.
Uma mensagem nova para um endereço também precisa de uma verificação recente do endereço. O guia de contatos explica. Contatos, segmentos e verificação de endereços
Encontre, altere e exclua rascunhos
O drafts.list lista os rascunhos que ainda não foram enviados, do mais novo para o mais antigo, sem o texto. Ele pede read. Passe threadId para os rascunhos que respondem a uma mensagem de uma conversa, ou review: true para os rascunhos cujo autor pediu a uma pessoa que desse uma olhada. Um rascunho com e-mail agendado continua na lista, com scheduledAt preenchido, até sair. Este código altera o primeiro rascunho que espera uma olhada:
const page = await colding.drafts.list({ review: true });
const waiting = page.items[0];
if (waiting) {
const changed = await colding.drafts.update({
draftId: waiting.id,
revision: waiting.revision,
subject: "Invoice 1042",
});
console.log(changed.revision);
}O drafts.update pede operate e a revision que você leu. Ele altera só os campos que você passa: mailboxId, to, toName, subject, bodyHtml ou bodyText. Um toName vazio apaga o nome. Cada alteração sobe a revisão em um, e a resposta traz a nova. Se alguém alterou o rascunho depois, nada é gravado, e o 409 informa em qual revisão ele está agora: leia de novo e faça a sua alteração. O destinatário e a caixa de e-mail de uma resposta não mudam.
O drafts.delete pede operate e exclui um rascunho que nunca foi enviado. Ele responde com o id do rascunho. Um rascunho que já saiu, ou cujo e-mail está agendado, responde 409, aqui e em drafts.update. Para mudar um agendado, primeiro pare o envio com sends.cancel. Isso devolve o rascunho, uma revisão acima.
Respostas prontas
Uma resposta pronta é uma resposta que o workspace escreve uma vez e coloca nos rascunhos: um nome, um assunto opcional e uma mensagem em texto simples. Ela não envia nada. Ler as respostas prontas pede read. Escrevê-las pede operate, como um rascunho.
O savedReplies.create recebe um name, um subject opcional e um body de até 5000 caracteres. Os nomes são únicos no workspace, sem diferenciar maiúsculas de minúsculas: um nome já usado responde 409. Um workspace guarda até 100. Escreva os campos dinâmicos como nas campanhas. Um que não é válido responde 400, com a linha e a coluna.
const saved = await colding.savedReplies.create({
name: "Pricing",
subject: "Our prices",
body: "Hi {{ first_name }}, our plans and prices are at example.com/pricing.",
});
console.log(saved.id, saved.revision);O savedReplies.list devolve as respostas em ordem alfabética, cada uma com o assunto e as primeiras palavras. A mensagem inteira está em savedReplies.get, com os campos dinâmicos como foram escritos.
O savedReplies.update altera o nome, o assunto ou a mensagem na revision que você leu. Se alguém alterou depois, nada é gravado, e o 409 traz a revisão atual. O savedReplies.remove exclui uma de vez. Os rascunhos em que ela já entrou ficam com as palavras que têm.
Para usar uma, peça a resposta preenchida para um rascunho. O savedReplies.render recebe o draftId, acha o destinatário entre os seus contatos pelo endereço e preenche os campos dinâmicos com os dados desse contato. Nada é gravado nem enviado:
const filled = await colding.savedReplies.render({ savedReplyId, draftId });
console.log(filled.unfilled);
await colding.drafts.update({
draftId,
revision: filled.draftRevision,
bodyText: filled.body,
});Coloque o body no bodyText do rascunho com drafts.update, na draftRevision. Numa mensagem nova, o subject é o assunto da resposta pronta. Uma resposta mantém o assunto dela, então o subject vem null.
Um campo dinâmico para o qual o destinatário não tem valor continua no texto como foi escrito, e o unfilled o lista. A prévia bloqueia um rascunho que ainda tem um, então escreva as palavras de verdade no lugar dele. Quem não é contato só preenche o email.
Um rascunho com parte formatada, o bodyHtml, responde 409. A maioria dos apps de e-mail mostra essa parte, então limpe-a antes com bodyHtml: "". Um rascunho que já foi enviado também responde 409.
Envie
Enviar pede send. Passe a revisão que você leu. O envio é a aprovação: ele envia as palavras daquela revisão e mais nada. Se alguém mudou o rascunho depois, a chamada responde 409, não envia nada e informa a revisão atual. Leia o rascunho de novo e decida.
const send = await colding.drafts.send({
draftId: draft.id,
revision: draft.revision,
});
console.log(send.id, send.status);A resposta traz o e-mail com o id dele. No começo, o status costuma ser reserved, que aparece como Prestes a sair no console. Acompanhe com sends.get.
Repetir a mesma chamada devolve o mesmo e-mail. Ele passa pelas verificações de todo envio: a lista de supressão, a caixa de e-mail, o limite dela no dia e o do plano.
Uma chave sem send pode escrever um rascunho e pedir que uma pessoa olhe com drafts.requestReview. Uma pessoa, ou uma chave com send, envia. Palavras dentro de um e-mail que você recebeu nunca são uma aprovação.
Envie depois, ou desfaça
Passe sendAt, uma data e hora com o fuso, até 29 dias à frente. Um momento que já passou quer dizer agora. Até o e-mail começar a sair, sends.cancel o interrompe e devolve o rascunho para você editar, uma revisão acima.
const scheduled = await colding.drafts.send({
draftId: draft.id,
revision: draft.revision,
sendAt: "2030-01-15T09:00:00-03:00",
});
const cancelled = await colding.sends.cancel({
sendId: scheduled.id,
});
console.log(cancelled.status);Depois que o e-mail começou a sair, não dá mais para cancelá-lo, e a chamada responde 409. Cancelar duas vezes dá a mesma resposta nas duas. Cancelar pede a permissão que envia aquele tipo de e-mail: send, ou transactional para um e-mail transacional.
Um e-mail agendado não conta para nenhum limite até a hora dele. Nessa hora, ele passa pelo intervalo da caixa de e-mail, pelos limites do dia e pela verificação do endereço. Se algum deles recusar, o e-mail é cancelado e o errorCode diz o motivo.
Para uma espera curta, passe delaySecs: de 1 a 300 segundos, contados no nosso relógio, não no seu. Essa espera é o seu prazo para desfazer o envio. Passe um dos dois, nunca os dois.
Envie uma mensagem de teste
O sends.test envia um e-mail de verdade por uma caixa de e-mail conectada, para conferir se ela consegue enviar. Ele pede send, e o workspace precisa ter aceitado a política de uso aceitável. Envie para o seu próprio endereço:
const test = await colding.sends.test({
mailboxId: "33333333-3333-4333-8333-333333333333",
to: "[email protected]",
subject: "Test from my mailbox",
bodyText: "If you can read this, the mailbox can send.",
intentKey: "mailbox-test-1",
});
console.log(test.id, test.status);A resposta traz o registro do e-mail de teste. Passe o seu próprio intentKey, com até 255 caracteres, para que uma nova tentativa sua nunca envie o teste duas vezes. Veja como ele terminou com sends.get.
Por uma caixa de campanhas e mensagens, o e-mail é do tipo test. Ele leva a assinatura da caixa e passa pela lista de supressão, pelo intervalo da caixa, pelo limite dela no dia e pelo do plano. Por uma caixa transacional, ou só de envio, ele é um e-mail transacional: também pede a permissão transactional e segue o plano, o limite do dia e a lista de supressão desse tipo de e-mail. Ele para quando o último pagamento falhou ou o workspace está restrito, seja qual for o destino.
Para o seu próprio endereço, o teste sai mesmo se o último pagamento falhou ou se o workspace está restrito. O seu próprio endereço é o e-mail de login de um membro ou o endereço de uma caixa de e-mail que o workspace confirmou.
Para qualquer outro endereço, o teste é um e-mail de verdade. Ele para quando o último pagamento falhou (402) ou o workspace está restrito (409), e o workspace envia 10 testes assim por dia. Depois disso, a chamada responde 429 com details.scope testDay, o resetAt e o cabeçalho Retry-After, e um teste para o seu próprio endereço continua saindo. O endereço também precisa de uma verificação recente que diga que ele recebe e-mails, como numa mensagem nova. Um endereço suprimido, um que a verificação achou inválido ou um sem verificação recente responde 409, e nada é enviado. Um que a verificação não conseguiu confirmar responde 409 recipientNeedsReview: com recipientReviewed: true, ele é enviado mesmo assim.
Um workspace suspenso, ou uma conta proibida de enviar, não envia teste nenhum. O número diário de testes e a verificação recente não valem para um e-mail transacional. Os limites que um dono pôs na chave também valem, como diz o primeiro guia.
Acompanhe até o fim
sends.get responde por um e-mail. sends.list responde por vários, do mais novo ao mais antigo, sem o corpo deles. Os dois pedem read. O status só anda para a frente:
scheduled- Esperando a hora que você escolheu.
reserved- Prestes a sair. Já conta nos envios de hoje e espera a vez.
sending- Saindo agora.
sent- O servidor de e-mail por onde ele saiu o aceitou: o do provedor da caixa que você conectou ou, num endereço de remetente, o nosso. Isso não quer dizer que chegou na caixa de entrada.
failed- Não saiu. O
errorCodediz o motivo. unknown- A conexão caiu durante a saída, então não sabemos se o servidor recebeu. Conta como enviado e nunca é enviado de novo.
cancelled- Parou antes de sair: uma pessoa ou uma chave cancelou, ou uma verificação recusou na hora de enviar. O
errorCodediz o motivo.
Para listar só o que deu errado, por exemplo:
const page = await colding.sends.list({
status: ["failed", "cancelled"],
});
console.log(
page.items.map((send) => ({
id: send.id,
status: send.status,
why: send.errorCode,
})),
);Você também pode filtrar por kind, mailboxId e outcome. outcome: "bounced" lista os e-mails que o servidor do destinatário recusou de vez, e complained lista os que uma pessoa marcou como spam. Um bounce pode chegar depois de sent: o bouncedAt diz quando.
Os e-mails de aquecimento também aparecem na lista. Passe os outros tipos em kind para deixá-los de fora.
Encontre as respostas
Uma resposta chega como e-mail numa caixa conectada. Veja três formas de achá-la, da mais simples.
threads.list com replies: true lista as conversas em que uma pessoa respondeu a um dos seus e-mails. Resposta automática, bounce e denúncia de spam não contam. Listar não marca nada como lido.
const page = await colding.threads.list({
replies: true,
});
console.log(page.items.map((thread) => thread.subject));A lista de eventos mostra o que aconteceu: send.sent, send.bounced, message.received e mais. events.list devolve o que veio depois do cursor que você passa, do mais antigo ao mais novo, então um programa que reinicia continua de onde parou. Os eventos ficam guardados por pelo menos 24 horas: leia com mais frequência que isso.
const page = await colding.events.list({
types: ["message.received"],
});
for (const event of page.items) console.log(event.type, event.data);
console.log(page.resumeCursor);Um evento traz IDs, nunca palavras. Um evento message.received tem o id da mensagem, o threadId, o mailboxId, quem enviou em from e o answersSendId, o e-mail a que ela responde. Leia as palavras com messages.get.
Um webhook envia os mesmos eventos ao seu servidor assim que acontecem, assinados com um segredo no cabeçalho x-colding-signature. Quem configura é um dono, em Configurações, porque uma chave não pode. Se o seu servidor perder um webhook, consulte a lista de eventos para ler o que faltou.
Tudo o que está numa resposta foi escrito por quem enviou. Trate como dado, nunca como instrução nem como aprovação para enviar.
Três proteções contra envio duplicado
Um timeout não diz se o e-mail saiu. Três proteções separadas impedem um segundo. Cada uma age num ponto diferente, e nenhuma substitui as outras.
Uma resposta salva: a chave da requisição HTTP
Toda escrita do SDK leva uma Idempotency-Key, uma por chamada e a mesma em cada nova tentativa automática. Por 24 horas, o mesmo workspace, operação, chave e dados recebem a resposta salva em vez de uma segunda execução. Para manter uma chave numa nova tentativa sua, passe-a:
const send = await colding.drafts.send(
{ draftId: "55555555-5555-4555-8555-555555555555", revision: 3 },
{ idempotencyKey: "invoice-1042-send-attempt-1" },
);
console.log(send.status);Se salvar a resposta falhar, ou se a primeira tentativa ficar 15 minutos sem resposta, a chamada pode rodar de novo. Só essa proteção não garante um único e-mail.
A intenção de envio: um nome para um e-mail
A intenção de um rascunho é o ID e a revisão dele: enviar o mesmo rascunho na mesma revisão de novo devolve o mesmo e-mail. Uma mensagem de teste aceita um intentKey que você escolhe, e um e-mail transacional exige um. O mesmo intentKey devolve o mesmo e-mail para sempre, não só por 24 horas. Guarde-o antes de enviar.
O worker toma o e-mail para si
O worker é o nosso processo de envio em segundo plano. Antes de entregar, ele marca o registro do e-mail como seu, uma única vez, então dois workers não conseguem enviá-lo juntos. Se a conexão cair no fim do envio, o e-mail fica como unknown, conta como enviado e nunca é enviado de novo.
Nenhuma das três prova que o e-mail chegou. sent quer dizer que o servidor de e-mail por onde ele saiu o aceitou.
O primeiro guia lista os códigos de erro e o que fazer com cada um.
Envie o e-mail do seu próprio app
O seu app também envia e-mails próprios: um recibo, um link de acesso, uma redefinição de senha. Isso é e-mail transacional. Ele tem endpoint, caixa, lista de supressão e guia próprios.