40 lines
2.8 KiB
Markdown
40 lines
2.8 KiB
Markdown
# outlook_utilities.py — Microsoft Graph (Outlook)
|
||||
|
|
|
|||
|
|
Cliente mínimo de Microsoft Graph para leer la bandeja de entrada, bajar adjuntos y enviar las notificaciones. Autenticación con MSAL (client credentials, permisos de aplicación).
|
|||
|
|
|
|||
|
|
## Estructura
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
outlook_utilities.py
|
|||
|
|
├── CONFIG (.env): CLIENT_ID, CLIENT_SECRET, TENANT_ID, VERIFY_SSL (false por defecto)
|
|||
|
|
├── get_access_token() → str
|
|||
|
|
├── get_emails(user_email, token, fecha_inicio, fecha_fin) → list[dict]
|
|||
|
|
├── download_attachments(user_email, message_id, token, download_path) → list[str]
|
|||
|
|
└── send_email(access_token, from_email, to_recipients, subject, html_body,
|
|||
|
|
attachment_paths=None, cc_recipients=None) → bool
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Funciones
|
|||
|
|
|
|||
|
|
| Función | Endpoint Graph | Qué hace |
|
|||
|
|
|---------|----------------|----------|
|
|||
|
|
| `get_access_token` | `login.microsoftonline.com/{TENANT_ID}` (scope `.default`) | Obtiene el token de aplicación. Lanza `Exception` si MSAL devuelve error. |
|
|||
|
|
| `get_emails` | `GET /users/{user}/mailFolders/Inbox/messages` | Correos de la bandeja de entrada del rango, con paginación (`$top=50`, sigue `@odata.nextLink`). Devuelve `id`, `fecha`, `sender`, `subject`, `has_attach`. Lanza `Exception` si el status no es 200. |
|
|||
|
|
| `download_attachments` | `GET /users/{user}/messages/{id}/attachments` | Guarda en `download_path` los adjuntos tipo archivo y devuelve sus nombres. Crea la carpeta si no existe. |
|
|||
|
|
| `send_email` | `POST /users/{from}/sendMail` | Envía HTML con adjuntos y CC; guarda copia en Enviados. Devuelve `True` si Graph responde 202; `False` (con `ERROR` en el log) en cualquier otro caso. No lanza excepciones. |
|
|||
|
|
|
|||
|
|
## Zona horaria
|
|||
|
|
|
|||
|
|
`get_emails` asume UTC-5 (Perú, sin horario de verano): el rango `fecha_inicio`–`fecha_fin` se convierte a UTC sumando 5 h (el fin incluye todo el día), y el campo `fecha` devuelto resta 5 h a `receivedDateTime`.
|
|||
|
|
|
|||
|
|
## Adjuntos de `send_email`
|
|||
|
|
|
|||
|
|
Los adjuntos se leen de las rutas indicadas. Una ruta inexistente se omite con un `WARNING`. El `contentType` se deduce de la extensión (`.pdf`, `.xml`, `.json`; cualquier otra, `application/octet-stream`).
|
|||
|
|
|
|||
|
|
## Notas
|
|||
|
|
|
|||
|
|
- `download_attachments` solo guarda adjuntos tipo `fileAttachment` con contenido; los adjuntos de tipo mensaje o referencia se ignoran.
|
|||
|
|
- Dos correos con un adjunto del mismo nombre se sobrescriben entre sí si comparten `download_path` (el pipeline usa una única carpeta, `DOWNLOAD_FOLDER`).
|
|||
|
|
- `VERIFY_SSL` se respeta en `get_access_token`, `get_emails` y `download_attachments`, pero `send_email` tiene `verify_ssl = False` fijo y lo ignora.
|
|||
|
|
- El módulo ejecuta `warnings.filterwarnings("ignore")`, lo que silencia todas las advertencias de Python del proceso (incluidas las de certificado SSL).
|
|||
|
|
- `get_access_token` retorna `None` (sin lanzar error) si MSAL devuelve un resultado vacío.
|