Documenta los tres flujos disponibles para componer y enviar correos HTML desde la terminal usando las plantillas OWA del repositorio. Cada modo resuelve un escenario distinto según el sistema operativo y el nivel de automatización.
owa— genera el HTML y lo guardas como archivo. Abres en el navegador, copias (Ctrl+A → Ctrl+C) y pegas en Outlook Web. Funciona en cualquier OS.mac— genera el HTML y abre un borrador en Microsoft Outlook vía AppleScript. Outlook inyecta la firma «Kabat One» automáticamente. Envías con ⌘+Enter. Solo macOS.graph— genera el HTML y lo envía directamente vía Microsoft Graph API con OAuth2. Incluye la firma como imagen inline (CID). Funciona en cualquier OS.
Todos los modos:
- Plantillas HTML en
~/rules/templates/mail/(delivery_template.htmlygeneric_template.html) - Reglas de composición en
~/rules/rulesets/MAIL.md
Modo mac (adicional):
- macOS con Microsoft Outlook instalado y configurado
- Firma «Kabat One» como firma predeterminada en Outlook
Modo graph (adicional):
- Cuenta de Microsoft 365 con buzón activo (por ejemplo,
ralvarez@kabatone.com) - Aplicación registrada en Microsoft Entra (ver pasos abajo)
- Python 3 y
curlinstalados - Imagen de firma en
~/rules/templates/mail/assets/ralvarez_firma_740.png - Credenciales en
~/.secrets.yamlbajo la claveGRAPH_API
- Genera el HTML con la plantilla correspondiente (entrega o genérica)
- Guarda el archivo como
YYYY-MM-DD-{nombre-corto}.html(fecha CST) - Copia la imagen de firma junto al HTML en una subcarpeta
assets/ - Abre el archivo en el navegador
- Selecciona todo (Ctrl+A), copia (Ctrl+C) y pega en la ventana de composición de OWA
- Outlook Web agrega la firma configurada automáticamente al enviar
Nota: no incluyas la firma en el HTML; OWA la inyecta sola.
- Genera el HTML con la plantilla correspondiente
- Guarda el archivo como
YYYY-MM-DD-{nombre-corto}.html(fecha CST) - Abre un borrador en Microsoft Outlook con AppleScript:
tell application "Microsoft Outlook"
activate
set newMsg to make new outgoing message with properties {subject:"...", content:"..."}
make new to recipient at newMsg with properties {email address:{address:"destinatario@ejemplo.com"}}
open newMsg
end tell- Outlook inyecta la firma «Kabat One» (con imagen embebida) automáticamente
- Revisa el correo y envía con ⌘+Enter
Nota: no incluyas la firma en el HTML. Usa
open(nosend) para que Outlook la inyecte. El envío directo consendno agrega la firma.
- Tabla exterior:
width="800"conmax-width:800px - Padding del
<td>interior: 30px por lado - Área útil de contenido: 740px (800 − 30 − 30)
- La firma debe medir 740px de ancho para llenar el área útil sin desbordar
Microsoft Graph no inyecta la firma configurada en Outlook. Debes incluir la imagen de firma como adjunto inline con contentId y referenciarla en el HTML con cid::
- Archivo:
~/rules/templates/mail/assets/ralvarez_firma_740.png(740px de ancho) - Variantes disponibles:
ralvarez_firma.png(original),_740.png,_800.png,_1024.png
<hr style="margin:30px 0; border:none; border-top:2px solid #ecf0f1;">
<img src="cid:firma_ralvarez" alt="Rodrigo Álvarez" width="740"
style="max-width:100%; display:block;">- Abre entra.microsoft.com e inicia sesión con tu cuenta corporativa
- Ve a Entra ID → Registros de aplicaciones → Nuevo registro
- Completa el formulario:
- Nombre:
Warp Mail CLI - Tipos de cuenta compatibles: «Solo inquilino único» (tu organización)
- URI de redirección: déjalo vacío
- Nombre:
- Haz clic en Registrar
- Copia estos valores de la página de información general:
- Id. de aplicación (cliente): tu
CLIENT_ID - Id. de directorio (inquilino): tu
TENANT_ID
- Id. de aplicación (cliente): tu
- En la aplicación registrada, ve a Permisos de API
- Haz clic en Agregar un permiso → Microsoft Graph → Permisos delegados
- Busca y agrega los siguientes permisos:
Mail.Send— enviar correo como usuarioemail— ver la dirección de correo electrónicoUser.Read— iniciar sesión y leer el perfil
Los tres permisos deben quedar como Delegada y con «No» en la columna «Se necesita consentimiento de administrador».
- Ve a Autenticación en el menú lateral de la aplicación
- Abre la pestaña Configuración
- Activa «Permitir flujos de clientes públicos» → Habilitado
- Haz clic en Guardar
Nota: si el toggle no guarda correctamente (error
invalid_cliental autenticar), ve a Manifiesto, busca"allowPublicClient"y cámbialo atruemanualmente.
Desde la terminal, solicita un código de dispositivo:
curl -s -X POST \
"https://login.microsoftonline.com/$TENANT_ID/oauth2/v2.0/devicecode" \
-d "client_id=$CLIENT_ID" \
-d "scope=https://graph.microsoft.com/Mail.Send"La respuesta incluye un user_code y un device_code. Abre la URL indicada (https://login.microsoft.com/device), ingresa el código de usuario y autentica con tu cuenta.
Después, canjea el device_code por un token de acceso:
curl -s -X POST \
"https://login.microsoftonline.com/$TENANT_ID/oauth2/v2.0/token" \
-d "grant_type=urn:ietf:params:oauth:grant-type:device_code" \
-d "client_id=$CLIENT_ID" \
-d "device_code=$DEVICE_CODE"La respuesta contiene un access_token válido (típicamente por una hora) y un refresh_token para renovarlo.
Usa el endpoint /me/sendMail con el token obtenido:
curl -s -X POST "https://graph.microsoft.com/v1.0/me/sendMail" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"message": {
"subject": "Asunto del correo",
"body": {
"contentType": "HTML",
"content": "<html><body>Contenido HTML</body></html>"
},
"toRecipients": [
{"emailAddress": {"address": "destinatario@ejemplo.com"}}
],
"attachments": [
{
"@odata.type": "#microsoft.graph.fileAttachment",
"name": "ralvarez_firma.png",
"contentType": "image/png",
"contentBytes": "<BASE64_DE_LA_IMAGEN>",
"contentId": "firma_ralvarez",
"isInline": true
}
]
},
"saveToSentItems": true
}'En el HTML del correo, referencia la firma como imagen inline:
<img src="cid:firma_ralvarez" alt="Rodrigo Álvarez" width="740"
style="max-width:100%; display:block;">Los valores de CLIENT_ID, TENANT_ID y demás parámetros de la aplicación están en ~/.secrets.yaml bajo la clave GRAPH_API.
El script scripts/graph_auth.py gestiona la autenticación con caché en ~/.graph_tokens.json.
flowchart TD
A["/mail graph ..."] --> B{"~/.graph_tokens.json\nexiste?"}
B -- No --> C["Indicar al usuario:\n/mail token"]
B -- Sí --> D{"access_token\nválido?"}
D -- Sí --> G["Enviar correo\nvía Graph API"]
D -- No --> E{"refresh_token\nválido?"}
E -- Sí --> F["Renovar access_token\nsilenciosamente"]
F --> G
E -- No --> C
C --> H["/mail token"]
H --> I["Device code flow\n(navegador)"]
I --> J["Guardar tokens\nen ~/.graph_tokens.json"]
J --> G
style A fill:#3498db,color:#fff
style G fill:#28a745,color:#fff
style C fill:#e67e22,color:#fff
style H fill:#e67e22,color:#fff
style I fill:#ffc107,color:#333
access_token: expira en ~1 hora. Se renueva automáticamente con elrefresh_token.refresh_token: expira en ~90 días. Cuando expira, debes ejecutar/mail tokende nuevo.- Uso diario: nunca te pide autenticación. El
refresh_tokense renueva cada vez que se usa. - Primer uso o después de 90 días sin uso: ejecuta
/mail tokenpara reautenticar.
scripts/graph_auth.py— lógica de autenticación (caché → refresh → device code)~/.graph_tokens.json— caché de tokens (permisos 600, no se versiona)~/.secrets.yaml—CLIENT_IDyTENANT_IDbajo la claveGRAPH_API
- SMTP AUTH: deprecado por Microsoft a partir del 1 de marzo de 2026, con deshabilitación completa el 30 de abril de 2026. El modo
graphes el reemplazo oficial. - Firma en cada modo:
owaymacdelegan la firma a Outlook;graphla incluye como adjunto inline CID. - Plantillas HTML: las reglas de composición (estilos inline,
bgcoloren<td>, sin CSS externo) están enrulesets/MAIL.md. - Invocación: usa el skill
/mail <token|owa|mac|graph> <delivery|generic> <asunto>.
- Reglas de composición HTML:
~/rules/rulesets/MAIL.md - CoT de composición y entrega:
~/rules/cot/mail.md - Skill:
~/rules/.agents/skills/mail/SKILL.md - Script de autenticación:
~/rules/scripts/graph_auth.py - Plantillas:
~/rules/templates/mail/
Elaborado por Rodrigo Álvarez (@incognia)