Herramienta de recuperación de correos eliminados desde Recoverable Items de Exchange Online. Búsqueda, restauración individual y masiva con progreso en tiempo real.
Búsqueda y restauración asíncronas mediante worker threads. El browser recibe actualizaciones en tiempo real via Server-Sent Events con soporte de reconexión y replay completo.
Chunking por día para evitar $skip profundo. Busca en recoverableitemsdeletions, versions y purges. Resultados persistidos en SQLite 7 días.
Selección individual o "Restaurar todos". Graph $batch API en lotes de 4 (límite MailboxConcurrency Exchange). Destino: carpeta "Restore" del buzón.
Sin búsqueda previa. Cuenta ítems primero ($count Graph, ~2s). Restaura por lotes de 1 página volviendo a skip=0 — evita 504 en buzón grandes.
El admin introduce email y rango de fechas. La búsqueda corre en background con progreso SSE. La restauración también es asíncrona con barra de progreso en tiempo real.
POST /searchsearch_folder() en las 3 carpetas Recoverable Items → ordena por receivedDateTime DESCEventSource /search/stream?token=...). Si se desconecta, replay completo desde el historial del job.POST /restore/$batch en lotes de 4 → mueve mensajes a carpeta "Restore" del buzón del usuarioInforme visual de uso de Recoverable Items por política de retención. Datos via PowerShell Exchange Online — Get-Mailbox + Get-MailboxFolderStatistics en streaming.
retention6 | Política estándar 6 años |
retention10 | Equipo legal (10 años) |
retention0 | Proceso judicial activo (sin borrado) |
Por grupo: buzón, n.º ítems, tamaño total, política MRM, barra de distribución. Exportable a HTML (para Purview) y CSV. Streaming SSE — sin esperar a que termine todo para ver resultados.
| Módulo | Responsabilidad |
|---|---|
graph.py | Cliente Graph API: paginación automática, retry en 429/503/504, batch API. graph_get(), graph_count(), graph_batch_post() |
recovery.py | Lógica de búsqueda y restauración. Chunking por día, get_or_create_restore_folder(), restore_items_batch(), stream_restore_to_folder() |
exchange_ps.py | Wrapper PowerShell Exchange Online. stream_mailboxes_with_stats() con auth certificado CurrentUser\My |
search_db.py | SQLite historial búsquedas (TTL 7d). create_pending(), mark_done(), get_search(). Thread-safe con mutex. |
search_worker.py | Thread búsqueda. Acumula mensajes para replay SSE via threading.Condition() |
restore_worker.py | Thread restauración individual. Estado + resultado final en memoria. |
mass_restore_worker.py | Thread recuperación masiva. Itera páginas sin acumular $skip. Yield por ítem para CSV. |
report.py | Informe HTML restauración: resumen estadístico + tabla por ítem |
retention_report.py | Informe HTML retención: barras distribución, badges política MRM, totales |
| Ruta | Método | Descripción |
|---|---|---|
/ | GET | Formulario de búsqueda |
/search | POST | Inicia búsqueda (crea worker thread) |
/search/stream | GET | SSE: progreso búsqueda en tiempo real |
/results/{token} | GET | Resultados + selección para restaurar |
/restore | POST | Inicia restauración |
/restore/stream/{token} | GET | SSE: progreso restauración |
/restore/done/{token} | GET | Resultado final + descarga informe |
/history | GET | Historial búsquedas (7 días) |
/mass-restore | GET/POST | Recuperación masiva por rango de fechas |
/retention-stats | GET | Estadísticas retención por grupo |
/retention-stats/stream | GET | SSE: stats por CustomAttribute en tiempo real |
Graph falla con 504 si $skip > ~10.000 en buzón grandes. Solución: chunking por día en búsqueda. En restauración masiva: lote de 1 página (100 ítems), restaurar, volver a skip=0.
Exchange Online limita conexiones simultáneas a un buzón. La restauración usa Graph /$batch en lotes de 4 para no superar el límite.
Los workers acumulan mensajes en job["messages"] con threading.Condition(). Si el browser pierde la conexión, al reconectar recibe el historial completo desde el inicio.
Individual: filtra por receivedDateTime, restaura a carpeta "Restore". Masiva: filtra por lastModifiedDateTime (fecha borrado), restaura a carpeta original.
cd C:\apps\jmfernandez\mailrecover
.\deploy.ps1
# git pull + pip install sisapps-ui + restartms_graph.client_id | App Registration para Graph API |
ms_graph.certificate_thumbprint | Cert en CurrentUser\My |
server.port | Puerto (default 5000) |
search_history.ttl_days | Retención historial (default 7) |
sso.dev_bypass_upn | Bypass SSO en desarrollo |