go-imapsync: migración de buzones IMAP con un único binario en Go

Mascote do LinuxPro conectando o duto que migra as mensagens do servidor antigo para o novo, com o gopher do Go ao lado

Migrar correo electrónico no es solo copiar la INBOX: hay que trasladar carpetas, adjuntos y fechas sin borrar el origen, comprobar el resultado y buscar los mensajes que hayan llegado durante el cambio. O go-imapsync es una herramienta en Go para copiar buzones IMAP en una sola dirección, de host1 para host2, distribuida como un único binario y con detección de mensajes ya copiados mediante cabeceras.

El proyecto se inspira en el comportamiento de imapsync de Gilles Lamiral, pero tiene un alcance menor: no es un sustituto con todas las opciones del imapsync original. Esta guía utiliza la versión 0.1.3 y presenta una secuencia práctica para probar, copiar y validar una cuenta antes de migrar las demás.

Cómo funciona la copia

El programa se ejecuta en una máquina que puede alcanzar ambos servidores. Abre una conexión IMAP con cada cuenta, lista las carpetas, consulta las cabeceras existentes y transfiere los mensajes aún no reconocidos en el destino. No necesita estar instalado dentro del servidor de correo y no utiliza SMTP para transportar los mensajes.

Fluxo do go-imapsync: origem IMAP, máquina de migração e destino IMAP, com conexões TLS, comparação de cabeçalhos e sequência de simulação e cópia

El flujo es unidireccional. El origen no se borra; el destino recibe carpetas y mensajes. La herramienta no crea usuarios, no altera registros MX y no migra contactos, calendarios, alias ni reglas de filtrado del servidor. Estas tareas forman parte del plan de migración, pero no de la copia IMAP.

Al insertar un mensaje, se envían su contenido, la fecha interna del IMAP y las flags soportadas por la implementación y por el destino. Esto no significa mantener dos bandejas continuamente idénticas: los mensajes reconocidos como ya existentes se omiten, incluso sin una etapa de actualización de las flags que hayan cambiado después.

Antes de empezar

  • Autorización y cuentas: utilice únicamente buzones que gestione o para los que tenga autorización para migrar. La cuenta de destino debe existir.
  • Cuota: compruebe el espacio disponible en el destino, incluidos los elementos Enviados, los archivos adjuntos y el crecimiento durante la migración.
  • Autenticación: confirme que el proveedor admite el método de inicio de sesión utilizado. La versión 0.1.3 no implementa XOAUTH2; no asuma compatibilidad con un servicio que requiere OAuth.
  • Conectividad: la máquina de migración debe alcanzar los endpoints IMAP, normalmente por el puerto TCP 993 con TLS desde la conexión.
  • Piloto: comience con una cuenta pequeña y representativa, con subcarpetas, mensajes leídos/no leídos y archivos adjuntos.
  • Preservación: mantenga una copia de seguridad y acceso al servidor antiguo hasta la aceptación de la migración.

Si el destino forma parte de una instalación propia, la creación de cuentas y cuotas puede administrarse por separado por el go-postfixadmin. Copiar una caja no aprovisiona la infraestructura que va a recibirla.

Instalación en Linux

El ejemplo siguiente es para Linux x86_64. La release 0.1.3 también ofrece archivos para macOS ARM64 y Windows AMD64. No ejecute el paquete de otra arquitectura.

uname -m
mkdir -p "$HOME/Downloads/go-imapsync-0.1.3"
cd "$HOME/Downloads/go-imapsync-0.1.3"

curl -fL --retry 3 \
  -o go-imapsync_0.1.3_linux_amd64.tar.gz \
  https://github.com/jniltinho/go-imapsync/releases/download/v0.1.3/go-imapsync_0.1.3_linux_amd64.tar.gz

tar -tzf go-imapsync_0.1.3_linux_amd64.tar.gz
tar -xzf go-imapsync_0.1.3_linux_amd64.tar.gz
sudo install -m 0755 go-imapsync /usr/local/bin/go-imapsync

go-imapsync version
go-imapsync --help

El binario ya compilado no requiere la instalación de Go para ejecutarse. Descargue únicamente desde el repositorio oficial y utilice el mecanismo de verificación proporcionado en la release, cuando esté disponible; calcular un hash local sin una referencia fiable no autentica el archivo.

Para compilar la misma versión, el go.mod declara Go 1.26.0. Con una herramienta Go compatible, Git y Make instalados:

git clone --branch v0.1.3 --depth 1 https://github.com/jniltinho/go-imapsync.git
cd go-imapsync
make build
make test
./dist/go-imapsync version

make build produce dist/go-imapsync; make test ejecuta las pruebas con detector de condiciones de carrera. El Makefile de la versión es la referencia para los destinos de compilación.

Preparar credenciales sin dejarlas en el historial

Los siguientes ejemplos usan Bash. Indique las contraseñas de forma interactiva: no quedan escritas en el comando ni se muestran al escribirlas. Ejecute todo en la misma sesión del shell.

umask 077
mkdir -p "$HOME/go-imapsync-logs"

read -rsp 'Senha da origem: ' GOIMAPSYNC_PASSWORD1; printf '\n'
read -rsp 'Senha do destino: ' GOIMAPSYNC_PASSWORD2; printf '\n'
export GOIMAPSYNC_PASSWORD1 GOIMAPSYNC_PASSWORD2

# Substitua servidores e usuários pelos valores reais.
IMAP_ARGS=(
  --host1 imap.origem.example --user1 alice@origem.example
  --host2 imap.destino.example --user2 alice@destino.example
)

Las variables de entorno evitan la contraseña en los argumentos del programa, pero no son una caja fuerte: los procesos y operadores con permisos suficientes pueden acceder a ellas. No use set -x, no imprima el entorno y no envíe registros sin revisarlos. El programa intenta ocultar las contraseñas en sus propios registros; esto no protege el historial del shell, las herramientas externas ni una captura de pantalla.

Cuatro etapas: simular, crear carpetas, planificar y copiar

Ejecute un paso cada vez y compruebe el resultado antes del siguiente. El primero no crea carpetas ni inserta mensajes:

go-imapsync "${IMAP_ARGS[@]}" --justfolders --dry

Verifique el árbol de carpetas. Si los nombres o la jerarquía son incorrectos, deténgase: no intente compensarlo creando datos en el lugar equivocado. Después cree solo la estructura en el destino:

go-imapsync "${IMAP_ARGS[@]}" --justfolders

Ahora simule la copia de los mensajes. El programa se conecta a los servidores y consulta las cabeceras, pero no ejecuta CREATE o APPEND en el destino:

go-imapsync "${IMAP_ARGS[@]}" --dry \
  --logfile "$HOME/go-imapsync-logs/plano.log"

Sin errores de autenticación, carpetas o conectividad, inicie la copia real y capture inmediatamente el código de salida:

go-imapsync "${IMAP_ARGS[@]}" \
  --logfile "$HOME/go-imapsync-logs/copia.log"
rc=$?
printf 'Código de saída: %s\n' "$rc"

La CLI distingue el éxito (0), error de ejecución (1) y error de uso/configuración (2). Lea también el resumen de mensajes transferidos, omitidos y fallidos. En una simulación, el recuento de transferencia representa lo que se haría, no mensajes realmente grabados.

IMAPS y STARTTLS: no confundas las opciones

El valor predeterminado es IMAPS con TLS desde el inicio, en el puerto 993. Cuando un servidor exige STARTTLS en el puerto 143, desactive el modo IMAPS y habilite explícitamente la negociación TLS para ese lado. Ejemplo con ambos servidores en STARTTLS:

# Acrescente estas opções antes das etapas de migração,
# somente se ambos os servidores exigirem STARTTLS:
IMAP_ARGS+=(--nossl1 --tls1 --port1 143 --nossl2 --tls2 --port2 143)
go-imapsync "${IMAP_ARGS[@]}" --justfolders --dry

Si solo el origen usa STARTTLS, aplique únicamente las opciones terminadas en 1; mantenga el destino en el valor predeterminado IMAPS. Utilice el nombre de host correspondiente al certificado. Un error de certificado exige revisar el hostname, la validez y la cadena de confianza, no añadir --insecuretls en producción.

A documentación de buenas prácticas detalla TLS, capacidad del destino, reanudación y cuidados con las credenciales.

Incremental no significa “imposible duplicar”

La comparación ocurre por carpeta y utiliza, por defecto, las cabeceras Message-Id e Received, no el UID IMAP. Si la clave calculada ya existe en el destino, el mensaje se omite. Esta decisión permite repetir la ejecución para buscar lo que llegó después, pero no compara el contenido completo byte a byte.

  • Si ninguno de los encabezados seleccionados aporta una identidad, el mensaje puede volver a transferirse en otra ejecución.
  • Si los encabezados utilizados en la identidad se modifican entre servidores, la comparación puede no reconocer la copia anterior.
  • Mensajes diferentes con la misma identidad pueden considerarse iguales; reducir la comparación a menos campos exige evaluar ese riesgo.
  • Cambiar --useheader entre rondas altera el criterio de identificación. Realice pruebas en una cuenta piloto, no por ensayo y error en todas las cajas.

El detalle está en el cálculo de la identidad y en flujo de sincronización. Por eso, “omitir mensajes reconocidos” es una descripción más precisa que garantizar la ausencia absoluta de duplicados.

Cómo comprobar y finalizar la migración

Después de la copia, ejecute otra simulación con los mismos parámetros:

go-imapsync "${IMAP_ARGS[@]}" --dry \
  --logfile "$HOME/go-imapsync-logs/verificacao.log"

En una caja sin nuevas entregas y con identidades estables, se espera que no haya mensajes pendientes. Esto es una comprobación operativa, no una validación criptográfica integral. Abra el webmail del destino y verifique muestras en INBOX, Enviados y subcarpetas: cuerpo, adjuntos, fechas y estado de lectura. Compare los recuentos por carpeta investigando las diferencias, en lugar de asumir que totales iguales prueban una migración correcta.

Planifique el cambio de los clientes y de la entrega del correo por separado. Una estrategia operativa es hacer la copia inicial, coordinar el cambio y repetir la sincronización para capturar mensajes que aún se reciban en el servidor antiguo. Evite que los usuarios modifiquen libremente ambas bandejas: la herramienta no reconcilia cambios en dos direcciones.

Mantenga el origen disponible hasta validar el uso real. Si necesita volver después de recibir mensajes en el destino, esos mensajes nuevos también necesitan un plan de recuperación; solo reenfocar los clientes puede ocultar parte del historial. Al terminar, elimine las contraseñas de la sesión:

unset GOIMAPSYNC_PASSWORD1 GOIMAPSYNC_PASSWORD2
unset IMAP_ARGS

Errores comunes y qué verificar

Síntoma Acción
OVERQUOTA en el destino Aumente la cuota o libere espacio con autorización. Después repita la copia y verifique el resumen; no borre el origen para sortear el error.
Conexión cerrada o tiempo de espera agotado Verifique la red, los límites del servidor y los registros. Resuelva la causa antes de repetir; aumentar --timeout no corrige credenciales ni cuota.
Fallo de inicio de sesión Verifique el usuario completo, la contraseña y la política del proveedor. El acceso por el webmail no demuestra que el inicio de sesión IMAP por contraseña esté habilitado.
Certificado no válido Corrija el endpoint o la confianza de la CA. No desactive la verificación TLS como solución permanente.
Los mensajes reaparecen en cada ronda Investigue las cabeceras de identidad y posibles transformaciones en el destino antes de cambiar --useheader.

La herramienta puede ejecutarse de nuevo después de corregir el fallo. Lo que ya se copió se reconocerá según el mismo criterio de cabeceras; esto no elimina las limitaciones descritas arriba.

Ejecutar con Docker

El repositorio incluye un Dockerfile. En el árbol de la versión elegida, compile la imagen y confirme que se ejecuta. Para la prueba de conexión, prepare de nuevo las variables de contraseña si ya las ha usado unset:

make docker-build
docker run --rm go-imapsync:dev version

docker run --rm \
  -e GOIMAPSYNC_PASSWORD1 \
  -e GOIMAPSYNC_PASSWORD2 \
  go-imapsync:dev \
  --host1 imap.origem.example --user1 alice@origem.example \
  --host2 imap.destino.example --user2 alice@destino.example \
  --justfolders --dry

No es necesario usar un contenedor con privilegios. Las contraseñas se facilitan en la ejecución, no en el Dockerfile, pero los usuarios con acceso administrativo a Docker pueden inspeccionar el entorno del contenedor. Restrinja ese acceso y no persista credenciales en imágenes.

Límites de la versión y siguientes pasos

La versión 0.1.3 es un MVP centrado en la copia IMAP. Filtros y mapeo configurable de carpetas, exclusiones con --delete1/--delete2, XOAUTH2, tratamiento específico de etiquetas de Gmail y migración masiva por CSV aparecen como trabajo futuro en el repositorio, no como funciones entregadas ni como promesa de plazo.

El código usa licencia MIT. En esta revisión, se comprobaron la versión y la ayuda del binario de la release y la suite de la etiqueta 0.1.3 pasó con go test -race ./..., usando las pruebas locales del proyecto. Esto no sustituye un ensayo contra los servidores reales de su migración.

La ganancia es simplificar la ejecución de la copia; el cuidado sigue siendo operativo: piloto, cuota, TLS, logs y validación. Para archivos y almacenamiento en la nube, el problema es distinto: consulte la guía de rclone en Linux. Para el correo electrónico, mantenga el procedimiento centrado en los buzones IMAP y solo cierre el servidor antiguo tras comprobar los datos.