User hosna reports that new signups using email subaddresses (e.g., email+1@gmail.com) are blocked via REST API, even though the normalize_emails setting is disabled. JammyDodger initially suggests checking that setting, but hosna confirms it’s off. supermathie tests on try.discourse.org and can’t reproduce the issue, asking for console output and version info. hosna provides console results showing the base email is blocked, and the error message translates to “Primary email is not allowed.” supermathie clarifies the block is likely due to the base email being on a blocklist, not normalization. hosna notes the behavior seems inconsistent with disabled normalization. supermathie explains that Discourse intentionally blocks subaddresses of blocked emails as an anti-griefing measure, regardless of settings. The underlying code checks the canonical email (stripping + and . for Gmail) and uses Levenshtein distance (default 2) to catch similar addresses — which explains why email+1@gmail.com is blocked if email@gmail.com is. supermathie links to the relevant code in screened_email.rb for transparency.
It seems in a recent update, new signup with same email including a + to represent a new email isnt allowed. my system is highly dependent on it. how to enable it again?
I did exactly the same and could not duplicate the problem on the latest code running live - it behaved as expected with the normalize emails setting disabled:
In this case we almost definitely block subaddresses of blocked addresses regardless of the setting as an anti-griefing measure since the normalisation option is not the default.
“Only show overridden” in settings. But now I suspect we don’t need to worry about that.
Back at my desk I took a look at the actual code that does this rejection:
Right at the top we’re checking the canonical email against the blocklist:
def self.canonical(email)
name, domain = email.split("@", 2)
name = name.gsub(/\+.*/, "")
name = name.gsub(".", "") if %w[gmail.com googlemail.com].include?(domain.downcase)
"#{name}@#{domain}".downcase
end
And even if that didn’t catch it, it would be caught by the Levenshtein distance check here: