# Configurar la aplicación de Microsoft Graph (MSAL) El proyecto lee y envía correo con Microsoft Graph usando una **aplicación registrada en Microsoft Entra ID** (antes Azure AD) y el flujo *client credentials*: no hay usuario interactivo, la aplicación se autentica sola con un `CLIENT_ID` y un `CLIENT_SECRET`. Este documento explica cómo obtener cada valor del `.env`. | Variable del `.env` | De dónde sale | |---------------------|---------------| | `CLIENT_ID` | *Application (client) ID* de la aplicación | | `TENANT_ID` | *Directory (tenant) ID* de la aplicación | | `CLIENT_SECRET` | **Value** de un *client secret* creado en esa misma aplicación | | `EMAIL` | Dirección del buzón que se lee y desde el que se envía | > Los pasos describen el portal de Azure tal como suele verse; los nombres de los menús cambian de vez en cuando. ## 1. Registrar la aplicación 1. Entra a (o al portal de Azure) con una cuenta con permisos para registrar aplicaciones. 2. **Identity → Applications → App registrations → New registration**. 3. Nombre, por ejemplo `descarga-factura-transporte`. En *Supported account types* elige **Accounts in this organizational directory only** (un solo tenant). No hace falta *Redirect URI*. 4. En la página **Overview** de la aplicación copia: - **Application (client) ID** → `CLIENT_ID` - **Directory (tenant) ID** → `TENANT_ID` Los dos tienen que salir de la **misma** aplicación. Un `CLIENT_ID` de una aplicación con el `TENANT_ID` de otro directorio da el error `AADSTS700016`. ## 2. Dar permisos Con el flujo *client credentials* se usan permisos de **aplicación**, no delegados. 1. **API permissions → Add a permission → Microsoft Graph → Application permissions**. 2. Agrega solo lo que el código usa: | Permiso | Para qué | Dónde se usa | |---------|----------|--------------| | `Mail.Read` | Listar la bandeja de entrada y descargar adjuntos | `get_emails`, `download_attachments` | | `Mail.Send` | Enviar las notificaciones | `send_email` | 3. Pulsa **Grant admin consent for **. Sin el consentimiento de administrador los permisos de aplicación no tienen efecto, aunque aparezcan en la lista. > **Ojo:** un permiso de aplicación de correo vale, por defecto, para **todos los buzones** del tenant. Conviene limitarlo al buzón del proyecto con una política de acceso de aplicaciones en Exchange Online (*Application Access Policy* o *RBAC for Applications*). Eso lo configura un administrador de Exchange. ## 3. Crear el client secret 1. **Certificates & secrets → Client secrets → New client secret**. 2. Descripción y vencimiento (el portal permite hasta 24 meses). 3. Al crearlo, copia la columna **Value** y guárdala de inmediato en `CLIENT_SECRET`. **Solo se muestra una vez.** Se confunde con frecuencia: la columna **Secret ID** es un identificador, no sirve como secret. Si usas el *Secret ID* el error es `AADSTS7000215`. Cada secret **vence**. Anota la fecha en un calendario: cuando vence, el demonio deja de poder autenticarse y no lee ni envía correo (error `AADSTS7000222`). Para renovar sin cortes, crea el secret nuevo antes, actualiza el `.env`, reinicia el demonio y recién entonces borra el viejo. ## 4. Completar el `.env` ``` CLIENT_ID = TENANT_ID = CLIENT_SECRET = EMAIL = buzon@tu-dominio.com ``` El `.env` no se sube a git. No pegues el secret en chats, tickets ni commits. ## 5. Verificar Pide un token sin enviar nada. Imprime solo el resultado, no el secret: ```bash python -c " import re, outlook_utilities as o try: o.get_access_token(); print('OK: token obtenido') except Exception as e: print('ERROR', re.findall(r'AADSTS\d+', str(e)) or e)" ``` Un `OK` confirma `CLIENT_ID`, `TENANT_ID` y `CLIENT_SECRET`. No confirma los permisos sobre el buzón: eso se comprueba al listar o enviar un correo, por ejemplo con `tools/previsualizar_plantillas.py --escenario aceptado_sin_pago --enviar tu@correo`. ## Errores frecuentes | Código | Significa | Qué revisar | |--------|-----------|-------------| | `AADSTS7000222` | El client secret **venció** | Crear un secret nuevo (paso 3) | | `AADSTS7000215` | Secret inválido | Se usó el *Secret ID* en vez del *Value*, o hay un error al copiarlo | | `AADSTS700016` | La aplicación no existe en ese directorio | `CLIENT_ID` y `TENANT_ID` deben ser de la misma aplicación (paso 1) | | `AADSTS90002` | El tenant no existe | `TENANT_ID` mal escrito | | `403` / `ErrorAccessDenied` al leer o enviar | Faltan permisos o consentimiento, o una política de acceso excluye al buzón | Paso 2 y la política de Exchange | | `404` / `MailboxNotFound` | El buzón de `EMAIL` no existe o no tiene licencia | Revisar `EMAIL` | Para cualquier código `AADSTS`, el mensaje completo trae un *Trace ID* y una explicación; la lista oficial está en la documentación de Microsoft Entra, sección de códigos de error de autenticación.