Buscar y borrar correos dentro del buzón de una cuenta con crad-log-search


#1

Introducción

crad-log-search.pyc es la herramienta de búsqueda de Core-Admin. Además de buscar en los logs del sistema (correo, syslog, Roundcube, etc.), sabe buscar dentro del propio buzón de una cuenta de correo almacenado en Dovecot, recorriendo los ficheros Maildir de la cuenta.

Sobre esa búsqueda se apoyan tres operaciones muy habituales en soporte:

  • Localizar los mensajes que contienen un texto determinado (--mbox), sin necesidad de que el cliente busque él mismo desde su cliente de correo.
  • Rescatar un falso positivo que ha ido a parar a la carpeta de spam, devolviéndolo a la bandeja de entrada (--move-to-inbox).
  • Limpiar en bloque todos los mensajes que coinciden con un criterio (--remove-selected y --confirm-remove-selected), por ejemplo los miles de rebotes MAILER-DAEMON que se acumulan tras una campaña de envíos fallida o tras un compromiso de la cuenta.

Este artículo explica cómo se usan estas opciones, qué información muestran y qué precauciones conviene tomar antes de borrar nada.

Requisitos previos

  • Core-Admin instalado en el servidor de correo, con el agente activo
  • Almacenamiento de correo en formato Maildir de Dovecot, bajo /var/spool/dovecot/mail/<dominio>/<usuario>/
  • Acceso root por SSH al servidor de correo (todas las operaciones se hacen desde la línea de comandos)
  • Conocer la cuenta sobre la que se va a trabajar (usuario@dominio.com)

Nota: estas opciones actúan sobre los ficheros del buzón. Antes de borrar en una cuenta de un cliente, conviene tener claro qué se va a borrar (para eso está el modo simulación) y, si el volumen es grande o el contenido dudoso, contar con la copia de seguridad del servidor.

Buscar dentro del buzón de una cuenta

La opción --mbox recibe la cuenta y busca el texto indicado dentro de los mensajes del buzón:

crad-log-search.pyc --mbox gabriel@ejemplo.com "factura"

Por defecto se revisan los mensajes modificados en los últimos 10 días. El intervalo se amplía con -D:

crad-log-search.pyc --mbox gabriel@ejemplo.com -D 30 "factura"

El resultado es un listado de líneas coincidentes: cada línea muestra la ruta del fichero del mensaje y el fragmento que ha coincidido. Un mismo mensaje aparece tantas veces como líneas coincidan dentro de él, por lo que es normal ver miles de líneas para unos pocos cientos de correos:

INFO: searching [MAILER-DAEMON] in [mbox]
[log: ...] /var/log/core-admin-mbox-search-1788277532.48.log: Found (4645) matches
001: /var/spool/dovecot/mail/ejemplo.com/gabriel/.Trash/cur/1786871854.M603052P3676.mailserver01,S=7944,W=8154:2,:Return-Path: <MAILER-DAEMON>
002: /var/spool/dovecot/mail/ejemplo.com/gabriel/.Trash/cur/1786871854.M603052P3676.mailserver01,S=7944,W=8154:2,:From: MAILER-DAEMON@mailserver01.ejemplo.com (Mail Delivery System)
...

La búsqueda no distingue mayúsculas de minúsculas y busca texto literal (no expresiones regulares), tanto en las cabeceras como en el cuerpo del mensaje.

Añadiendo --verbose se muestra el comando interno ejecutado, útil para reproducir la búsqueda a mano o para ajustar el criterio.

Devolver un mensaje a la bandeja de entrada

Cuando la búsqueda localiza un mensaje legítimo que ha acabado en la carpeta de spam, se puede devolver al INBOX de la misma cuenta pasando la ruta exacta que imprime --mbox:

crad-log-search.pyc --move-to-inbox '/var/spool/dovecot/mail/ejemplo.com/gabriel/.Spam/cur/1781254525.M133631P26020.mailserver01,S=168170,W=170460:2,a'

Antes de mover, la herramienta valida que la ruta apunta a un mensaje real dentro del almacenamiento de una cuenta, deriva la cuenta a partir de la propia ruta, rechaza los mensajes que ya están en el INBOX, regenera un nombre Maildir único y conserva los flags IMAP estándar (leído, respondido, etc.) descartando las etiquetas propias de la carpeta de origen. Muestra un resumen y pide confirmación, que se puede omitir con -y.

Borrado masivo de los mensajes encontrados

Paso 1: simulación (no borra nada)

--remove-selected repite la misma búsqueda de --mbox pero informa por mensaje en lugar de por línea coincidente, mostrando de cada uno la fecha, la carpeta, el tamaño y el asunto. Por sí sola no borra nada: es un informe de simulación.

crad-log-search.pyc --mbox gabriel@ejemplo.com -D 30 --remove-selected "MAILER-DAEMON"
Mensajes seleccionados para BORRADO
-----------------------------------
  Cuenta:    gabriel@ejemplo.com
  Búsqueda:  MAILER-DAEMON
  Intervalo: last 30 days

001: 2026-08-28 19:53  [Trash]     2.90 KB  Undelivered Mail Returned to Sender
     /var/spool/dovecot/mail/ejemplo.com/gabriel/.Trash/cur/1788205293.M217439P24466.mailserver01,S=6740,W=6911:2,S
002: 2026-08-28 23:58  [Trash]    10.91 KB  ***SPAM*** Undeliverable: A new message is calling your name
     /var/spool/dovecot/mail/ejemplo.com/gabriel/.Trash/cur/1788205546.M559752P31130.mailserver01,S=41944,W=42743:2,S
...

--- Resumen ---
  Mensajes seleccionados: 2652
  Espacio a liberar:      10.17 MB
    [Deleted Messages]: 33
    [INBOX]: 2533
    [Trash]: 86

SIMULACIÓN: no se ha borrado nada.
Para aplicar el borrado, repita el mismo comando añadiendo --confirm-remove-selected

El desglose por carpeta del resumen es la parte más importante de la simulación: el criterio de búsqueda selecciona mensajes esté donde esté, y en el ejemplo anterior la inmensa mayoría (2533 de 2652) están en el INBOX, no en la papelera. Conviene revisarlo antes de confirmar y, si hace falta, afinar el texto buscado o reducir el -D para acotar la selección.

Paso 2: aplicar el borrado

Cuando el listado es el esperado, se repite exactamente el mismo comando cambiando la opción por --confirm-remove-selected:

crad-log-search.pyc --mbox gabriel@ejemplo.com -D 30 --confirm-remove-selected "MAILER-DAEMON"

La herramienta vuelve a imprimir el listado y el resumen, borra los ficheros y muestra el resultado:

OK: borrados 2652 mensaje(s), 10.17 MB liberados en el buzón gabriel@ejemplo.com.
    Buzón reindexado (doveadm force-resync). Los clientes dejarán de mostrar los mensajes tras la siguiente sincronización.

Tras el borrado se ejecuta automáticamente doveadm force-resync sobre la cuenta, para que Dovecot regenere sus índices y los clientes de correo dejen de mostrar los mensajes eliminados. Si doveadm no estuviera disponible o fallara, la herramienta lo indica con un aviso y muestra el comando a ejecutar manualmente.

El borrado es definitivo: los ficheros se eliminan del disco, no se mueven a la papelera. La única forma de recuperarlos es la copia de seguridad del servidor.

Resumen de opciones

Opción Descripción
--mbox <cuenta> Busca el texto dentro del buzón Dovecot de la cuenta indicada
-D <días> Ventana de búsqueda: mensajes modificados en los últimos N días (10 por defecto)
--remove-selected Informe por mensaje (fecha, carpeta, tamaño y asunto) de lo que se borraría. No borra
--confirm-remove-selected Aplica el borrado del listado anterior y reindexa el buzón
--move-to-inbox <ruta> Devuelve un mensaje concreto al INBOX de su propia cuenta
-v, --verbose Muestra los comandos internos ejecutados

Detalles técnicos

Cómo se seleccionan los mensajes

  • La búsqueda recorre /var/spool/dovecot/mail/<dominio>/<usuario>/ con find, limitándose a ficheros de mensaje (nombres Maildir con S=) modificados dentro de la ventana -D, y busca el texto con zgrep (texto literal, sin distinguir mayúsculas).
  • En modo --remove-selected la búsqueda usa zgrep -l, que reporta una vez cada fichero coincidente. Por eso el número de mensajes del informe es mucho menor que el número de líneas que muestra la búsqueda normal con --mbox.
  • Se recorren todas las carpetas de la cuenta: INBOX, .Trash, .Deleted Messages, .Spam y cualquier otra carpeta IMAP del usuario.

De dónde salen la fecha y el asunto

De las cabeceras del propio mensaje. La herramienta lee el bloque de cabeceras (desplegando las líneas continuadas), decodifica el asunto codificado en MIME (RFC 2047: base64 y quoted-printable, con acentos correctos) y formatea la cabecera Date: en hora local. Si un mensaje no tiene Date: o no se puede interpretar, se usa la fecha de modificación del fichero; si tampoco, se muestra (unknown). Cuando falta el asunto se indica (sin asunto).

Los mensajes comprimidos por el plugin zlib de Dovecot se descomprimen de forma transparente si usan gzip.

Salvaguardas

  • Cada ruta candidata se valida antes de tocarla: debe ser un fichero regular, estar dentro de una carpeta cur o new de un buzón Maildir y pertenecer exactamente a la cuenta indicada en --mbox. Cualquier otra ruta se descarta.
  • --remove-selected sin --mbox es un error: la operación siempre está acotada a una cuenta.
  • El texto de búsqueda no puede contener comillas simples.
  • Toda operación de borrado queda registrada en el log del sistema, indicando cuántos mensajes se han eliminado, cuánto espacio se ha liberado, sobre qué cuenta y con qué criterio de búsqueda.

Preguntas frecuentes

¿Puedo borrar sólo los mensajes de la papelera?
No con un filtro de carpeta: la selección es por contenido, no por carpeta. Lo que sí se puede hacer es revisar el desglose por carpeta de la simulación y afinar el texto buscado hasta que la selección sea la deseada.

¿Por qué la simulación muestra menos mensajes que líneas la búsqueda con --mbox?
Porque --mbox muestra cada línea coincidente y un mismo correo suele contener varias (Return-Path:, From:, cuerpo…), mientras que la simulación cuenta correos.

¿Afecta el borrado a las cuotas del buzón?
Sí. Tras el force-resync Dovecot recalcula los índices y el espacio liberado se refleja en la cuota de la cuenta.

¿Y si el cliente tenía el correo abierto durante el borrado?
El cliente puede seguir mostrando los mensajes hasta la siguiente sincronización de la carpeta. Al refrescar desaparecen; los índices ya se han regenerado en el servidor.

¿Puedo lanzar esto desde el panel web?
No: por ahora es una operación exclusiva de línea de comandos, precisamente por su carácter destructivo.