Files
descarga_factura_transporte/docs/outlook_utilities.md
T
GeorgeandClaude Sonnet 5.5 4deb9d4e4d se responde al remitente con las plantillas de aceptado/rechazado
El sistema contesta a quien envió el correo con la plantilla que corresponda.
Por defecto (NOTIFICACION_MODO=prueba) la respuesta va solo al equipo con el
asunto "[PRUEBA → remitente]"; en modo real va al remitente con copia oculta
al equipo. El correo técnico (tablas de SAP, JSON) pasa a ir solo al equipo.

- respuesta_proveedor.py: contextos de las plantillas, envío y protecciones
  (remitente desconocido o sin dominio, propio buzón, no-reply, mensajes
  automáticos, respuestas a notificaciones, límite de 3 por remitente/24 h).
- observaciones.py: motivos de rechazo con título, filas y cómo corregir
  (borrador de textos); también para correos sin comprobante válido.
- Un error de SAP/HANA o un fallo inesperado no se le comunica al proveedor y
  ya no tumba el ciclo; "guía no encontrada" exige que HANA responda.
- outlook_utilities: es_mensaje_automatico y copia oculta en send_email.
- seguimiento: notificacion_destinatario (con migración) y
  contar_respuestas_correo.
- config_validator anuncia el modo activo; documentación y pruebas.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 08:55:54 -05:00

3.2 KiB
Raw Blame History

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). Cómo obtener las credenciales: configurar_msal.md.

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 y es_automatico (calculado con los encabezados del mensaje). 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, CC y copia oculta (bcc_recipients); 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.
  • es_mensaje_automatico(headers) marca como automáticos los mensajes con Auto-Submitted distinto de no, X-Auto-Response-Suppress, X-Autoreply, Precedence (bulk, junk, list, auto_reply) o Content-Type de informe de entrega (rebotes). El sistema no responde a esos mensajes.