Envío y seguimiento de correo
Envía, agrupa en lotes, traduce, programa y cancela correo con los comandos `emails`, y sigue después su entrega, aperturas y clics con `tracking`.
Descripción general
El espacio de nombres emails es la API de envío en forma de comandos, uno por cada método de openemail.emails en el SDK. Cada uno llama a un endpoint y muestra lo que devuelve. El espacio de nombres tracking lee las aperturas y los clics del correo que enviaste. openemail email funciona en lugar de openemail emails.
Cada comando de esta página necesita un inicio de sesión, con el navegador o con una clave de API, y uno de dos scopes: emails:send para enviar, traducir, cancelar y reprogramar, y emails:read para todo lo que solo lee.
Qué envío usar
openemail send es el comando escrito a mano de la página Correo, y envía a través de emails send. Está hecho para una persona ante un terminal: elige la dirección de envío cuando omites --from, lee el cuerpo de un archivo, de stdin o de tu editor, adjunta archivos por ruta y muestra un resumen para confirmar antes de que salga nada. openemail emails send recibe el cuerpo de la solicitud como opciones, una por campo, y no pregunta nada, lo que va bien para un script que sabe exactamente lo que envía.
| send | emails send |
|---|---|
| --from <address> | Obligatoria, como --to, salvo que --data la incluya. send puede omitirla y elegir una dirección por ti |
| -f, --body-file <path> | No hay opción de archivo para el cuerpo. Pasa --html "$(cat body.html)", o la solicitud entera en --data @email.json |
| -a, --attach <path> | --attachments, un array JSON de archivos, cada uno con un filename y un content en base64, o con el fileId de un archivo que ya está en Archivos |
| --at <when> | --scheduled-at <when>, un instante ISO 8601 o una duración como PT1H o P2D. send acepta también retrasos cortos como 10m, 2h y 1d |
| --undo <seconds> | --cancellable-for-seconds <n>, de 0 a 900 |
| --translate <language> | --translate '{"to":"de"}', que acepta también from, includeOriginal y subject |
| --template <id> --props <json> | --template '{"id":"welcome","props":{"name":"Ada"}}', que también puede fijar una version |
| --draft <id> | --draft-id <id> |
| --thread <id> | --thread-id <id> |
| --tag <key=value> | --tags <key=value>, repetida, o un objeto JSON |
Solo emails send tiene --tracking para desactivar las aperturas o los clics en un envío, --signature, --headers para cabeceras personalizadas, --attachment-delivery para elegir entre adjuntar archivos o enlazarlos, y --data para el cuerpo entero como JSON, en línea, desde un archivo con @path o desde stdin con -.
Los dos terminan de forma distinta. send sale con el código 1 cuando el correo vuelve como failed. emails send sale con el código 0 siempre que la API haya respondido, así que comprueba status en lo que muestra.
Todos los comandos de emails
send, send-batch, translate, cancel y reschedule necesitan emails:send. list, get, list-events y get-tracking necesitan emails:read. Un id de correo es msg_ seguido de 24 caracteres hexadecimales, tal como lo devuelve un envío.
| Comando | Qué hace |
|---|---|
| openemail emails send --from <value> --to <a,b> | Enviar un correo ahora, retenerlo durante una ventana para deshacer con --cancellable-for-seconds, o programarlo con --scheduled-at. El cuerpo es --html, --text o ambos, una --template guardada o un --draft-id guardado |
| openemail emails send-batch <emails> | Enviar hasta 100 correos independientes en una sola solicitud, desde un array JSON en un archivo, en línea o por stdin con -. Cada elemento tiene la forma del cuerpo de emails send y tiene éxito o falla por su cuenta |
| openemail emails translate --to <value> | Previsualizar lo que entregaría un envío traducido, para --subject, --html o --text. No se guarda ni se envía nada, y consume una acción de IA |
| openemail emails list | Una página de correos enviados, del más reciente al más antiguo, filtrada por --status, --from o --broadcast-id |
| openemail emails get <id> | Un correo enviado con el estado, el error y la hora de entrega de cada destinatario, y el informe de seguimiento completo cuando tuvo seguimiento |
| openemail emails list-events <id> | El rastro de eventos de un envío, del más antiguo al más reciente: aceptado, programado, enviado, entregado, rebotado, con queja, abierto, con clic y el resto |
| openemail emails get-tracking <id> | El informe de interacción de un envío: sus totales, una entrada por cada copia con seguimiento y cada enlace reescrito con sus clics |
| openemail emails cancel <id> | Detener un correo en cola o programado antes de que salga. Pide que confirmes |
| openemail emails reschedule <id> <scheduled-at> | Mover un correo en cola o programado a un instante ISO 8601, o a una duración como PT30M, desde un segundo hasta 365 días en el futuro |
Todos los comandos de tracking
Los cinco necesitan emails:read. tracking get, list-opens y list-clicks aceptan cualquiera de los dos ids que tiene un mensaje: el id msg_ que devolvió su envío, o el id de seguimiento tmsg_ que llevan tracking list y los payloads de los webhooks.
| Comando | Qué hace |
|---|---|
| openemail tracking list | Una página de mensajes con seguimiento enviados en un periodo, del más reciente al más antiguo, cada uno con su informe completo. --opened y --clicked la filtran, y --no-opened deja los que nadie abrió. El periodo es de 30 días salvo que --days o --minutes indiquen otra cosa |
| openemail tracking get-stats | Las cifras de un panel de interacción: mensajes con seguimiento, abiertos y con clic, tasas de apertura y de clic, una serie temporal en intervalos de --grain, y los principales enlaces, clientes de correo y países |
| openemail tracking get <id> | El informe de interacción de un mensaje, el mismo documento que devuelve emails get-tracking |
| openemail tracking list-opens <id> | Las aperturas individuales detrás del recuento de aperturas de un mensaje, de la más reciente a la más antigua, cada una marcada como human, proxy o machine. --include-machine añade los accesos que no se contaron |
| openemail tracking list-clicks <id> | Los clics individuales en los enlaces de un mensaje, del más reciente al más antiguo, con la url original de cada uno. --include-machine añade los escáneres de enlaces y las repeticiones agrupadas |
tracking list y get-stats cubren cada mensaje con seguimiento que envió el buzón, incluido el correo escrito en la app web y el enviado por las herramientas MCP o el asistente, mientras que emails list contiene los registros de envío que hizo la API. Un informe sin registro de envío tiene sendId con el valor null.
Ejemplos
Envía desde un script con una clave de idempotencia propia. Volver a ejecutarlo con la misma --idempotency-key muestra el primer correo con replayed: true en lugar de enviar un segundo.
openemail emails send \ --from 'Acme Billing <[email protected]>' \ --to [email protected] \ --subject 'Your September invoice' \ --html '<p>The invoice is attached. Tell me if anything on it looks wrong.</p>' \ --attachments '[{"fileId":"file_6bb640f5b99e47deb758f1f5"}]' \ --tracking '{"opens":false}' \ --idempotency-key invoice:inv_2026_09_4192 \ --json | jq -r '.id + " " + .status'Haz que una persona lea una traducción antes de que salga. Envía el texto aprobado como --subject y --html normales, sin --translate, o se traducirá una segunda vez. El html traducido ya contiene tu original debajo, salvo que pases --no-include-original.
openemail emails translate --to de \ --subject 'Your September invoice' \ --html "$(cat invoice.html)" \ --json > preview.jsonjq -r .html preview.jsonopenemail emails send --from [email protected] --to [email protected] \ --subject "$(jq -r .subject preview.json)" \ --html "$(jq -r .html preview.json)"Envía un lote desde un archivo. El comando sale con el código 0 siempre que el lote se haya procesado, aunque fallen algunos elementos, así que lee failed y el status de cada elemento. Volver a ejecutarlo con la misma clave reproduce los elementos que salieron y envía solo el resto, siempre que el array mantenga su orden.
[ { "from": "[email protected]", "to": "[email protected]", "subject": "Receipt 4192", "text": "Thanks for your order." }, { "from": "[email protected]", "to": "[email protected]", "subject": "Receipt 4193", "text": "Thanks for your order." }]openemail emails send-batch receipts.json --idempotency-key receipts:2026-09-27 --json > result.jsonjq '{ sent, failed }' result.jsonjq -r '.items[] | select(.status == "error") | "\(.index) \(.error.code)"' result.jsonPrograma un correo, muévelo y cancélalo. --yes responde a la confirmación que pide cancel, algo que un script no puede hacer.
ID=$(openemail send --from [email protected] --to [email protected] --subject "Standup notes" \ --body-file notes.md --at 2026-10-01T09:00:00Z --json | jq -r .id)openemail emails reschedule "$ID" 2026-10-01T13:00:00Zopenemail emails get "$ID" --json | jq -r '.status + " " + .scheduledAt'openemail emails cancel "$ID" --yesBusca los envíos que fallaron y lee qué le pasó a uno. Redirigido sin --json, --all muestra un objeto JSON por línea.
openemail emails list --status failed,partial --from [email protected] --all | jq -r .idopenemail emails get msg_3f9a1c07d2b84e6a9c5b1f20openemail emails list-events msg_3f9a1c07d2b84e6a9c5b1f20 --all --json | jq -r '.items[] | .createdAt + " " + .type'Lee una semana de interacción en días que cortan a medianoche UTC+2, lista lo que nadie abrió y cuenta los clics en cada enlace de un mensaje.
openemail tracking get-stats --days 7 --offset-minutes 120 --json | jq '{ tracked, openRate, clickRate }'openemail tracking list --no-opened --days 7 --all | jq -r .subjectopenemail tracking list-clicks msg_3f9a1c07d2b84e6a9c5b1f20 --all | jq -r .url | sort | uniq -cScopes, códigos y confirmaciones
- Un inicio de sesión con el navegador pide los scopes en la página de aprobación, y
openemail login --scopes emails:send,emails:readpreselecciona ambos. Un comando al que le falta su scope se detiene con el código de salida4einsufficient_scope, y nombra el scope. send --attachcon más de 5 MB de archivos los sube primero a Archivos, lo que también necesitafiles:write.- Ninguno de estos comandos pide un código de verificación, así que un inicio de sesión con el navegador los ejecuta igual que una clave de API.
emails cancelpregunta antes de cancelar, y--yesresponde por ti. Sin supervisión y sin--yes, se detiene conRefusing to run unattended. Pass --yes to confirm.y el código de salida2.emails send,send-batchyreschedulenunca preguntan.sendmuestra un resumen y pregunta solo en un terminal, y--yestambién se lo salta.--dry-runmuestra la solicitud que enviaría un comando, no envía nada y sale con el código0. Enemails translateno consume ninguna acción de IA, y enemails cancelno pregunta nada.
Páginas de resultados
emails list, emails list-events, tracking list, list-opens y list-clicks leen una página. --limit fija su tamaño, de 1 a 100 con 25 por defecto para las dos listas de emails, y de 1 a 200 con 50 por defecto para las tres listas de tracking. --cursor sigue desde el cursor que mostró una página.
--alllee 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.--jsonmuestra un único documento{ items, hasMore, nextCursor }, también con--all.- La paginación es por cursor, no por desplazamiento, así que el correo enviado mientras paginas nunca desplaza ni repite una fila.
Conviene saber
- Cada ejecución crea su propia clave de idempotencia, que cubre los reintentos dentro de esa ejecución. Ejecutar un envío dos veces envía dos veces, salvo que ambas ejecuciones pasen la misma
--idempotency-key. La misma clave con un cuerpo distinto se rechaza conidempotency_key_reusey el código de salida7. - Solo el correo
queuedyscheduledse puede cancelar o mover. Un envío inmediato sin ventana para deshacer sale dentro de la propia solicitud, así que cuando tienes su id suele ser demasiado tarde, y la llamada termina conemail_not_cancellabley el código de salida6. - Un correo cancelado sigue cancelado. Reprogramar cambia solo la hora, contada desde que el servidor recibe la solicitud en el caso de una duración, así que para cambiar el texto, cancela y vuelve a enviar.
- Una traducción que no se puede producir rechaza el envío entero, y nada sale sin traducir. Un lote traducido contiene como máximo 10 mensajes que llevan
translate. - Una cuota de envío agotada detiene un envío con
send_quota_exceededhasta el primer día del mes, y una cuota de IA agotada detiene una traducción conai_quota_exceededhasta la medianoche UTC, ambas con el código de salida8. - El correo enviado con una clave
oe_test_nunca se entrega. Aparece comosent, contransportentest, y nunca tiene seguimiento. emails get-trackingytracking getresponden 404, código de salida5, para un mensaje que no llevaba píxel ni enlaces reescritos, porque sin seguimiento no es lo mismo que sin abrir. El seguimiento sigue la configuración con la que se envió el mensaje, así que activarlo más tarde no alcanza al correo anterior.- Cada recuento es un mínimo. Un lector cuyo cliente de correo bloquea las imágenes nunca cuenta como apertura, y un clic es una prueba de lectura más fuerte que una apertura.
list-opensylist-clicksresponden 404 para un idmsg_sin nada con seguimiento, pero aceptan un idtmsg_tal cual, así que uno desconocido vuelve como una lista vacía.- Una clave limitada a algunas direcciones solo ve el correo enviado desde esas direcciones, y una que tiene un dominio entero cubre todas sus direcciones.
Todas las opciones
Esta página nombra las opciones más importantes. openemail <command> --help lista cada argumento y opción que acepta un comando, con su tipo, el scope que necesita, su método y ruta, lo que devuelve y las notas de la referencia de la API. Añade --json para obtener la misma ayuda como un único documento JSON.
openemail emails --helpopenemail emails send --helpopenemail tracking list-opens --help --json