The database schema for {user} does not require that email addresses are unique, and user_save() does not prevent saving multiple users with the same address. However, when user with a non-unique address submits the account form on user/123/edit, the form validation fails with the following error message:
The e-mail address c960657@example.com is already taken.
The error occurs, even if the registered mail address has not been changed, i.e. this prevents the user from changing other parts of the profile.
I know that other parts of Drupal does not properly handle duplicate email addresses, e.g. the lost password feature, but we should either fix those parts or enforce the uniqueness in the database schema and/or in user_save().
| Comment | File | Size | Author |
|---|---|---|---|
| #42 | 771002-42.patch | 3.56 KB | nikhil_110 |
| #42 | interdiff_41-42.txt | 603 bytes | nikhil_110 |
| #41 | 771002-41.patch | 3.57 KB | nikhil_110 |
| #41 | interdiff_39-41.txt | 2.91 KB | nikhil_110 |
| #39 | 771002-39.patch | 2.7 KB | Ankit.Gupta |
Comments
Comment #1
c960657 commentedThis patch adds a hidden setting. I think it's reasonable to make it hidden, because once you allow duplicate email addresses, you cannot just disallow them again without manually removing the duplicates.
The patch also modifies the lost password feature in a crude way, so that multiple mails are sent. This is not that user friendly, but I would like to hear some opinion on the general approach in this issue before I dig into the details.
Also, this needs tests.
Comment #2
Georg commentedMy personal take on this would be to only allow unique eMailadresses. One account per eMailadress.
The only people I could think of that need more than one account, would be admins. Those people I expect to have more than one eMailadress by hand anyway.
So I don't see a reason to allow multiaccounts per eMailadress.
But if it is easier to change everything to support multiple accounts per eMailadress, then I'm fine with that.
Comment #3
c960657 commentedIt's not unlikely that two people (e.g. married couples) share one email address.
In some setups, the user list in Drupal is mirrored from some other system, e.g. a single sign-on system. Any constraint added by Drupal that does not exist in the source system makes the mirroring harder. This is also a problem when mirroring users from two or more separate systems and you don't want to combine the profile fields of two different users even though they share an email address.
I'm not sure what the intention behind the current database scheme is, i.e. whether it's a feature or an oversight.
Comment #4
sivaji_ganesh_jojodae commentedI don't think this feature will made into core. You could use contrib modules like Shared email http://drupal.org/project/sharedemail to achieve it.
Edit: ..and this is not a bug perhaps feature request.
Comment #5
drewish commentedThis is definitely wonky. We should either allow duplicate emails or not. We've got the worst of both worlds right now.
Comment #6
c960657 commentedRerolled patch with tests added.
Summary:
The patch introduces a hidden setting that allows e-mails to be non-unique. The "reset password" feature is rudimentarily extended so that specifying an email address will send one mail per account with that email.
Comment #7
c960657 commentedReroll.
Comment #8
aaronbaumanThanks for your work on the patches above, Christian.
I think you've demonstrated the tip of the iceberg in terms of how major a change supporting duplicate emails would be.
Further, offering configurable uniqueness of email will be even more work.
I agree with drewish - we're currently in the worst of both worlds.
I will cast my vote for disallowing duplicate emails explicitly, and enforcing uniqueness of email in the database.
Here's how I usually hack core on my own sites:
This patch is 100% sufficient for new sites, but of course any installs with existing dupes will fail updates.
Failing updates is a big deal, and we've painted ourselves into a corner by being wishy-washy about email for the past 10 years.
But better late than never.
From a UX perspective, I can give you an example of how terrible a system is that allows duplicate emails.
You may not be familiar with this amazon.com "feature", but their user system validates uniqueness on a dual key: email+password.
The other day I logged into my amazon account with my email address and one of my throwaway common passwords, only to find that I had no order history even though I had recently placed a new order.
Further, if I had placed orders under both accounts, there is no way to merge the two accounts.
I'd have to explicitly request one account to be deleted, and I'd lose all my order history.
Awful awful UX.
If Drupal were to fully support non-unique email, we'd have to take a similar approach, which implies some pretty fundamental shifts to any subsystem that deals with users.
Comment #9
c960657 commentedIt may be tricky to enforce uniqueness if the users log have their profile data updated from some external source (e.g. a single sign-on system). Even if the external system enforces uniqueness, there may be duplicates in Drupal unless all changes in the external system are synced to Drupal immediately.
If we are to allow users to use their email address as identifier instead of a username, we should definitely require uniqueness (the Amazon approach sounds wacky).
Comment #10
aaronbaumanIt's not tricky to enforce uniqueness: just add a unique key to {users} and throw an exception when someone breaks it (even an external source).
Right now, core assumes and requires uniqueness of email without actually enforcing it.
This is broken.
And it leads to inconsistencies in the database, and a completely broken UX in which a user cannot update their own user record.
In my opinion, accommodating a non-unique external identifier is not something core should be concerned with.
In general, I think scenarios like the one you're describing need to be handled in contrib.
Comment #11
bleen commentedI have to agree with aaronbauman. We already require a unique email address - if you go to /admin/people/create and use the GUI to try creating a user with a taken email and you get the message "The email address %mail is already taken".
Let's start enforcing...
Comment #12
c960657 commentedWhy do we do that? It seems we do not use this uniqueness for anything, so why have that restriction? If there was a phone number user profile field in core by default, should we require that to be unique too? :-)
Sorry, I didn't make myself clear. I did write that it is hard to enforce uniqueness, but what I meant ( :-) ) was that it is hard to sync users from some external user database into Drupal when there is uniqueness on not only 1 but 2 columns. This is also the case if both email and username are unique in the external user database if the changes are not synced immediately (or at least in the same order) but e.g. are synced when the user logs in.
Assume 1) user A changes his email from foo@example.org to bar@example.org, and then 2) user B changes his email from baz@example.org to foo@example.org, then change #1 must be synced before #2, otherwise the uniqueness constraint will be violated. This problem may arise even if all users are synced in one batch during a feed.
I agree that the actual login/mapping etc. should happen in a contrib module. But it is hardly kosher for a contrib module to alter the database schema of {users} by removing a unique key.
Drupal are used more and more on sites owned by large organisations. Often the Drupal site is not the only web site or user database in the organisation, and it is generally preferably to support some kind of single sign-on system across all systems (external web sites would have a regular web-based log-in system, and internal web sites would interface with e.g. an Active Directory), so interfacing against various external user databases with various uniquness constraints is an important feature for a system targeting enterprise users.
Comment #13
bleen commentedDont many (most?) external login contrib modules simply create a ghost user in the Drupal users table with a username of some-module-user1 and some throw-away email address? This is not to say that all modules do this, but certainly some do (IIRC fb.module does this for example) so there is a solution to this for contrib.
And cant I make the same argument you are making about making life easier on contrib by pointing to the several modules out there that allow people to log in using his/her email?
Comment #14
c960657 commentedUsing dummy usernames is not a problem, because using hook_username_alter() contrib modules can ensure that they are never shown to the end-user. Using a throwaway email address will break modules that send email to the user.
I'm not sure I understand you correctly. It is easy to prevent duplicate emails even if the database table allows duplicates (core does this already). But if the database does not allow duplicates, a contrib module cannot allow them without changing the database scheme or saving the user's email address somewhere else than in {users}.mail.
We could also optionally add the unique key depending on the setting I suggested in my patch. This would support both use-cases equally good, though it would be a rather unusual approach.
Comment #15
c960657 commentedReroll.
Comment #17
c960657 commented#15: user-mail-unique-4.patch queued for re-testing.
Comment #18
aaronbaumanThis is a fundamental question, but it's outside the scope of this issue.
If you want to open a discussion about whether we should change the existing assumption, that belongs in a new issue.
In the meantime, we can fix the buggy behavior by enforcing this assumption.
Comment #19
jbrown commented#15: user-mail-unique-4.patch queued for re-testing.
Comment #23
dpiThe user entity includes a validator on the mail field for uniqueness.
See \Drupal\user\Plugin\Validation\Constraint\UserMailUnique.Comment #24
dpiThe argument for non-unique email addresses could be made in #286401: Make email not required for a Drupal site account
Comment #25
avpadernoThis issue is about adding a unique key for the email database field.
Drupal sets many database fields as part of a unique key, even if form validation handlers verify the entered value isn't already used. One thing doesn't exclude the other one.
The other issue is about not setting as required the email field. It simply means that an empty value for the email address would be acceptable, but this doesn't exclude the validation code may reject a value that is already present in the database. It just means the validation code needs to first check the entered value isn't empty; if it's empty, it doesn't proceed with the validation.
The code to change is in
UserStorageSchema::getEntitySchema(), the method that alters the database schema for the User entity, which now contains the following code.Comment #26
avpadernoComment #27
cilefen commentedWhat will occur if there are duplicates when the schema change is implemented?
Comment #29
karishmaamin commentedTried re-rolling patch against 9.4.x
Comment #30
avpadernoComment #31
ranjith_kumar_k_u commentedFixed cSpell error.
Comment #34
shubham chandra commentedRe-rolled patch against #31 in Drupal 9.5.x
Comment #35
avpadernoComment #37
sandeepsingh199 commentedfixed #34 drupalPost() error
Comment #39
Ankit.Gupta commentedReroll the patch #37 with Drupal 10.1.x
Comment #40
avpadernorandomName()isn't defined in the test class or its parent classes.variable_set()is a Drupal 7 function.Comment #41
nikhil_110 commentedTry to fixed #39 Cc Failed
Comment #42
nikhil_110 commentedFixed #41 Cc Failed.
Comment #43
avpadernoThe
UserRegistrationTestclass has therandomMachineName()and therandomString()methods. Using theRandomclass should not be necessary.Comment #44
dpiI still stand by my comment from #23.
I dont think we should be enforcing database level uniqueness, defer to validators and contrib to solve these issues.
Shall we get a framework maintainer opinion on this? (currently: Moshe)
Comment #45
poker10 commentedI think there are still some unresolved questions, for example the one from #27:
It is also important to think about case-sensitivity. In MySQL unique columns are case insensitive by default, so you cannot have
test@test.comandTEST@test.com. On the other side, in PostgreSQL, these are case sensitive and by default it will allowtest@test.comandTEST@test.comin the unique columns. This can cause another confusion if not handled properly.In my opinion, the uniqueness validation could remain only in code. There are lot of contrib modules creating weird email addresses just to workaround the need of the email address, or even saving empty email addresses and this change could potentially break all these.
Comment #46
aaronbaumanShould we get rid of other database constraints as well then?
How do we justify having unique constraints for UUID or username, but not email?
Seems like maybe we need to define a decision making criteria for when database constraints are warranted.
Comment #47
moshe weitzman commentedHi all - user module maintainer here.
If I were designing Drupal from scratch, I would certainly put a uniqueness constraint in the DB. But we are now 22 years into Drupal's life, and I think that ship has sailed. We dont want to disrupt existing sites so much. Folks who want to add this constraint to their DB are free to do so via schema alter. See UserStorageSchema::getEntitySchema().
Lets focus improving our add/edit validators as needed. And lets do that in other issues.
I respectfully close this long-standing issue.
Comment #48
daffie commentedI think this functionality would be great for a contrib module.