Ir a la documentación
CLI

Contactos, audiencias y envíos masivos

Cada comando de la libreta de direcciones, las audiencias, los envíos masivos y la lista de supresión, con ejemplos prácticos.

Cómo encajan

Cuatro espacios de nombres cubren a las personas a las que escribes. Los contactos son la libreta de direcciones del espacio de trabajo, las audiencias son listas de contactos con nombre, un envío masivo manda un mensaje a todas las personas de algunas audiencias, y la lista de supresión contiene las direcciones a las que el espacio de trabajo no enviará. Cada comando llama a un método del SDK, así que las páginas del SDK describen las mismas llamadas con más detalle.

  • Un contacto no tiene id. Su dirección es la clave que acepta cada comando de contacts, sin espacios y en minúsculas, así que [email protected] y [email protected] son un mismo contacto. Una audiencia tiene un id aud_, un envío masivo un id brd_, y una supresión el id que muestra suppressions list.
  • Cada contacto está en la audiencia predeterminada mientras exista. Esa audiencia no se puede eliminar, vaciar ni reducir, y en ella builtin es default.
  • La libreta de direcciones pertenece al espacio de trabajo, así que cada miembro y cada clave leen y escriben la misma.
  • Cada espacio de nombres responde también a su singular, como en openemail contact get, y funcionan los alias habituales: ls, show, new, edit y rm. En suppressions, cuyos verbos son add y remove, new lleva a add y rm a remove.

openemail <namespace> <verb> --help muestra cada opción con su tipo, los scopes, el endpoint y lo que devuelve el comando. Añade --json para obtener la misma página como datos.

Contactos

La libreta de direcciones del espacio de trabajo: las personas a las que un miembro ha escrito desde el editor de la app, más cualquiera guardada a mano. El correo que llega no añade a nadie, y tampoco un envío por la API o la CLI.

ComandoQué hace
openemail contacts listUna página de los contactos guardados, primero aquellos a los que se escribió más recientemente. --source deja los contactos manual o auto, y --q busca en nombres y direcciones
openemail contacts get <email>Un contacto, con todas las audiencias en las que está
openemail contacts create --email <value>Guardar un contacto nuevo, con --name, --notes y --audience-ids. Una dirección que ya está en la libreta se rechaza con 409 contact_exists
openemail contacts update <email>Cambiar --name o --notes, donde null borra uno de ellos. La dirección en sí no puede cambiar
openemail contacts delete <email>Eliminar el contacto con sus notas, su foto y sus pertenencias, y ocultar la dirección para que el editor no vuelva a registrarla
openemail contacts set-audiences <email> --audience-ids <a,b>Hacer que las audiencias en las que está el contacto sean exactamente esta lista. La audiencia predeterminada siempre se conserva
openemail contacts list-peopleTodas las personas de la página Contactos: los contactos guardados y, con threads:read, cada dirección vista en el correo, con el número de hilos. --sort, --q, --email y --blocked la filtran
openemail contacts save <email>Guardar una dirección, conservar una registrada a partir de un envío o recuperar una eliminada. Nunca da error, esté la dirección en el estado que esté
openemail contacts delete-many <emails...>Eliminar y ocultar de 1 a 200 direcciones en una sola llamada
openemail contacts set-photo <email> <data>Subir la foto desde un archivo, o desde stdin con -: PNG, JPEG, WebP o GIF de hasta 5 MB
openemail contacts remove-photo <email>Quitar la foto y eliminar la imagen guardada
openemail contacts block <email>Poner la dirección en la lista de bloqueo del espacio de trabajo, para que se rechace el correo que venga de ella. Se quita la etiqueta con signo más
openemail contacts unblock <email>Quitar cada regla de la lista de bloqueo que bloquea la dirección, incluida una regla para todo el dominio
openemail contacts list-threads <email>Los hilos que la dirección escribió o en los que se le escribió, en todas las carpetas. --q busca dentro de ellos
openemail contacts activity <email>El correo recibido de la dirección y enviado a ella en un periodo, de 90 días salvo que --minutes indique otra cosa, con los hilos que esperan respuesta y la mediana del tiempo de respuesta en cada sentido

Audiencias

Listas de contactos con nombre, hasta 100 por espacio de trabajo. Una dirección tiene que ser un contacto antes de unirse a una, salvo mediante import-contacts, que guarda las direcciones nuevas sobre la marcha.

ComandoQué hace
openemail audiences listUna página de las audiencias, primero la predeterminada y el resto de la más reciente a la más antigua, cada una con su contactCount
openemail audiences growthCómo crecieron las audiencias en un periodo, de 30 días salvo que --days o --minutes indiquen otra cosa: altas y bajas por intervalo, y totales
openemail audiences get <id>Una audiencia, con un contactCount actualizado
openemail audiences create --name <value>Crear una audiencia vacía, con una --description opcional. Los nombres no son únicos
openemail audiences update <id>Cambiar --name o --description. Los miembros no se tocan
openemail audiences delete <id>Eliminar la audiencia y conservar sus contactos. La audiencia predeterminada no se puede eliminar
openemail audiences empty <id>Sacar todos los contactos y conservar la audiencia, con su id, su nombre y su descripción
openemail audiences list-contacts <id>Una página de los contactos de la audiencia, con cuándo se unió cada uno y si se dio de baja. --sort, --q, --source y --statuses la filtran
openemail audiences add-contact <id> --email <value>Añadir un contacto existente a la audiencia. Añadir a alguien que ya está no cambia nada
openemail audiences remove-contact <id> <email>Sacar un contacto. Un contacto que no está en la audiencia da 404
openemail audiences add-contacts <id> --emails <a,b>Añadir hasta 200 contactos existentes, e indicar en missing las direcciones que no son contactos
openemail audiences remove-contacts <id> --emails <a,b>Sacar hasta 200 contactos, e indicar los que no estaban en ella
openemail audiences import-contacts <id> --contacts <json|@file|->Importar hasta 500 filas { email, name }, guardando las direcciones que aún no son contactos

Envíos masivos

Un mensaje para todas las personas de hasta 10 audiencias, enviado como una copia aparte para cada persona, con los campos de combinación rellenados y un enlace para darse de baja. Cada copia es un correo normal con su propio id msg_, sus eventos y sus webhooks.

ComandoQué hace
openemail broadcasts preview --audience-ids <a,b>Contar a quién llegaría un envío masivo a estas audiencias, y a quién omitiría por haberse dado de baja o estar suprimido. No envía nada
openemail broadcasts send --audience-ids <a,b> --from <value>Enviar con --subject y --html o --text, o con una --template guardada, ahora o en --scheduled-at
openemail broadcasts listUna página de envíos masivos, del más reciente al más antiguo, con recuentos en directo. --audience-id deja los enviados a esa audiencia
openemail broadcasts get <id>Un envío masivo, con su estado y sus recuentos en directo: el comando que hay que consultar mientras se envía
openemail broadcasts stats <id>Totales de entregados, rebotados, abiertos, con clic y bajas, y una serie por intervalo de --grain, de una hora salvo que indiques otra cosa
openemail broadcasts list-recipients <id>A quién fue cada copia y qué le pasó. --filter deja un grupo, como bounced o not_opened
openemail broadcasts get-recipient <id> <email-id>La copia de una persona, con el asunto, el HTML y el texto exactamente como los recibió
openemail broadcasts cancel <id>Detener un envío masivo programado, en cola o que aún se está enviando. Las copias que ya salieron no se pueden recuperar

Supresiones

Las direcciones a las que este espacio de trabajo no enviará: rebotes permanentes y quejas, registrados cuando ocurren, y cualquier dirección que añadas a mano. Un envío a una de ellas se rechaza para ese destinatario antes de que salga nada.

ComandoQué hace
openemail suppressions listUna página de la lista, de la más reciente a la más antigua. --reason deja bounce, complaint o manual, y --q busca
openemail suppressions get <id>Una fila: la dirección, el motivo, el detalle que traía el rebote o la queja, y si se puede quitar
openemail suppressions add --email <value>Dejar de enviar a una dirección. Añadir una que ya está devuelve la fila que tiene
openemail suppressions remove <id>Volver a permitir el correo a la dirección. Un rebote permanente no se puede quitar

Las supresiones y la lista de bloqueo son listas distintas. suppressions add impide que salga correo hacia una dirección, y contacts block rechaza el correo que llega de ella.

Scopes

La mayoría de los comandos necesitan el scope de lectura o de escritura de su espacio de nombres. Unos pocos necesitan otro, porque leen o cambian otra cosa:

ScopeComandos
contacts:readcontacts list, get y list-people
contacts:writecontacts create, update, delete, save, delete-many, set-photo y remove-photo, y audiences import-contacts junto con audiences:write
audiences:readaudiences list, growth, get y list-contacts, y broadcasts preview, así que una clave que no puede enviar puede mostrar igualmente el recuento
audiences:writeTodos los demás comandos de audiences, y contacts set-audiences. contacts create --audience-ids lo necesita junto con contacts:write
threads:readcontacts list-threads y activity, y las direcciones vistas en el correo en list-people
settings:readsuppressions list y get
settings:writesuppressions add y remove, y contacts block y unblock
emails:readbroadcasts list, get, stats, list-recipients y get-recipient
emails:sendbroadcasts send, que también necesita audiences:read, y broadcasts cancel
  • Una clave limitada a determinadas direcciones o dominios lee y escribe la misma libreta de direcciones que cualquier otra clave. Solo ve los envíos masivos enviados desde una dirección o un dominio que tiene, obtiene solo los contactos guardados de list-people, y recibe un rechazo 422 capability_unsupported de contacts list-threads, activity, block y unblock, y de suppressions add y remove.
  • Un inicio de sesión con el navegador de un miembro que solo llega a algunas direcciones se rechaza con 422 capability_unsupported en cada comando de contacts, audiences y broadcasts. suppressions add rechaza un inicio de sesión con el navegador de cualquiera que no sea el propietario del espacio de trabajo.

Ejemplos prácticos

Crea una audiencia a partir de un archivo y cuenta después a quién llegaría un envío masivo a ella. import-contacts guarda las direcciones que aún no son contactos, y volver a ejecutarlo no crea ni añade nada dos veces.

contacts.json
[  { "email": "[email protected]", "name": "Ada Lovelace" },  { "email": "[email protected]", "name": "Grace Hopper" },  { "email": "[email protected]" }]
Crear la audiencia y contarla
AUDIENCE=$(openemail audiences create --name 'Product updates' --json | jq -r .id)openemail audiences import-contacts "$AUDIENCE" --contacts @contacts.jsonopenemail broadcasts preview --audience-ids "$AUDIENCE"

Comprueba un envío masivo con --dry-run, que muestra la solicitud y no envía nada, y después envíalo. El envío masivo se crea al momento y se envía en segundo plano, así que consulta get para seguirlo. Este cuerpo no incluye {{unsubscribeUrl}}, así que cada copia recibe un pie de una línea para darse de baja.

broadcast.json
{  "audienceIds": ["aud_4c1b8e2a7d9f05c36b4e8a71"],  "from": "Acme <[email protected]>",  "subject": "{{firstName|Hello}}, the September release is out",  "html": "<p>Hi {{firstName|there}},</p><p>Here is what changed this month.</p>",  "scheduledAt": "2026-10-01T09:00:00Z"}
Comprobar el envío masivo y luego enviarlo
openemail broadcasts send --data @broadcast.json --dry-runBROADCAST=$(openemail broadcasts send --data @broadcast.json --yes --json | jq -r .id)openemail broadcasts get "$BROADCAST"openemail broadcasts stats "$BROADCAST" --grain day

Mira a quién no llegó un envío masivo. --ndjson muestra un destinatario por línea, y --all --json un único documento con todas las páginas.

A quién no llegó
openemail broadcasts list-recipients brd_5a8c1e3f7b2d94a06c8e1f3b --filter bounced --ndjson | jq -r .emailopenemail broadcasts list-recipients brd_5a8c1e3f7b2d94a06c8e1f3b --filter not_opened --all --json | jq ".items | length"openemail suppressions list --reason bounce --all --max 50

Copia los miembros suscritos de una audiencia a otra. jq convierte el flujo en el cuerpo que acepta add-contacts, y --data - lo lee de stdin. --max 200 lo limita a las 200 direcciones que acepta una llamada.

Copiar los miembros suscritos
openemail audiences list-contacts aud_9f2c4b7e1a0d63d84c5f2e7b --statuses subscribed --max 200 --ndjson \  | jq -s '{ emails: map(.email) }' \  | openemail audiences add-contacts aud_1c4e7a9b2d0f36e85a7c1b4d --data -

Elimina cada contacto que el editor registró en un dominio. delete-many acepta hasta 200 direcciones por llamada, así que xargs -n 200 divide una lista más larga. Comprueba antes los lotes con --dry-run, porque no se puede deshacer.

Eliminar por dominio
openemail contacts list --source auto --all --ndjson \  | jq -r 'select(.email | endswith("@old-vendor.example")) | .email' > leaving.txtxargs -n 200 openemail contacts delete-many --dry-run < leaving.txtxargs -n 200 openemail contacts delete-many --yes < leaving.txt

Deja de enviar a una dirección, vuelve a permitir otra y bloquea a un remitente. removable dice qué filas aceptará suppressions remove.

Suprimir, permitir y bloquear
openemail suppressions add --email [email protected]openemail suppressions list --q [email protected] --json | jq -r '.items[] | select(.removable) | .id'openemail suppressions remove 7b1e2c3d-4f5a-4b6c-8d7e-9f0a1b2c3d4e --yesopenemail contacts block [email protected]

Confirmaciones y códigos de verificación

Estos comandos piden que confirmes en un terminal antes de ejecutarse:

Espacio de nombresPide confirmación
contactsdelete, delete-many, remove-photo y unblock
audiencesdelete, empty, remove-contact y remove-contacts
broadcastssend y cancel
suppressionsremove
  • --yes confirma por ti. Sin supervisión, con --json o --no-input, en CI o sin terminal, un comando que preguntaría se detiene con Refusing to run unattended. Pass --yes to confirm. y el código de salida 2.
  • --dry-run muestra la solicitud que enviaría el comando y sale con el código 0, sin preguntar y sin cambiar nada.
  • Con un inicio de sesión con el navegador, audiences delete pide primero un código de verificación, como hace la app web. --yes nunca se lo salta, y sin supervisión el comando se detiene con el código de salida 4. Ejecuta antes openemail verify, o usa una clave de API, a la que nunca se le pide.
  • audiences empty nunca pide un código de verificación, así que comprueba el id antes de pasar --yes.

Paginación

Cada comando que lista lee una página. Cuando quedan más, pasa a --cursor el cursor que mostró, con los mismos filtros, o léelas todas:

  • --all lee todas las páginas y transmite los elementos: una tabla en un terminal, y un objeto JSON por línea cuando se redirige o con --ndjson.
  • --max <n> se detiene tras esa cantidad de elementos, e implica --all.
  • --json muestra un único documento { items, hasMore, nextCursor }, también con --all.
  • Un cursor mal formado o caducado da 400 invalid_cursor. Empieza de nuevo sin él.
ComandoTamaño de página
openemail contacts listDe 1 a 200, 50 salvo que --limit indique otra cosa
openemail contacts list-peopleDe 1 a 100, 25 salvo que --limit indique otra cosa
openemail contacts list-threadsDe 1 a 100, 25 salvo que --limit indique otra cosa
openemail audiences listDe 1 a 100, 25 salvo que --limit indique otra cosa
openemail audiences list-contactsDe 1 a 200, 50 salvo que --limit indique otra cosa
openemail broadcasts listDe 1 a 100, 25 salvo que --limit indique otra cosa
openemail broadcasts list-recipientsDe 1 a 200, 50 salvo que --limit indique otra cosa
openemail suppressions listDe 1 a 100, 25 salvo que --limit indique otra cosa

Bueno saberlo

  • contacts create rechaza una dirección que ya está en la libreta con 409 contact_exists, así que un reintento nunca sobrescribe un nombre que alguien editó. contacts save nunca rechaza: guarda, conserva o recupera la dirección, esté en el estado que esté.
  • contacts delete acepta también una dirección que solo se ha visto en el correo, lo que quita a esa persona de list-people. El correo se queda. No se puede deshacer: volver a guardar la dirección empieza un contacto sin nombre, sin notas y sin más audiencia que la predeterminada.
  • La dirección es la identidad de un contacto, así que contacts update no puede cambiarla. Mover un contacto es un delete y un create.
  • contacts set-photo lee la imagen de un archivo, o de stdin con -. Pasa --content-type, como image/jpeg: sin él la imagen puede ir como application/octet-stream, que el servidor rechaza con 422 invalid_image.
  • broadcasts send --scheduled-at acepta una hora ISO 8601 como 2026-10-01T09:00:00Z, o una duración ISO 8601 como PT2H o P1D, hasta 365 días en el futuro. Los retrasos cortos que acepta send --at, como 2h, aquí se rechazan.
  • Los campos de combinación funcionan en --subject, --html y --text: {{firstName}}, {{lastName}}, {{name}}, {{email}} y {{unsubscribeUrl}}, cada uno con un valor alternativo tras una barra, como en {{firstName|there}}. Un cuerpo que no incluye {{unsubscribeUrl}} recibe un pie de una línea para darse de baja. Una plantilla se envía tal cual, así que pon el enlace en la plantilla.
  • Un envío masivo se comprueba contra los envíos mensuales del plan antes de escribir nada, y cada copia cuenta como un envío. Uno que la cuota no puede cubrir se rechaza con 429 send_quota_exceeded, y no queda nada a medias.
  • Pasa tu propia --idempotency-key a broadcasts send cuando un script pueda volver a ejecutar el paso. La misma clave responde con el envío masivo que creó en lugar de enviar uno nuevo.
  • Un contacto que se da de baja de un envío masivo sigue en la audiencia con unsubscribedAt definido, y los envíos masivos posteriores a esa audiencia lo omiten. audiences list-contacts --statuses unsubscribed los lista.
  • Un rebote permanente se queda en la lista de supresión. suppressions remove lo rechaza con 409 suppression_not_removable, y removable en cada fila lo indica de antemano.

Tu bandeja de entrada,
en tus propios términos.

Infraestructura de correo para empresas, IA, agentes y correo personal. Creada para escalar, con privacidad y control. Todo lo que el correo debería haber tenido desde el primer día.

OpenEmail

Infraestructura de correo para empresas, IA, agentes y correo personal. Creada para escalar, con privacidad y control. Todo lo que el correo debería haber tenido desde el primer día.

© 2026 OpenEmail. Todos los derechos reservados.