Gmail 도트 변형 처리 또는 부 이메일 추가 시 기본 이메일이 이미 사용 중이라는 오류가 발생합니다

Discourse 버전: 2026.5.0-latest.1

배경

외부 사용자가 Gmail의 “점(dot)” 변형 주소(예: user.name@gmail.com)를 사용하여 수신 메일 핸들러에 이메일을 보냈으나, 해당 사용자의 등록된 포럼 계점이 점 없는 기본 버전(username@gmail.com)인 경우, 수신 메일 핸들러가 처리되지 않은 예외 ActiveRecord::RecordInvalid (Validation failed: Primary email has already been taken)와 함께 충돌합니다.

또한, 사용자 프로필에 점 있는 변형 주소를 부(secondary) 이메일로 추가하여 이를 해결하려는 시도(UI를 통해 또는 UserEmail.create!를 사용한 Rails 콘솔 모델 계층을 통해)는 동일한 검증 루프 오류로 실패합니다. 유일한 우회 방법은 ActiveRecord를 우회하여 데이터베이스에 원시 SQL을 주입하는 것입니다.

재현 단계

  1. Discourse에서 기본 이메일이 username@gmail.com인 사용자 계정을 생성합니다.

  2. 해당 사용자에게 user.name@gmail.com에서 카테고리/답글 주소로 수신 이메일을 보내게 합니다.

  3. ActiveRecord::RecordInvalid로 인해 수신 메일 로그에서 거부되는 것을 관찰합니다.

  4. Rails 콘솔을 통해 username@gmail.com 계정에 user.name@gmail.com을 부 이메일로 추가해 봅니다:

    UserEmail.create!(user_id: target_id, email: 'user.name@gmail.com', primary: false)
    
    
  5. 모델 검증 충돌을 관찰합니다.

예상 동작

Discourse는 Gmail 정규화를 깔끔하게 처리해야 합니다. 다음 중 하나가 되어야 합니다:

  1. 수신 메일 처리 단계에서 수신된 점 있는 Gmail 변형 주소를 기본 계정에 속하는 것으로 매끄럽게 인식해야 합니다.

  2. 최소한, 해당 주소가 동일한 사용자에게 속해 있고 primary: false로 명시적으로 설정되어 있으므로, 관리자가 “Primary email taken” 애플리케이션 블록을 트리거하지 않고 점 있는 변형 주소를 메인 계정의 부 이메일로 추가할 수 있어야 합니다.

실제 동작

애플리케이션 계층이 논리 루프에 갇힙니다:

  • user.name@gmail.com을 “새로운” 문자열로 인식하므로, 이를 처리하려고 합니다(단계적 사용자 생성 또는 부 이메일 추가).

  • 검증 단계에서 UserEmail 모델은 Gmail 정규화 로직을 실행하여 점을 제거하고, username@gmail.com이 해당 user_id의 이미 기본 이메일 인덱스임을 확인한 후, 중복 레코드 충돌이 발생한다고 잘못 판단하여 자신의 실행을 차단합니다.

사용된 우회 방법

이를 해결할 유일한 방법은 컨테이너에 SSH로 접속하여 ActiveRecord 검증을 완전히 우회하기 위해 원시 SQL을 실행하는 것이었습니다:

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로 강제 삽입한 후, 수신 메일 추적은 완벽하게 작동합니다. 이 엣지 케이스를 고려하도록 검증 코드가 업데이트되어야 합니다.

감사합니다!

4개의 좋아요

안녕하세요, @dennisjbr! :waving_hand:

이것은 실제로 버그인 것 같습니다. 오류 메시지에 나와 있듯이, 우리는 이메일들이 동일하다는 것을 알고 있습니다. 시간이 허락되면 오늘 밤 이 문제를 확인해 보겠습니다.

normailize_emails 사이트 설정을 false로 설정하여 이 동작을 비활성화할 수 있다고 생각합니다. 그러나 위에서 언급한 이메일 응답 경로에서 새로운 계정이 생성될 위험이 있습니다. 아직 코드에 대해 자세히 살펴보지 않았습니다.

2개의 좋아요

맞아요! 이 문제를 확인해 주셔서 정말 감사합니다.

리포트 감사합니다.

FIX: handle email aliases when normalize emails is enabled - Pull Request #42344 - discourse/discourse - GitHub 에서 변경 사항을 병합하여, 원시 검증 오류 대신 명확한 설명이 표시되도록 했습니다. 또한 UI에서 즉시 실패하도록 변경했으며, 클릭 시 오류가 발생하는 확인 링크를 이메일로 보내는 대신 즉시 실패합니다.

다만 normalize_emails가 활성화된 경우에도 별칭을 추가할 수 있는 문제는 해결되지 않았습니다. 정규화된 주소의 고유성 규칙이 의도적으로 설정된 것으로 생각되기 때문입니다.

3개의 좋아요

멋지네요, 감사합니다! 이메일 전송 실패와 dsicourse가 저를 위해 60,000개의 메시지를 생성한 문제에 대한 또 다른 보고서가 있습니다. 제 메모만 찾을 수 있으면 좋으련만… :slight_smile: