Saltar al contenido

Conecta y sigue un buzón

Un buzón es la conexión de correo desde la que envías o recibes mensajes. Lee sus datos primero. Estar conectado no significa, por sí solo, que pueda enviar.

Lee su 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 pide read y no cambia nada. Cambia mailboxId por un ID de mailboxes.list() o de mailboxIds en una conversación. La primera guía muestra cómo conseguir una clave de API.

Ejemplo de un buzón ficticio. Está conectado y la dirección remitente está confirmada.
connected proven
connected
El buzón no está en pausa y sus datos de acceso no están marcados para reemplazo. La confirmación de la dirección y las demás comprobaciones de envío siguen vigentes.
needs_reconnect
El proveedor rechazó el acceso. Pide al dueño que actualice los datos de acceso en la consola, con la solicitud de abajo.
paused
El envío está en pausa. La recepción continúa mientras los datos de acceso funcionen. Consulta sync para ver si se está leyendo el correo.

La respuesta completa también trae provider, purpose, dailyCap, minGapSeconds, problems, domainAuth, sync, warmup y sendState. ownership dice si la dirección remitente está confirmada. sendState es una espera para campañas, no permiso para un mensaje suelto.

Las contraseñas nunca se devuelven. Un buzón solo de envío también oculta el usuario SMTP, porque puede ser un secreto. smtp e imap pueden ser null según la conexión del buzón.

Pide al dueño que lo conecte

Antes de pedírselo al dueño, consulta la dirección. mailboxes.detectSettings dice quién gestiona su correo (name), qué servidores usa y qué contraseña necesitará el dueño (password): normal, app_password (una contraseña aparte que el proveedor crea para una sola aplicación), app_password_with_2fa (contraseña de aplicación solo si la verificación en dos pasos está activa) o secure_mail_key (el nombre que AT&T da a su contraseña de aplicación). Pide read, solo consulta el DNS y nunca inicia sesión en el buzón.

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);
Ejemplo de una dirección en Google Workspace.
Google app_password

accessSwitch indica una opción que el dueño tiene que activar antes en el proveedor: imap (acceso IMAP) o third_party (acceso de otras apps de correo). signIn indica un proveedor cuyo propio inicio de sesión conecta el buzón en lugar de la contraseña, y unavailable dice por qué ninguno de nuestros accesos llega a él. Si no se encuentra nada, servers es nulo y source es none. Entonces unresolved dice por qué: dns_unanswered (el DNS no respondió, así que vuelve a intentarlo) o not_published (el dueño escribe los servidores en la consola). Cada workspace puede consultar 20 direcciones por minuto.

SMTP envía correo e IMAP lo lee. Un agente pide esa conexión con una solicitud que da al dueño un enlace a la consola, llamada handoff en la API. Crear una pide operate. Dale url al dueño. Quien recibe el enlace inicia sesión e introduce los datos de acceso en la consola, no en un chat con el agente.

const request = await colding.handoffs.create({
  kind: "connect_mailbox",
});
console.log(request.url);

Lee la misma solicitud con handoffs.get, que pide read. Una solicitud completada identifica el buzón en resultMailboxId. Lee ese buzón para ver su estado actual.

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);
}

Una solicitud está en pending, completed, cancelled o expired. Las pendientes caducan a las 24 horas. Si caduca, crea una nueva. Para retirar una que ya no necesitas, llama a handoffs.cancel con handoffId. Cancelar pide operate y nunca desconecta un buzón que ya se conectó.

Para reemplazar los datos de acceso, usa update_mailbox_credentials e indica mailboxId. El dueño introduce los nuevos en la consola. Una comprobación aprobada los reemplaza, pero no deshace una pausa del buzón.

const request = await colding.handoffs.create({
  kind: "update_mailbox_credentials",
  mailboxId,
});
console.log(request.url);

Antes de guardar una conexión o nuevos datos de acceso, el worker los comprueba por conexiones cifradas. Un acceso rechazado no guarda nada y responde 400 VALIDATION_ERROR, con el campo y el motivo en details. El dueño corrige el dato indicado y reintenta en la consola. Pasar solo prueba que los datos funcionaron en ese momento, no que el correo llegará ni que la dirección sea tuya.

Si la comprobación no termina en 15 segundos, o el worker no está disponible, responde 503 SERVICE_UNAVAILABLE, que permite reintentar, con messageKey: serverErrors.mailboxCheckUnavailable. No se guarda nada. No hay cabecera Retry-After. El dueño puede reintentar la comprobación en la consola.

El SDK público no tiene métodos para enviar datos de acceso, cambiar contraseñas, introducir códigos de confirmación ni desconectar. Son acciones del dueño con sesión en la consola. El enlace de una solicitud no aprueba un envío.

Usa SMTP para los correos de tu app

Un buzón solo de envío usa los datos de acceso SMTP de un servicio de envío, sin IMAP. En la solicitud de conexión, pide al dueño que elija Servicio de envío (solo envío). Aparece como provider: smtp_only y purpose: transactional.

Envía el correo transaccional de tu app, como un recibo o un enlace de acceso. Nunca envía campañas, inicia mensajes sueltos ni hace calentamiento. Necesita un plan con correo transaccional y cuenta para el límite de buzones del plan. El servicio debe pedir acceso SMTP antes de que guardemos el buzón.

No podemos leer el correo enviado a esa dirección. Las respuestas van adonde ya va el resto del correo de tu dominio. Define replyTo en el buzón con mailboxes.update, o en el correo transaccional, para elegir una dirección que alguien lea. Conecta un buzón que reciba mensajes si necesitas esas respuestas en esta bandeja de entrada.

Los rebotes y las denuncias de spam que llegan después necesitan el webhook de informes del servicio de envío, configurado por el dueño en la consola. Un buzón sin lectura no recibe esos informes por correo. Para pedírselo al dueño, crea una solicitud manage_report_hook con el id del buzón: el dueño pega el secreto del servicio en la consola, así que tú nunca lo ves. El SDK lee el estado del webhook con mailboxes.reportHook y los informes recibidos con mailboxes.reports.

Envía el correo transaccional de tu app

Confirma la dirección remitente

Un acceso que funciona no prueba la dirección remitente. ownership.state es unproven (sin confirmar), pending (esperando un código) o proven (confirmada). No se envía nada mientras esté unproven o pending, ni respuestas, pruebas, correo transaccional ni calentamiento. La lectura sigue funcionando.

El dueño confirma la dirección en la consola, en Dirección de envío, dentro del Resumen del buzón. Enviamos un código por correo a esa dirección, y el dueño pulsa el botón del correo o escribe el código. Si la dirección no recibe correo, pide a nuestro equipo que la confirme de otra forma.

Pide a nuestro equipo que confirme una dirección

Si hay un código pendiente, ownership incluye expiresAt y mail, el estado del correo de ese código. Pendiente no significa confirmado. No hay handoff para confirmar direcciones ni método público del SDK para enviar códigos.

Incluso con proven, enviar todavía requiere el permiso que corresponda, los límites de la clave que puso el dueño, la política de uso aceptable, el plan, el pago y las verificaciones del destinatario. Las pausas y otras esperas del buzón siguen vigentes. Usa la guía de envío para el mensaje que quieras enviar.

Lee las comprobaciones de envío

Comprueba la lectura y el correo importado

resync es Comprobar ahora. Pide al worker que mire el buzón antes de la comprobación normal (hoy, aproximadamente cada 60 segundos). Pide operate. La respuesta muestra el buzón en ese momento, no prueba que la nueva lectura terminó. Lee mailboxes.get de nuevo más tarde.

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 es cuando la lectura listó las carpetas por primera vez. lastSuccessAt es la última pasada que terminó sin dejar nada en espera. Null significa que no terminó ninguna pasada así, no que el buzón esté vacío. nextAt dice cuándo toca la siguiente. failures cuenta fallas seguidas, y pending cuenta mensajes encontrados pero aún no guardados.

sync.import describe la importación única del correo que ya existía, del más reciente al más antiguo. Su status es pending, running o complete. since y limit son el período y el límite de mensajes fijados al empezar. imported cuenta lo guardado, y completedAt dice cuándo terminó. Complete no significa que se importó todo el historial del proveedor.

sync.folders cuenta las carpetas descubiertas y vigiladas. mailboxes.folders lista la ruta del proveedor, role, watched, excludedReason, pending e importDone de cada una. Una carpeta excluida indica el motivo, sin fingir que se leyó. Esta llamada pide read.

Si la lectura se detuvo por un acceso IMAP rechazado, Comprobar ahora prueba primero los datos guardados. Si el acceso sigue rechazado, responde 409: pide al dueño que lo reemplace. Si las comprobaciones de ese servidor están en espera, un 429 dice cuándo reintentar. Un buzón solo de envío responde 409 porque no recibe correo que leer.

Lee el correo que llegó

Comprueba el dominio de envío

El dominio de envío es la parte después de la @. Los registros DNS dicen a los servidores que reciben quién puede enviar desde él. checkDomain lee los registros ahora y guarda el resultado en los buzones de este workspace que usan ese dominio. Pide operate.

const mailbox = await colding.mailboxes.checkDomain({ mailboxId });
console.log(mailbox.domainAuth);

SPF y DMARC deciden si el dominio está en passing o failing. Un buzón solo de envío se evalúa solo por DMARC. DKIM aparece como encontrado o sin verificar, nunca ausente: DNS no puede listar todos los selectores, los nombres bajo los que se publican las claves DKIM. Cuando falta SPF o DMARC, domainAuth.dnsHost dice dónde está el DNS del dominio, leído de sus servidores de nombres: hosts lista los proveedores de DNS que coinciden (vacío si no conocemos el proveedor), y el valor entero viene en null si el DNS no respondió.

Si los registros exigidos siguen fallando durante 72 horas, las campañas y el calentamiento dejan de usar estos buzones hasta que una comprobación pase. failingSince es cuando empezó ese plazo. Corrige los registros con quien administra tu dominio y llama a checkDomain de nuevo.

unknown significa sin conclusión, no aprobado ni rechazado. unknownReason dice si DNS no respondió o el dominio es un nombre reservado. Un timeout no borra una falla ya registrada. Comprueba de nuevo cuando DNS responda. Estos registros nunca prometen entrega.

Algunos proveedores de DNS pueden agregar el registro DMARC que falta: el dueño ve el registro en la propia página del proveedor y lo aprueba. Esto usa un estándar llamado Domain Connect. domainConnectLink devuelve ese enlace. Pide operate.

const link = await colding.mailboxes.domainConnectLink({ mailboxId });
console.log(link.url ?? link.reason);

La respuesta trae la url y el nombre del proveedor en provider, o la url nula y un motivo en reason: not_set_up (todavía no activamos los enlaces de un clic), not_offered (el proveedor de DNS del dominio no ofrece nuestro registro), unanswered (el DNS o el proveedor no respondió a tiempo, así que vuelve a intentarlo) o nothing_to_add (un registro DMARC ya cubre el dominio). Ningún proveedor ofrece nuestros registros todavía, así que por ahora cada respuesta trae un motivo y ningún enlace. Dale el enlace al dueño. Abre la página del proveedor, y el proveedor lo devuelve a la consola, o a la página de la consola que indiques en returnTo (una ruta como /acme/mailboxes). Volver no prueba nada, así que llama a checkDomain después. Cada workspace puede pedir 30 enlaces por minuto.

El registro CNAME de un dominio de seguimiento tiene el mismo tipo de enlace: trackingDomains.connectLink recibe un trackingDomainId y responde igual, con nothing_to_add cuando el dominio ya está verificado.

Pausa el envío o desconecta

mailboxes.pause detiene lo que sale del buzón. Las campañas y el calentamiento esperan, y los envíos nuevos se rechazan. El correo sigue llegando y se lee mientras los datos de acceso funcionen. Los ajustes y los datos de acceso se quedan. No puede recuperar un correo que ya está en camino. Pide operate.

const mailbox = await colding.mailboxes.pause({ mailboxId });
console.log(mailbox.state, mailbox.sync.lastSuccessAt);

mailboxes.resume con mailboxId quita esa pausa. También pide operate. No arregla un acceso rechazado, confirma una dirección ni quita una espera separada.

Desconectar es una acción del dueño en la consola, sin método público del SDK ni tipo de handoff. Elimina la conexión, los datos de acceso, los ajustes y los mensajes de ese buzón guardados en colding. El correo en tu proveedor no se elimina. No se puede deshacer. Las retenciones de calentamiento ligadas a la dirección se quedan, así que volver a conectar no sirve para quitarlas.

Inicia y lee el calentamiento

El calentamiento intercambia correo con un grupo de buzones, llamado pool. Envía correo real, así que startWarmup pide send. El dueño también debe haber aceptado la política de uso aceptable. Puede habilitarse antes de confirmar la dirección remitente, pero no envía nada hasta confirmarla. Los límites de la clave para buzones y flujos siguen vigentes. Una clave limitada a correo transaccional no inicia calentamiento. Los buzones solo de envío y los buzones por la API de Gmail nunca hacen calentamiento.

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

Lee warmup.state, blockedBy, sentToday y todayCap en la respuesta. Running significa habilitado, no que envía en este momento. todayCap es el límite real de hoy, considerando el tamaño del pool, los días y la salud. dailyTarget es la meta de la rampa, no una cantidad prometida de mensajes.

day cuenta tiempo de calentamiento, no días del calendario desde la conexión. rampHeldUntil dice cuándo termina una espera por haber caído en spam. health trae la banda de salud y sus lecturas, o null si no hay lectura. Una lectura de denuncias ausente es sin datos, no cero. health.probation puede reducir el calentamiento después de una cuarentena o un bloqueo, incluso si la banda dice saludable.

blockedBy indica el primer motivo que debes resolver: suspensión del workspace, retención de nuestro equipo, dirección sin confirmar, acceso rechazado, pausa del buzón, espera por salud, dominio o falta de buzones compañeros. La retención de nuestro equipo tiene su motivo en staffBlock. Pide una revisión con mailboxes.appealWarmup, pasando mailboxId y reason. Pide operate y no levanta la retención por sí sola. Solo una apelación puede esperar a la vez.

mailboxes.pauseWarmup con mailboxId pausa el envío de calentamiento, pero mantiene el buzón en el pool y conserva su rampa. Los buzones compañeros aún pueden escribirle. Reanuda con startWarmup. mailboxes.stopWarmup sale del pool. La próxima ronda empieza la rampa desde el primer día. Pausar y finalizar piden operate y conservan las horas, los días y la tasa de respuesta guardados. Ninguno quita la espera por salud ni la retención del equipo ligada a la dirección.

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 en el primer inicio permite que los buzones compañeros escriban al buzón sin que este envíe calentamiento. Reanuda con el mismo valor. Para cambiar de modo, finaliza primero. window y days usan el reloj del workspace.

warmupStats pide read y devuelve 30 días por defecto, incluido hoy. Pasa days para leer hasta 90. Cada día dice qué salió, su límite, qué encontraron los buzones compañeros en spam y qué llegó aquí. El calentamiento no aparece en la bandeja de entrada ni genera eventos send.*. No promete en qué carpeta caerá el correo.

Lee dónde llega tu correo

deliverability.get pide read y responde en una sola llamada, sin nota. Pasa days como 7, 14 o 30, contando hoy, en el calendario del workspace. Si no lo pasas, vale 7. Lee todos los buzones y campañas del workspace, así que una clave limitada a algunos buzones recibe 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 es el calentamiento, por dominio de envío y proveedor de destino. Cada fila de proveedor cuenta los correos que arrived (llegaron), los que el buzón compañero encontró en spam (parte de los arrived), los que neverArrived (nunca llegaron), los que el servidor de tu buzón rechazó (bounced), los que todavía están tooSoon para juzgarlos y los que dejamos fuera (leftOut). La suma da sent. atTestInboxes cuenta cuántos de los correos que llegaron fueron a un buzón de prueba nuestro.

fromOurServers es lo que respondieron los servidores de destino sobre los correos que salieron de nuestros servidores, por stream (cold o transactional) y proveedor. Aceptado significa que el servidor recibió el correo, no que llegara a la bandeja de entrada. noWordYet cuenta los correos que todavía no tienen respuesta. El valor es null cuando el workspace no tiene bandeja de entrada de agente ni dirección de remitente y no envió nada por nuestros servidores en la ventana.

attention lista los buzones y las campañas que una de nuestras reglas pausó o frenó. Cada uno trae su motivo, lo que el motivo impide (sending, first_contact, campaigns, warmup, nothing_yet o slows_warmup) y cuándo empezó y cuándo termina. La pausa que hizo una persona no aparece. Las listas guardan 100 elementos como máximo, y more cuenta el resto.

Un porcentaje llega como { pct, of, bound }, y bound es under1 u over99 cuando la cifra está cerca de 0 o de 100, pero no es exactamente ese número. El porcentaje solo aparece a partir de 20 correos de calentamiento (placement.floor) o de 50 mensajes (floor). Por debajo recibes { tooFew, floor }.

Las denuncias de spam son un conteo, nunca un porcentaje, porque la mayoría de los proveedores no envía ninguna. source: false quiere decir un proveedor que no le cuenta nada al remitente, y eso no es 0. days trae una entrada por día de la ventana, con cero donde no pasó nada.

Responde a una revisión

Nuestro equipo puede poner un buzón en revisión, por ejemplo después de denuncias sobre su correo. Mientras dura, review en mailboxes.get, mailboxes.list y en las lecturas de bandeja de entrada de agente no es null. Sin revisión, es null.

Lee primero review.caseNumber y cítalo cuando nos escribas. since dice cuándo empezó la revisión, y until es la fecha en que dijimos que la revisaríamos. Nada se levanta cuando pasa until, y overdue pasa a true. reason trae las palabras de nuestro equipo, o null si fue el sistema quien puso el buzón en revisión. answeredAt es null hasta que nos cuentes qué pasó.

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);
}

Cuéntanos qué pasó con mailboxes.answerReview. Pasa mailboxId y tres respuestas con tus propias palabras: whatHappened, whatChanged y howItStaysFixed. Cada una tiene de 1 a 2000 caracteres. Pide operate, y una clave limitada a algunos buzones solo puede responder por ellos. La respuesta es la revisión, con answeredAt ya puesto.

Nuestro equipo lee las tres respuestas junto con el caso. Si las envías otra vez, reemplazan la respuesta anterior. Esto no levanta nada: solo nuestro equipo termina una revisión. Un buzón que no está en revisión responde 409, así que lee review antes. También funciona mientras el workspace espera su eliminación.

Sirve también para una bandeja de entrada de agente. Pasa el id de la bandeja como mailboxId. Las lecturas de bandeja de entrada de agente traen el mismo campo review.

Sigue los cambios del buzón

Lee mailbox.failed, mailbox.recovered, mailbox.address_confirmed y mailbox.warmup_health_changed por events.list o un webhook. Identifican el buzón y el cambio, sin datos de acceso. Un evento de llegada es de correo nuevo después del inicio de la lectura, nunca de correo antiguo importado.

const page = await colding.events.list({
  types: [
    "mailbox.failed",
    "mailbox.recovered",
    "mailbox.address_confirmed",
    "mailbox.warmup_health_changed",
  ],
});
console.log(page.items);

Recibe eventos y lee los que te faltaron