Dear Steve, dear list

> That's not true on the systems I've worked with most recently -- those
> will be recognized as duplicate addresses (...)

You are right. I am sorry for this confusion. Please let me correct my initial posting to this list from yesterday, saying:

>> (...) <markus.grand...@uni-konstanz.de> and <markus.grand...@uni-konstanz.de> are being recognized as separate identities.

That is not the case. Meanwhile I discovered an error with logging into Postorius when an account is associated with two semantically identical email addresses that differ in their formatting, e.g.,


   <markus.grand...@uni-konstanz.de>

   and

   <markus.grand...@uni-konstanz.de>.


In this case, the user is unable to log in, and I observed the following error message in the log file:


   (...) returned more than one EmailAddress -- it returned 2!


Here is the complete stack trace of this error:


ERROR 2025-02-10 14:29:55,599 211159 django.request Internal Server Error: /mailman3/accounts/login/
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/django/views/generic/base.py", line 70, in view
    return self.dispatch(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/django/utils/decorators.py", line 43, in _wrapper
    return bound_method(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/django/views/decorators/debug.py", line 89, in sensitive_post_parameters_wrapper
    return view(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/allauth/account/views.py", line 149, in dispatch
    return super(LoginView, self).dispatch(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/allauth/account/views.py", line 77, in dispatch
    response = super(RedirectAuthenticatedUserMixin, self).dispatch(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/django/views/generic/base.py", line 98, in dispatch
    return handler(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/allauth/account/views.py", line 105, in post
    response = self.form_valid(form)
               ^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/allauth/account/views.py", line 162, in form_valid
    return form.login(self.request, redirect_url=success_url)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/allauth/account/forms.py", line 196, in login
    ret = perform_login(
          ^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/allauth/account/utils.py", line 168, in perform_login
    response = adapter.pre_login(request, user, **hook_kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/allauth/account/adapter.py", line 411, in pre_login
    if not has_verified_email(user, email):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/allauth/account/utils.py", line 130, in has_verified_email
    emailaddress = EmailAddress.objects.get_for_user(user, email)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/allauth/account/managers.py", line 54, in get_for_user
    ret = self.get(user=user, email__iexact=email)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/django/db/models/query.py", line 439, in get
    raise self.model.MultipleObjectsReturned(
allauth.account.models.EmailAddress.MultipleObjectsReturned: get() returned more than one EmailAddress -- it returned 2! ERROR 2025-02-10 14:29:55,599 211159 django.request Internal Server Error: /mailman3/accounts/login/
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/django/views/generic/base.py", line 70, in view
    return self.dispatch(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/django/utils/decorators.py", line 43, in _wrapper
    return bound_method(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/django/views/decorators/debug.py", line 89, in sensitive_post_parameters_wrapper
    return view(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/allauth/account/views.py", line 149, in dispatch
    return super(LoginView, self).dispatch(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/allauth/account/views.py", line 77, in dispatch
    response = super(RedirectAuthenticatedUserMixin, self).dispatch(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/django/views/generic/base.py", line 98, in dispatch
    return handler(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/allauth/account/views.py", line 105, in post
    response = self.form_valid(form)
               ^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/allauth/account/views.py", line 162, in form_valid
    return form.login(self.request, redirect_url=success_url)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/allauth/account/forms.py", line 196, in login
    ret = perform_login(
          ^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/allauth/account/utils.py", line 168, in perform_login
    response = adapter.pre_login(request, user, **hook_kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/allauth/account/adapter.py", line 411, in pre_login
    if not has_verified_email(user, email):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/allauth/account/utils.py", line 130, in has_verified_email
    emailaddress = EmailAddress.objects.get_for_user(user, email)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/allauth/account/managers.py", line 54, in get_for_user
    ret = self.get(user=user, email__iexact=email)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/django/db/models/query.py", line 439, in get
    raise self.model.MultipleObjectsReturned(
allauth.account.models.EmailAddress.MultipleObjectsReturned: get() returned more than one EmailAddress -- it returned 2!


To resolve the issue, the only solution I found was to manually delete the second email address from the database:


mailman3web-prod=> select * from account_emailaddress where user_id = 93;
 id  |                email            | verified | primary | user_id
-----+---------------------------------+----------+---------+---------
 100 | markus.grand...@uni-konstanz.de | t        | t       |      93
 101 | markus.grand...@uni-konstanz.de | t        | f       |      93
(2 rows)
mailman3web-prod=> delete from account_emailaddress where id = 100;
DELETE 1
mailman3web-prod=> select * from account_emailaddress where user_id = 93
;
 id  |                email            | verified | primary | user_id
-----+---------------------------------+----------+---------+---------
 101 | markus.grand...@uni-konstanz.de | t        | f       |      93
(1 row)


Could I have achieved the same deletion using the REST interface?

After the deletion login with <markus.grand...@uni-konstanz.de> was possible again, and I set the remaining email address as 'primary' using Postorius.

I am not entirely sure how the duplicate email address came into the system. During the data migration from Mailman 2.1 to Mailman 3, an account was created for <markus.grand...@uni-konstanz.de>. It is most likely that during registration, the user provided <markus.grand...@uni-konstanz.de> as username or email address, which resulted in both variations of the semantically same email address being stored under the same account.

I apologize again for the incorrect information in my initial message to this list. I should have waited until I had a clearer understanding of this issue.

Best regards,
Markus


Am 10.02.25 um 15:32 schrieb Stephen J. Turnbull:
Markus Grandpré writes:

  > We've encountered an issue with Postorius after migrating from
  > Mailman 2.1. It appears that Postorius is treating email addresses
  > with differing capitalization as distinct user accounts. For
  > example, <markus.grand...@uni-konstanz.de> and
  > <markus.grand...@uni-konstanz.de> are being recognized as separate
  > identities.

That's not true on the systems I've worked with most recently -- those
will be recognized as duplicate addresses, both at list import time and
at login on Postorius.  Those are versions Mailman 3.3.9 and 3.3.11,
with corresponding Postorius.  As far as I can tell the last case-
sensitivity bugs were fixed as of Mailman 3.2.1 (released 2019-02-22).
Postorius does not appear to have had any case sensitivity bugs (not
surprising since Postorius just passes them through to Mailman).

I guess it's possible that this is a Debianism, or there was a
temporary regression around 3.3.8.

  > Is there a known configuration option or method within Postorius
  > (or Mailman 3 itself) to normalize or unify account identification,
  > effectively treating email addresses as case-insensitive for
  > account matching?

There is no such configuration option because Mailman has treated
email addresses as case insensitive for quite a while.  All I can
recommend is an upgrade.

Steve

--
Markus Ludwig Grandpré
Universität Konstanz
Kommunikations-, Informations-, Medienzentrum (KIM)
Abteilung IT-Dienste Forschung und Lehre,
B803, Tel: ++49 7531 88 4342

Attachment: smime.p7s
Description: Kryptografische S/MIME-Signatur

_______________________________________________
Mailman-users mailing list -- mailman-users@mailman3.org
To unsubscribe send an email to mailman-users-le...@mailman3.org
https://lists.mailman3.org/mailman3/lists/mailman-users.mailman3.org/
Archived at: 
https://lists.mailman3.org/archives/list/mailman-users@mailman3.org/message/OS3HE6XJLSPK22WKEHTEVQAZCFUTX3XS/

This message sent to arch...@mail-archive.com

Reply via email to