Versión de Discourse: 2026.5.0-latest.1
Contexto
Cuando un usuario externo envía un correo electrónico al gestor de correo entrante utilizando una variante con «punto» de Gmail (por ejemplo, user.name@gmail.com), pero su cuenta registrada en el foro es la versión principal sin puntos (username@gmail.com), el gestor de correo entrante falla con una excepción no manejada: ActiveRecord::RecordInvalid (Validation failed: Primary email has already been taken).
Además, intentar resolver esto añadiendo la variante con puntos como correo secundario al perfil del usuario —ya sea mediante la interfaz de usuario o la capa de modelos de Rails Console usando UserEmail.create!— falla con el mismo error de bucle de validación. La única solución alternativa es una inyección SQL directa en la base de datos, eludiendo ActiveRecord.
Pasos para reproducir
-
Crea una cuenta de usuario en Discourse con el correo principal
username@gmail.com. -
Haz que ese usuario envíe un correo entrante a una dirección de categoría/respuesta desde
user.name@gmail.com. -
Observa el rechazo en los registros de correo entrante debido a
ActiveRecord::RecordInvalid. -
Intenta añadir
user.name@gmail.comcomo correo secundario a la cuentausername@gmail.comdesde la consola de Rails:UserEmail.create!(user_id: target_id, email: 'user.name@gmail.com', primary: false) -
Observa el fallo de validación del modelo.
Comportamiento esperado
Discourse debe manejar la normalización de Gmail de forma correcta. Debería:
-
Reconocer la variante con puntos de Gmail entrante como perteneciente a la cuenta principal de forma transparente durante la fase de gestión del correo entrante.
-
Como mínimo, permitir que un administrador añada la variante con puntos como correo secundario a la cuenta principal sin desencadenar un bloqueo de la aplicación por «correo principal ya tomado», ya que pertenece al mismo usuario y está explícitamente configurado como
primary: false.
Comportamiento real
La capa de aplicación queda atrapada en un bucle lógico:
-
Detecta
user.name@gmail.comcomo una cadena «nueva», por lo que intenta actuar sobre ella (crear un usuario provisional o añadir un correo secundario). -
Durante la fase de validación, el modelo
UserEmailejecuta su lógica de normalización de Gmail, elimina los puntos, detecta queusername@gmail.comya es el índice de correo principal para eseuser_idy bloquea su propia ejecución bajo la falsa premisa de que se está produciendo un conflicto de registro duplicado.
Solución alternativa utilizada para desbloquear
La única forma de resolver esto fue conectarse por SSH al contenedor y ejecutar SQL directo para eludir completamente las validaciones de ActiveRecord:
sql = "INSERT INTO user_emails (user_id, email, \"primary\", created_at, updated_at) VALUES (X, 'user.name@gmail.com', false, NOW(), NOW())"
ActiveRecord::Base.connection.execute(sql)
Una vez forzado mediante SQL directo, el seguimiento del correo entrante funciona perfectamente. El código de validación debería actualizarse para tener en cuenta este caso extremo.
¡Gracias!