Repository: Mailu/Mailu

Issue:
Configuration (or hardcode) to rank users higher than aliases
Currently, when resolving the localpart of a domain, `admin` first tries aliases, and if no alias is found, users are searched:
```
        alias = Alias.resolve(localpart, domain_name)
        if not alias and localpart_stripped:
            alias = Alias.resolve(localpart_stripped, domain_name)
        if alias:
            return alias.destination

        user = User.query.get('{}@{}'.format(localpart, domain_name))
        if not user and localpart_stripped:
            user = User.query.get('{}@{}'.format(localpart_stripped, domain_name))
        if user:
            if user.forward_enabled:
                destination = user.forward_destination
                if user.forward_keep or ignore_forward_keep:
                    destination.append(user.email)
            else:
                destination = [user.email]
        return destination
```
This may be counter-intuitive to some users: After all, wildcards often behave the way that they are considered only after all more-specific options are considered and dismissed. Here, it’s vice-versa: If there’s a catchall alias (`%@xxx.tld`), then all users under `xxx.tld` are not reachable anymore.
One use-case that is not possible here would be: A domain-owner would like catchall for himself, but give specific names to services, relatives, friends, etc.: The only workaround for this is currently to create these accounts on another domain, and then create an alias on `xxx.tld` to them.

Since changing the behavior of that function might break existing users setups, I’d follow the suggestion of `braintopping` from matrix: Using a kind of feature-flag or configuration variable to switch the behavior of preferring users vs. preferring aliases.

What does everyone think about that? I’d be grateful for some feedback~.


Discussion:
I don't like the idea of an configuration variable. It makes it unnecessary complicated and confuses people. 
Furthermore this behavior was introduced with the new `feat-abstract-db` only on master a few month ago. So I suggest we just change it.
You do have a point there — with such behavioral feature-flags, they can become a lot and quite confusing quickly.

I made 2 example of how this could look like in the branches github kindly linked above. I can’t PR them yet because the only make sense based off https://github.com/Mailu/Mailu/pull/814 — so I’ll wait until that one’s in. If you want to have a look at them beforehand, please go ahead ^_^.

Thanks!

Resolving patch:
diff --git a/core/admin/mailu/models.py b/core/admin/mailu/models.py
--- a/core/admin/mailu/models.py
+++ b/core/admin/mailu/models.py
@@ -266,16 +266,6 @@ def resolve_destination(cls, localpart, domain_name, ignore_forward_keep=False):
         if os.environ.get('RECIPIENT_DELIMITER') in localpart:
             localpart_stripped = localpart.rsplit(os.environ.get('RECIPIENT_DELIMITER'), 1)[0]
 
-        pure_alias = Alias.resolve(localpart, domain_name)
-        stripped_alias = Alias.resolve(localpart_stripped, domain_name)
-
-        if pure_alias and not pure_alias.wildcard:
-            return pure_alias.destination
-        elif stripped_alias:
-            return stripped_alias.destination
-        elif pure_alias:
-            return pure_alias.destination
-
         user = User.query.get('{}@{}'.format(localpart, domain_name))
         if not user and localpart_stripped:
             user = User.query.get('{}@{}'.format(localpart_stripped, domain_name))
@@ -288,6 +278,16 @@ def resolve_destination(cls, localpart, domain_name, ignore_forward_keep=False):
                 destination = [user.email]
             return destination
 
+        pure_alias = Alias.resolve(localpart, domain_name)
+        stripped_alias = Alias.resolve(localpart_stripped, domain_name)
+
+        if pure_alias and not pure_alias.wildcard:
+            return pure_alias.destination
+        elif stripped_alias:
+            return stripped_alias.destination
+        elif pure_alias:
+            return pure_alias.destination
+
     def __str__(self):
         return self.email
 


Test patch: