Updated: Comment #69

Problem/Motivation

Often, Drupal accounts get added without email addresses associated with them. This happens when the account is created automatically, by modules such as the drupal.module or third party modules like Drupal for Facebook.

It would be nice if site administrators could edit those accounts. For example to change roles or usernames. But currently they do not because several checks are in place to ensure that email is present on the user edit form.

Proposed resolution

This patch removes some of those checks. However, this patch does not change Drupal's default behavior in any way, because it leaves the #REQUIRED attribute set to true on the email field of the user edit form. This patch merely allows a custom or third-party module to use form_alter to explicitly set that #REQUIRED to false.

So to sum up, this patch will not affect default behavior, but it enables a customization which I think should be supported. If you want to make the email field optional, you can add something like this to a form_alter hook, after this patch has been applied.

function my_form_alter($form_id, &$form) {
  if ($form_id == 'user_register') {
    if (user_access('administer users')) {
      $form['mail']['#required'] = FALSE;
    }
  }
}

Remaining tasks

This task needs more work.

User interface changes

Site administrators can modify accounts without email IDs.

API changes

None.

Original report by Dave Cohen

Comments

lilou’s picture

Title: Allow administrator to edit accounts without email addresses. » Allow administrator to edit account without email address
Version: 5.2 » 7.x-dev
Status: Active » Needs work

Patch no longer applied against CVS/HEAD.

cafuego’s picture

Version: 7.x-dev » 8.x-dev
Status: Needs work » Needs review
StatusFileSize
new764 bytes

This is still an issue when using an external auth/account creation module such as Twitter.

Ported patch to 8.x and modified it a little bit. The email is now not required if the user making the changes has "administer users" permission and if the account didn't have an email address set.

If the account had an email address, the field remains mandatory.

larowlan’s picture

Status: Needs review » Needs work
+++ b/modules/user/user.module
@@ -980,7 +980,7 @@ function user_account_form(&$form, &$form_state) {
+    '#required' => (empty($account->mail) && user_access('administer users')) ? FALSE : TRUE,

can't this just be

+  '#required' => !(empty($account->mail) && user_access('administer users'))

Powered by Dreditor.

cafuego’s picture

Yes it can, though I don't know if that's considered equally readable :-)

cafuego’s picture

Status: Needs work » Needs review
StatusFileSize
new1.78 KB

Redid patch according to the suggestion in #3.

To allow users without an email address to be deleted, I've also wrapped the call to user_validate_mail() in an if statement, so said function is not called is the email field is empty and not required.

cafuego’s picture

...because with the use of signups via Twitter (and probably other contrib modules) D6 and D7 sites can have users without email addresses, I think it might be worth considering backporting this patch. Not so much as a new feature, but as a fix for the "cannot delete user without email" bug ;-)

Status: Needs review » Needs work

The last submitted patch, 189544-missing-email-5.patch, failed testing.

cafuego’s picture

Status: Needs work » Needs review
StatusFileSize
new1.57 KB

Fixed my logic error in the validate handler. Updated patch attached.

cafuego’s picture

Status: Needs review » Needs work

Needs tests to make sure this remains working.

cafuego’s picture

Status: Needs work » Needs review
StatusFileSize
new3.77 KB

Attached patch hopefully contains two test cases that should fail if an admin cannot edit or delete users without an email address.

cafuego’s picture

StatusFileSize
new3.79 KB

Updated test case to actually unset the test user's email, then admin delete the user.

cafuego’s picture

StatusFileSize
new3.85 KB

Fixup tests so the created test users *actually* have no e-mail addresses set :-)

xjm’s picture

Status: Needs review » Needs work
Issue tags: +Novice

Thanks for your work on this patch! I reviewed it and have two small points of feedback:

+++ b/modules/user/user.moduleundefined
@@ -980,7 +980,7 @@ function user_account_form(&$form, &$form_state) {
+    '#required' => !(empty($account->mail) && user_access('administer users')),

I had to read this several times before I understood it. Could we add an inline comment explaining how the value is being set and why?

+++ b/modules/user/user.testundefined
@@ -796,6 +796,34 @@ class UserCancelTestCase extends DrupalWebTestCase {
+   * Create an administrative user and delete a user without an e-mail address.

This should start with "Creates..." (see http://drupal.org/node/1354#functions). We're currently cleaning up the other docblocks as a part of #1310084: [meta] API documentation cleanup sprint, so we should make sure the new docblocks we add are also consistent with the standard.

Also, note that the Drupal 8.x patch will need to be rerolled, because the core directory structure for Drupal 8 has now changed. (For more information, see #22336: Move all core Drupal files under a /core folder to improve usability and upgrades). When the patch has been rerolled, please set the issue back to "Needs Review."

Tagging as novice for the task of rerolling the Drupal 8.x patch.

If you need help rerolling this patch, you can come to core office hours or ask in #drupal-gitsupport on IRC.

Finally, can we get a separate patch with just the tests to demonstrate that they fail without the fix?

cafuego’s picture

Status: Needs work » Needs review
StatusFileSize
new4 KB
new4.21 KB

Rerolling is easy, since the files were all moved via git mv, a simple rebase does the trick.

Attached are patch 14, which contains the original changes plus the updated doc strings and patch fail, which contains only the new tests, but not the code that should make these tests pass.

So 14 should pass, fail should fail.

cafuego’s picture

[edit] Sigh. Double-posted because Chrome got stuck and didn't show me it'd already added the patches.

Status: Needs review » Needs work

The last submitted patch, 189544-missing-email-fail.patch, failed testing.

cafuego’s picture

Status: Needs work » Needs review

Yay, failpatch has failed testing :-)

xjm’s picture

+++ b/core/modules/user/user.testundefined
@@ -796,6 +796,35 @@ class UserCancelTestCase extends DrupalWebTestCase {
+   * Creates an administrative user and deletes a user without an
+   * e-mail address.

Oops, one more thing. We should put this all on one line. (It's less than 80 chars already I think.)

Other than that, this patch looks good to me, and it solves something that annoys me constantly. :)

cafuego’s picture

So now I have a question, that line is 78 characters from * to . but if you include the indent spacing at the front, it's 81 characters. The latter is why I broke the line. Should I be counting from the * ?

Edit: Not changing the comment :-)

xjm’s picture

I answered cafuego's question in IRC. ;) All the characters count, including those from indentation and such. (Well.. okay, I won't get into the "slings and arrows of outrageous newlines.") Basically, though, just make the friendly gray line in dreditor happy!

cafuego’s picture

Re-rolled with updated comments. Also put the edit user without e-mail test in its own function, so a test failure message is a bit clearer as to what failed.

Status: Needs review » Needs work

The last submitted patch, 189544-missing-email-21-fail.patch, failed testing.

cafuego’s picture

Status: Needs work » Needs review

Okay, that seems to be all loose ends tied up :-)

BrockBoland’s picture

StatusFileSize
new5.65 KB

The user module has changed enough since November that this patch no longer applied cleanly. The attached is updated to include the logic change that cafuego had made, but does not include the change to the user_validate_mail() call, since that function no longer exists.

However, one issue remained: if the admin created a new user without providing an email address, and checks the "Notify user of new account" option, they got an error from user_register_submit(): "The e-mail address is already taken."

This patch adds two things in addition to what cafuego already wrote:

  • Checks that the email address was provided before sending a welcome message. If email address is empty, it skips the mail send and displays a different message to the admin. Is there other documentation, translations, etc, that needs to be updated for the addition of a message like this?
  • Don't check if the email address is already in use if none is provided. Otherwise, the admin gets an error the second time a user is created without an email address: "The e-mail address is already taken."
xjm’s picture

Status: Needs review » Needs work
Issue tags: +Needs manual testing

I think this looks great overall, and both the changes from #24 are good ones. Tests look good as well. Few stylistic cleanups:

  1. It would be better to remove the t() from the assertion messages that are only displayed to the admin or bot when the test is run. Reference: http://drupal.org/simpletest-tutorial-drupal7#t
  2. +++ b/core/modules/user/user.moduleundefined
    @@ -943,11 +943,14 @@ function user_account_form(&$form, &$form_state) {
    +  // The mail field is NOT required if account originally had no mail set
    +  // and the user performing the edit has 'administer users' permission.
    +  // This allows users without e-mail address to be edited and deleted.
    

    This comment seems to wrap a bit before 80 chars. Edit: Either that, or it was moved up from above the #required maybe? I think it might actually be more helpful down there.

  3. +++ b/core/modules/user/user.moduleundefined
    @@ -1129,7 +1132,7 @@ function user_account_form_validate($form, &$form_state) {
    +  if (!empty($mail) && (bool) db_select('users')->fields('users', array('uid'))->condition('uid', $account->uid, '<>')->condition('mail', db_like($mail), 'LIKE')->range(0, 1)->execute()->fetchField()) {
    

    Oy. I realize this predates the patch, but can we move the query up a line and set a variable so that the condition is legible?

  4. +++ b/core/modules/user/user.testundefined
    @@ -785,6 +785,34 @@ class UserCancelTestCase extends DrupalWebTestCase {
    +    // Create administrative user.
    ...
    +    // Delete regular user without e-mail address.
    

    It would be good to add articles to these comments ("Create an administrative user", "delete the regular user", etc.)

Once that is fixed, let's have a couple people testing this manually and checking that everything behaves as expected and is intuitive. If a couple people can try adding/editing a few accounts and confirm that it behaves, I think it's RTBC.

cafuego’s picture

StatusFileSize
new5.67 KB

Rerolled patch with adjusted comment, variablized giant SQL query and articled test comments :-)

cafuego’s picture

Status: Needs work » Needs review
cafuego’s picture

StatusFileSize
new5.66 KB

... forgot to remove superfluous calls to t(), which is done as per http://drupal.org/simpletest-tutorial-drupal7#t (I think) in this patch.

BrockBoland’s picture

Manually tested the latest patch in #28 and it looks good. I think we should have at least one more person test it before RTBC.

This might be a question for a different issue, but should we allow admins to remove an email address from a user? With this patch, an admin can create a user with no email, and then edit that user without having to provide an email. But, if the admin does set an email address, the email is a required field forevermore on that user. Is this ideal?

cafuego’s picture

should we allow admins to remove an email address from a user

I had a think about that as well when I first worked on the patch and I decided against it. A fair bit of Drupal functionality depends on a user having an email address (password reset, notifications, etc) and usually users only end up without an email address when a user is created programmatically or via some third party integration thing (twitter, facebook).

I think if we're going to allow users without an email address maybe that should be a setting on the user settings page, which can contain some text to explain caveats, so it's a decision admins need to expressly make. I'm hesitant to just throw it out the window as a required field.

Dave Cohen’s picture

I had a think about that as well when I first worked on the patch and I decided against it.

There is a difference between "I would never do that," and "Drupal should not be able to do that." Drupal should allow just about anything a sophisticated admin wants to do.

So I encourage you guys to permit the removal of an email field, if a custom module explicitly makes the field not required (i.e. the original post to this thread). Drupal core should maintain conservative choices, but Drupal APIs should allow riskier ones.

dsm’s picture

Assigned: Unassigned » dsm
dsm’s picture

Manual testing passed.

1. Created a user: created user
2. Removed the email address via sql: removed email address
3. Edited the user: edited user

xjm’s picture

Assigned: dsm » Unassigned
Status: Needs review » Reviewed & tested by the community
Issue tags: -Novice, -Needs manual testing

Thanks for the testing @drupkick! I think this is RTBC. :)

catch’s picture

Status: Reviewed & tested by the community » Fixed

Looks good to me too, committed/pushed to 8.x.

cafuego’s picture

Version: 8.x-dev » 7.x-dev
Status: Fixed » Needs work

Thanks catch! Now let's see if we can backport this into D7 as a fix, because not being able to delete users just because they don't happen to have an email address is a bug.

xjm’s picture

So the things to be aware of for backporting this are:

  • Introduces a new string.
  • Eensy teensy form change in that the field is no longer always required.

I think this is safe. We probably could even get around the string addition if need be.

xjm’s picture

Status: Needs work » Patch (to be ported)
cafuego’s picture

Status: Patch (to be ported) » Needs review
StatusFileSize
new6.15 KB

First roll of this patch for D7.

jcisio’s picture

Priority: Normal » Critical
Status: Needs review » Active

In the commit on Apr 13th an unrelated file core/modules/search/lib/Drupal/search/SearchQuery.php was committed and is still there.

xjm’s picture

Version: 7.x-dev » 8.x-dev
Priority: Critical » Normal
Status: Active » Needs review

core/modules/search/lib/Drupal/search/SearchQuery.php is part of #1513970: Convert SearchQuery to PSR-0. So the file should be there... it just should have been part of the other commit instead. :)

xjm’s picture

Version: 8.x-dev » 7.x-dev
naxoc’s picture

Assigned: Unassigned » naxoc
naxoc’s picture

Status: Needs review » Reviewed & tested by the community

This is good to go.

I tested (manually) that:

  • When I delete an existing user's email from the database - I can still edit the user from the UI.
  • I can create a new user with no email address.
  • I can create two users with no email address - so the potential problem of looking up in the database to see if the email "" is taken is not an issue.
  • The message The new user Derp was created without an email address, so no welcome message was sent. is displayed when I check the "Notify user of new account" checkbox and the user has no email address.

There is a new string that should be translated: The new user %name was created without an email address, so no welcome message was sent.

The simpletests look fine too.

cafuego’s picture

  • I can create a new user with no email address.
  • I can create two users with no email address - so the potential problem of looking up in the database to see if the email "" is taken is not an issue.
  • Hmm, can you create them as administrator or when signing up as visitor? If the former, that's OK (I think) but if the latter then that's a feature this patch isn't supposed to provide ;-)

    naxoc’s picture

    Sorry. That was unclear.
    I did all the tests above as a privileged user.

    webchick’s picture

    I really love the idea of this patch, however, David has requested help on resolving release blockers, so I don't feel comfortable committing feature patches until that happens.

    David_Rothstein’s picture

    Title: Allow administrator to edit account without email address » Allow administrator to edit account without email address (regression: accounts can be created without email addresses also)
    Version: 7.x-dev » 8.x-dev
    Category: feature » bug
    Priority: Normal » Major
    Status: Reviewed & tested by the community » Needs work

    Er, whoa... Why are we allowing administrators to create accounts without an email address? The Drupal core UI should not be allowing that, not even in Drupal 8 and especially not in Drupal 7.

    Also, I'm having trouble understanding most of the code in this patch. Contrib modules can easily use hook_form_alter() to set #required to FALSE if they want to make the field not required. And they can do so on their own terms.... So why should we make assumptions in core about the exact conditions under which it might be made un-required?

    It seems like instead we need to focus this issue on the original goal, which would be removing only those things that are actual barriers to a contrib module which wants to make the field non-required (like the changes to user_account_form_validate(), etc).

    Also, if the other goal of the patch is to fix the bug where an account without a valid email can't be deleted, that seems good (and the test that was added for that looks very nice) but this should be done by setting #limit_validation_errors on the delete button, rather than modifying the #required property of one particular field. (That would solve the problem for other fields too; there are many reasons an account could be invalid but none of them should necessarily prevent the account from being deleted.) At least, it's definitely the way it should be fixed in Drupal 8.

    BrockBoland’s picture

    Not including this in D7 makes sense. Should it be rolled back out of D8? And if not, can this issue be closed?

    cafuego’s picture

    The patch in this issue *should* not allow administrators to create accounts without email addresses, that is not what this issue is about... the #required check is:
    code>!(empty($account->mail) && user_access('administer users'))
    So that should be FALSE if account->mail is empty and the viewing user has administer users access and TRUE in all other cases.

    Perhaps there should also be a test to see that account->uid is not empty, so the email field remains required when an admin creates a new user.

    What we're trying to address is the editing and deleting of accounts that lack an email address by administrators. Such accounts can be created by third party authorization plugins such as twitter or Facebook, which pass back a username and authentication result, but not an email address.

    As it stands, administrators cannot edit or delete such accounts because the mail field is a required field on the account edit form. The patch makes it be *not* required when an administrator edits an account that has no email set. It should not affect the form otherwise and should not allow users to remove their email address or indeed save the form without first adding an email address if it was not originally present.

    I will be happy to read up on the limit validation errors and perhaps rewrite the patch, but backing the fix out and marking this issue as closed leaves a big problem for many site admins, so do not.

    sun’s picture

    Assigned: naxoc » Unassigned
    Priority: Major » Critical
    Status: Needs work » Active
    Issue tags: -String freeze, -Needs backport to D7 +Regression

    Just recognized this on the user add form. Bumping to critical, since this is a major regression. An e-mail address should be required in core.

    The fastest way to get this critical out of the queue would be to revert the committed patch.

    Aside from that, I also question the original idea of allowing contrib to store no e-mail address at all for a user account. To my knowledge, that's an extremely bad practice, since it means that a user is not able to regain access to the own account in case the originating service or account at that service ceases to exist. If someone really wants to destroy that option, then it is trivial to inject a fake e-mail address into each created user account which does not exist — same effect, no core changes required.

    webchick’s picture

    Patch above does not revert cleanly, so we'll need a patch to do that.

    sun’s picture

    Status: Active » Needs review
    StatusFileSize
    new7.03 KB

    The entire code that was touched by #28 moved to new locations, so reverting this patch wasn't exactly trivial.

    Furthermore, the commit mistakenly added a new Drupal\search\SearchQuery class, which of course should not be reverted either.

    Status: Needs review » Needs work

    The last submitted patch, user.mail-revert.53.patch, failed testing.

    swentel’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new6.84 KB

    Changed the test in core/modules/user/lib/Drupal/user/Tests/UserEditTest.php to assert that the e-mail should always be required - I doubted between removing, but I feel this might be a better option.

    Hope this passes, all my local tests were failing and those html5 things are annoying sometimes as well to test.

    swentel’s picture

    StatusFileSize
    new7.26 KB

    Changed the comment in that test as well.

    dcam’s picture

    Since this issue deals with deleting entities with empty required fields I want to point out a related issue, #1342444: Do not validate fields if entity is in the process of being deleted. This isn't only an issue with users.

    Dave Cohen’s picture

    I also question the original idea of allowing contrib to store no e-mail address at all for a user account

    I've been trying since D5 to get this feature. I think it makes Drupal a better platform for developing Facebook Apps, where the users email is not always known. And I'm aware of other login/registration schemes that also never learn an email address. So, I can't help but be disappointed to read sun's logic in #51. To me, that logic reads, "I (sun, or whoever is currently blocking the feature) can never imagine wanting this, therefore Drupal should never be capable of doing it."

    If someone really wants to destroy that option, then it is trivial to inject a fake e-mail address into each created user account which does not exist — same effect, no core changes required.

    I argue this is not good enough. Suppose a user registers via facebook connect and gets a user account generated for them. Shouldn't they be able to edit their user account just like other users? Is it not a bug when they see randomly generated 123@abc.com for their email address?

    I really think it would be easier to fix the small bug in this patch, which accidentally makes the email address optional in core, rather than revert the whole thing.

    jcisio’s picture

    #58 As being pointed out earlier, in those cases a fake email could be use. An account registered via Facebook could be assigned an email FacebookUID@facebook.com that is unique (and many other social platform, why do not reveal user email, can expose an address to route emails to user's real email address).

    Dave Cohen’s picture

    While it is often possible to learn an email address from facebook, it is not always.

    There are several reasons why the fake email address is not a good solution.

    • I don't really want my Drupal server to start sending emails to blahblahblah@facebook.com.
    • I don't really want postmaster@facebook.com to receive those emails.
    • I don't really want Drupal sending emails to any random string of letters and number that I make up and throw into that mail field.
    • And I don't really want users to see that random string when they edit their account.
    sun’s picture

    Status: Needs review » Reviewed & tested by the community

    For now, it would be a good idea to get this critical regression out of the way. This does not imply any kind of "absolute" decision that e-mail addresses cannot or must not be optional.

    However, re-introducing this capability should be covered by much more serious considerations with regard to:

    1. How a potentially missing/empty e-mail address will affect other (core and contributed) modules.
    2. Double-checking where and how e-mail addresses are used throughout Drupal core.
    3. How this change affects modules using drupal_mail() to send mails to users.
    4. Security aspects, such as recovering user account access/information. (Also: What if uid 1 has no e-mail address?)
    5. Preventing the user/password reset form from attempting to send an e-mail to a user account without e-mail address. Requires special error handling.
    6. What about contrib modules that only make any sense with non-empty user account e-mail addresses? (Wanted to mention comment_notify, but that's an invalid example. Anyway, I'm sure there are some.)
    7. Various stuff like: #85494: Use email verification when changing user email addresses
    8. etc.pp.

    We also need much more sophisticated tests - at minimum for an entire user registration + edit + password-reset + cancellation flow.

    chx’s picture

    Priority: Critical » Major
    Status: Reviewed & tested by the community » Needs work

    I fail to see the data loss that makes this critical. Also, since when it is acceptable to fix something by nuking its test? If commit this as it stands, I think, unless I am missing something here, you won't be able to cancel an account without an email address. At least you need a #limit_validation_errors on the Cancel Account button so that cancel goes through without validation.

    cafuego’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new5.25 KB

    Attached patch contains a subset of swentels patch from #56. It leaves in place the tests, and sets #limit_validation_errors to array('uid') on the cancel action.

    This still means an account without email address cannot be edited and saved without adding in a (possibly fake) email address. That's not ideal, but at least such accounts can be deleted from the database now.

    I'm not sure how to sensibly use #limit_validation_errors for the save action without iterating through the whole form array and adding all elements except mail. Is there a property we can set that lists the elements to be ignored by the validation handler rather than the ones that should NOT be ignored? Like an inverse #limit_validation_errors?

    Status: Needs review » Needs work

    The last submitted patch, 189544-63.patch, failed testing.

    cafuego’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new4.2 KB

    Reverted the assignment of #required on the profile form submit button, then added a test on $account->uid.

    This now means that the email field is not required if:

    - The account is being edited, not created.
    - The account had no email when the form was loaded.
    - The current user has administer users permission.
    - The account is being canceled.

    When a new account is being created, the email field is required.

    Also added in a few comments to explain what and why is happening.

    I've also left the logic that allows an administrator to edit an account if there are multiples without an email address (by not checking if an empty email address is already in use).

    Finally, the logic that previously allowed a new user with an empty email address to be created and react accordingly in the RegisterFormController is now gone, as that case should never happen (and was also outside the scope of the original patch!)

    cafuego’s picture

    Issue tags: +Needs manual testing

    Tagged for manual testing.

    kscheirer’s picture

    Status: Needs review » Needs work

    I'm not sure what the needs manual testing tag is for in this case. Don't we want to add some tests to make sure this behavior stays?

    +++ b/core/modules/user/lib/Drupal/user/AccountFormController.phpundefined
    @@ -47,12 +47,12 @@ public function form(array $form, array &$form_state, EntityInterface $account)
    +      '#required' => !(!empty($account->uid) && empty($account->mail) && user_access('administer users')),
    

    Minor nitpick, I think the form !(!A && B && C) is a little clearer as: A || !B || !C

    dcam’s picture

    http://drupal.org/node/1427826 contains instructions for updating the issue summary with the summary template.

    The summary may need to be updated with information from comments.

    PavanL’s picture

    Issue summary: View changes
    PavanL’s picture

    Issue summary: View changes
    jhedstrom’s picture

    Issue summary: View changes
    Status: Needs work » Closed (duplicate)
    eric_a’s picture

    Unless I'm missing something, this was fixed in #189544: Allow administrator to edit account without email address (regression: accounts can be created without email addresses also).

    @jhedstrom, you a referrering to this issue as duplicating itself?

    mlahde’s picture

    Status: Closed (duplicate) » Active

    Set back to Active as this is still valid.

    We have a Drupal site where there shouldn't be emails used at all. The users are migrated to the system without email adresses and that works fine. Unfortunately they cannot be edited (for example to change the password or deleted) because the email is a mandatory field. This is a bit contradictory since you can also create a user without an email through UI.

    mlahde’s picture

    Status: Active » Closed (duplicate)
    Related issues: +#2600158: User email requirement is inconsistent

    Finally found more recent issue for this one: https://www.drupal.org/project/drupal/issues/2600158
    Set back as duplicate and sorry for the noise.