Версия Discourse: 2026.5.0-latest.1
Контекст
Когда внешний пользователь отправляет электронное письмо обработчику входящей почты, используя вариант с точкой в адресе Gmail (например, user.name@gmail.com), но его зарегистрированный аккаунт на форуме привязан к основному адресу без точек (username@gmail.com), обработчик входящей почты падает с необработанной ошибкой: ActiveRecord::RecordInvalid (Validation failed: Primary email has already been taken).
Более того, попытка решить эту проблему путём добавления варианта с точкой как дополнительного адреса электронной почты в профиль пользователя — будь то через интерфейс или на уровне модели Rails Console с использованием UserEmail.create! — завершается неудачей с той же ошибкой цикла валидации. Единственным обходным путём является прямое выполнение SQL-запроса к базе данных, минуя ActiveRecord.
Шаги для воспроизведения
-
Создайте аккаунт пользователя в Discourse с основным адресом
username@gmail.com. -
Попросите этого пользователя отправить входящее письмо на адрес категории/ответа с адреса
user.name@gmail.com. -
Обратите внимание на отказ в логах входящей почты из-за ошибки
ActiveRecord::RecordInvalid. -
Попробуйте добавить
user.name@gmail.comкак дополнительный адрес к аккаунтуusername@gmail.comчерез консоль Rails:UserEmail.create!(user_id: target_id, email: 'user.name@gmail.com', primary: false) -
Обратите внимание на сбой валидации модели.
Ожидаемое поведение
Discourse должен корректно обрабатывать нормализацию адресов Gmail. Он должен либо:
-
Без проблем распознавать входящий вариант Gmail с точками как принадлежащий основному аккаунту на этапе обработки входящей почты.
-
Как минимум, позволять администратору добавлять вариант с точкой в качестве дополнительного адреса к основному аккаунту, не вызывая блокировки приложения с сообщением «Основной адрес занят», поскольку он принадлежит тому же пользователю и явно установлен как
primary: false.
Фактическое поведение
Уровень приложения попадает в логический цикл:
-
Он видит
user.name@gmail.comкак «новый» строковый идентификатор и пытается выполнить действия с ним (создать временного пользователя или добавить дополнительный адрес). -
На этапе валидации модель
UserEmailзапускает свою логику нормализации Gmail, удаляет точки, обнаруживает, чтоusername@gmail.comуже является основным индексом адреса для данногоuser_id, и блокирует собственное выполнение, ошибочно полагая, что происходит конфликт дублирующихся записей.
Использованный обходной путь для разблокировки
Единственный способ решить проблему — подключиться по SSH к контейнеру и выполнить прямой SQL-запрос, полностью минуя валидации 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)
После принудительного добавления через прямой SQL отслеживание входящей почты работает безупречно. Код валидации следует обновить, чтобы учесть этот частный случай.
Спасибо!