Version de Discourse : 2026.5.0-latest.1
Contexte
Lorsqu’un utilisateur externe envoie un e-mail au gestionnaire de courrier entrant en utilisant une variante « point » de Gmail (par exemple, user.name@gmail.com) alors que son compte de forum enregistré est la version principale sans point (username@gmail.com), le gestionnaire de courrier entrant plante avec une exception non gérée : ActiveRecord::RecordInvalid (Validation failed: Primary email has already been taken).
De plus, toute tentative de résoudre ce problème en ajoutant la variante avec points comme e-mail secondaire au profil de l’utilisateur — que ce soit via l’interface utilisateur ou la couche modèle de la console Rails en utilisant UserEmail.create! — échoue avec la même erreur de boucle de validation. La seule solution de contournement consiste à exécuter une injection SQL brute dans la base de données, en contournant ActiveRecord.
Étapes pour reproduire le problème
-
Créez un compte utilisateur sur Discourse avec l’e-mail principal
username@gmail.com. -
Demandez à cet utilisateur d’envoyer un e-mail entrant à une adresse de catégorie/réponse depuis
user.name@gmail.com. -
Observez le rejet dans les journaux de courrier entrant en raison de
ActiveRecord::RecordInvalid. -
Essayez d’ajouter
user.name@gmail.comcomme e-mail secondaire au compteusername@gmail.comvia la console Rails :UserEmail.create!(user_id: target_id, email: 'user.name@gmail.com', primary: false) -
Observez le plantage de la validation du modèle.
Comportement attendu
Discourse gère la normalisation des adresses Gmail de manière fluide. Il devrait soit :
-
Reconnaître la variante Gmail avec points entrante comme appartenant au compte principal de manière transparente lors de la phase de traitement du courrier entrant.
-
À tout le moins, permettre à un administrateur d’ajouter la variante avec points comme e-mail secondaire au compte principal sans déclencher un blocage de l’application du type « E-mail principal déjà pris », puisqu’il appartient au même utilisateur et est explicitement défini sur
primary: false.
Comportement réel
La couche application reste bloquée dans une boucle logique :
-
Elle considère
user.name@gmail.comcomme une chaîne « nouvelle », elle tente donc d’agir dessus (créer un utilisateur en attente ou ajouter un e-mail secondaire). -
Lors de la phase de validation, le modèle
UserEmailexécute sa logique de normalisation Gmail, supprime les points, constate queusername@gmail.comest déjà l’index d’e-mail principal pour cetuser_id, et bloque son propre exécution en supposant à tort qu’un conflit de doublon de registre se produit.
Solution de contournement utilisée pour débloquer la situation
La seule façon de résoudre ce problème était de se connecter en SSH au conteneur et d’exécuter du SQL brut pour contourner complètement les validations d’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)
Une fois forcé via du SQL brut, le suivi du courrier entrant fonctionne parfaitement. Le code de validation devrait être mis à jour pour tenir compte de ce cas limite.
Merci !