fix(soporte): el buzón IMAP nunca se leía — la búsqueda pedía UIDs a una búsqueda por secuencia

Usé c.Search, que devuelve números de secuencia, y después le pedí los UIDs al
resultado. go-imap devuelve nil ahí, así que la lista salía siempre vacía: el
cron conectaba bien, buscaba bien, y se iba sin leer nada ni escribir un solo
error en el log. Va con UIDSearch.

Con eso se arreglan las dos cosas: no leía y no creaba tickets.

Además:
- Fetch con Peek: el correo queda marcado como leído solo si se llegó a
  procesar. Antes, un fallo a mitad de camino lo perdía para siempre.
- "Probar conexión" ahora informa cuántos mensajes hay en la carpeta y cuántos
  sin leer; "Revisar buzón ahora" informa cuántos encontró y cuántos convirtió
  en ticket, y avisa si la lectura está desactivada.
- Un correo sin asunto abre ticket como "(sin asunto)" en vez de descartarse en
  silencio, y los descartes quedan en el log.

Los tres tests nuevos corren contra un servidor IMAP en memoria: bajar los no
leídos, que marcar como leído los saque de la próxima corrida, y que bajarlos
sin procesarlos no los marque. El primero falla si se vuelve a poner Search.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-08-17 19:20:27 -05:00
co-authored by Claude Opus 5
parent d1bbb4a508
commit 5875f9e36b
5 changed files with 247 additions and 38 deletions
+7 -1
View File
@@ -26,9 +26,15 @@ var ticketRefRe = regexp.MustCompile(`(?i)\[Ticket #(\d+)\]`)
// ticket existente. Devuelve true si se procesó algo (false = ignorado por
// duplicado o por venir vacío).
func IngestarCorreoSoporte(cfg *models.SoporteWebhookConfig, e CorreoSoporte) bool {
if e.From == "" || e.Subject == "" {
if strings.TrimSpace(e.From) == "" {
log.Printf("[Soporte] Correo sin remitente, ignorado (asunto=%q)", e.Subject)
return false
}
// Un correo sin asunto es raro pero existe, y perderlo en silencio es peor
// que abrir un ticket con un título feo.
if strings.TrimSpace(e.Subject) == "" {
e.Subject = "(sin asunto)"
}
// Deduplicación: el proveedor puede reintentar la entrega, y el poller IMAP
// puede releer un correo si falló el marcado como leído.