We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Mail relaying (Relayed domain) does't work when no Remote Host is configured.
Description: 
When in the Web Administration Interface in Relayed domain, a domain is added without a Remote Host, emails for this domain fail to be relayed. When no Remote Host is configured, Mailu is supposed to relay the email message directly to the relayed domain.

In case it is relevant I use the docker-compose deployment.

Replication steps:
1). Deploy a standard Mailu installation (no special configuration required). 
2). In the Web Administration interface, on Relayed domains page add a new relayed domain with
Relayed domain name: test.mailu.io
Remote Host:  (blank, keep it empty).
3). Configure your email client SMTP settings to use your Mailu server on port 25 without any authentication.
4). Send an email to admin@test.mailu.io. If you receive the message, server is busy try again. Then Rspamd has greylisted you. Try sending the email again in 10 to 15 minutes. It should be accepted now.
5). Check the postfix logs (docker logs --tail 100 mailu_smtp_1 )

Aug 13 22:47:32 mail postfix/smtpd[270]: A1C493E2CE1: client=<redacted>.nl[xx.xxx.xx.xxx]
Aug 13 22:47:32 mail postfix/cleanup[315]: A1C493E2CE1: message-id=<71874e8e-c30d-e0a3-4d70-de4542b47664@yahoo.com>
Aug 13 22:47:33 mail postfix/qmgr[177]: A1C493E2CE1: from=<redacted@yahoo.com>, size=2765, nrcpt=1 (queue active)
Aug 13 22:47:33 mail postfix/smtpd[270]: disconnect from <redacted>.nl[xx.xxx.xx.xxx] ehlo=2 xclient=0/1 mail=1 rcpt=1 data=1 quit=1 commands=6/7
**Aug 13 22:47:33 mail postfix/smtp[316]: fatal: valid hostname or network address required in server description: []
Aug 13 22:47:34 mail postfix/qmgr[177]: warning: private/smtp socket: malformed response**
Aug 13 22:47:34 mail postfix/qmgr[177]: warning: transport smtp failure -- see a previous warning/fatal/panic logfile record for the problem description
Aug 13 22:47:34 mail postfix/master[175]: warning: process /usr/libexec/postfix/smtp pid 316 exit status 1
Aug 13 22:47:34 mail postfix/master[175]: warning: /usr/libexec/postfix/smtp: bad command startup -- throttling
Aug 13 22:47:34 mail postfix/error[318]: A1C493E2CE1: to=<admin@test.mailu.io>, relay=none, delay=1.6, delays=0.59/1/0/0.01, dsn=4.3.0, status=deferred (unknown mail transport error)

Workaround:
A workaround is to enter the hostname or IP address of the SMTP server of the relayed domain name as Remote Host. No MX lookup is performed for a hostname entered as Remote Host. For a public domain, you could use the mxtoolbox to lookup the SMTP server. E.g. in my example for test.mailu.io https://mxtoolbox.com/SuperTool.aspx?action=mx%3atest.mailu.io&run=toolpage .

Entering 78.47.92.244 or test.mailu.io as Remote Host will work as a workaround for the above example.
Can relay domains support relaying directly to a LMTP port?
## Before you open your issue
- [x] Check if no issue or pull-request for this already exists.
- [x] Check [documentation](https://mailu.io/master/) and [FAQ](https://mailu.io/master/faq.html). (Tip, use the search function on the documentation page)
- [x] You understand `Mailu` is made by volunteers in their **free time** — be conscise, civil and accept that delays can occur.
- [x] The title of the issue should be short and simple. It should contain specific terms related to the actual issue. Be specific while writing the title.

## Environment & Versions

### Environment
 - [ ] docker-compose
 - [ ] kubernetes
 - [x] docker swarm

### Versions

We're using the `master` docker tag.

## Description

When using relay domains in the web interface, the implementation assumes the use of SMTP. However, I am trying to relay directly using another protocol, namely, LMTP (the receiver is a mailman3 instance). 

When I see the remote host of my relay domain to `<host>:8024`, I see `refused to talk to me: 500 Error: command "HELO" not recognized)`. The Mailu postfix relay configuration assumes another postfix on the receiving end.

In my postfix configuration, I see it is possible to support a map such as `lmtp:/<ip>:<port>` and then postfix understands not to start with a `EHLO` command and pass the mail using LMTP (as far as I understand).

So, would it be possible to support LMTP relaying using relay domains?

## Replication Steps

- Setup any relay domain
- Specify a receiving port of 8024
- Setup a receiver on port 8024 expecting LMTP-based requests

## Expected behaviour

Relay domains can support LMTP.

## Logs

```
mail_example_com_smtp.1.zh0tmwq3qnjn@autonomic-swarm    | May 23 09:21:25 mail postfix/smtp[378]: 63D4536B052: to=<doesitwork@lists.example.com>, relay=lists_example_com_core[10.0.44.41]:8024, delay=1.4, delays=1.3/0.08/0.01/0, dsn=5.0.0, status=bounced (host lists_example_com_core[10.0.52.41] refused to talk to me: 500 Error: command "HELO" not recognized)
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `core/admin/mailu/internal/views/postfix.py`
Content:
```
1 from mailu import models
2 from mailu.internal import internal
3 
4 import flask
5 import re
6 import srslib
7 
8 
9 @internal.route("/postfix/domain/<domain_name>")
10 def postfix_mailbox_domain(domain_name):
11     if re.match("^\[.*\]$", domain_name):
12         return flask.abort(404)
13     domain = models.Domain.query.get(domain_name) or \
14              models.Alternative.query.get(domain_name) or \
15              flask.abort(404)
16     return flask.jsonify(domain.name)
17 
18 
19 @internal.route("/postfix/mailbox/<path:email>")
20 def postfix_mailbox_map(email):
21     user = models.User.query.get(email) or flask.abort(404)
22     return flask.jsonify(user.email)
23 
24 
25 @internal.route("/postfix/alias/<path:alias>")
26 def postfix_alias_map(alias):
27     localpart, domain_name = models.Email.resolve_domain(alias)
28     if localpart is None:
29         return flask.jsonify(domain_name)
30     destination = models.Email.resolve_destination(localpart, domain_name)
31     return flask.jsonify(",".join(destination)) if destination else flask.abort(404)
32 
33 
34 @internal.route("/postfix/transport/<path:email>")
35 def postfix_transport(email):
36     if email == '*' or re.match("(^|.*@)\[.*\]$", email):
37         return flask.abort(404)
38     localpart, domain_name = models.Email.resolve_domain(email)
39     relay = models.Relay.query.get(domain_name) or flask.abort(404)
40     ret = "smtp:[{0}]".format(relay.smtp)
41     if ":" in relay.smtp:
42         split = relay.smtp.split(':')
43         ret = "smtp:[{0}]:{1}".format(split[0], split[1])
44     return flask.jsonify(ret)
45 
46 
47 @internal.route("/postfix/recipient/map/<path:recipient>")
48 def postfix_recipient_map(recipient):
49     """ Rewrite the envelope recipient if it is a valid SRS address.
50 
51     This is meant for bounces to go back to the original sender.
52     """
53     srs = srslib.SRS(flask.current_app.config["SECRET_KEY"])
54     if srslib.SRS.is_srs_address(recipient):
55         try:
56             return flask.jsonify(srs.reverse(recipient))
57         except srslib.Error as error:
58             return flask.abort(404)
59     return flask.abort(404)
60 
61 
62 @internal.route("/postfix/sender/map/<path:sender>")
63 def postfix_sender_map(sender):
64     """ Rewrite the envelope sender in case the mail was not emitted by us.
65 
66     This is for bounces to come back the reverse path properly.
67     """
68     srs = srslib.SRS(flask.current_app.config["SECRET_KEY"])
69     domain = flask.current_app.config["DOMAIN"]
70     try:
71         localpart, domain_name = models.Email.resolve_domain(sender)
72     except Exception as error:
73         return flask.abort(404)
74     if models.Domain.query.get(domain_name):
75         return flask.abort(404)
76     return flask.jsonify(srs.forward(sender, domain))
77 
78 
79 @internal.route("/postfix/sender/login/<path:sender>")
80 def postfix_sender_login(sender):
81     localpart, domain_name = models.Email.resolve_domain(sender)
82     if localpart is None:
83         return flask.abort(404)
84     destination = models.Email.resolve_destination(localpart, domain_name, True)
85     return flask.jsonify(",".join(destination)) if destination else flask.abort(404)
86 
87 
88 @internal.route("/postfix/sender/access/<path:sender>")
89 def postfix_sender_access(sender):
90     """ Simply reject any sender that pretends to be from a local domain
91     """
92     if not is_void_address(sender):
93         localpart, domain_name = models.Email.resolve_domain(sender)
94         return flask.jsonify("REJECT") if models.Domain.query.get(domain_name) else flask.abort(404)
95     else:
96         return flask.abort(404)
97 
98 
99 def is_void_address(email):
100     '''True if the email is void (null) email address.
101     '''
102     if email.startswith('<') and email.endswith('>'):
103         email = email[1:-1]
104     # Some MTAs use things like '<MAILER-DAEMON>' instead of '<>'; so let's
105     # consider void any such thing.
106     return '@' not in email
107
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/core/admin/mailu/internal/views/postfix.py b/core/admin/mailu/internal/views/postfix.py
--- a/core/admin/mailu/internal/views/postfix.py
+++ b/core/admin/mailu/internal/views/postfix.py
@@ -2,6 +2,7 @@
 from mailu.internal import internal
 
 import flask
+import idna
 import re
 import srslib
 
@@ -35,13 +36,67 @@
 def postfix_transport(email):
     if email == '*' or re.match("(^|.*@)\[.*\]$", email):
         return flask.abort(404)
-    localpart, domain_name = models.Email.resolve_domain(email)
+    _, domain_name = models.Email.resolve_domain(email)
     relay = models.Relay.query.get(domain_name) or flask.abort(404)
-    ret = "smtp:[{0}]".format(relay.smtp)
-    if ":" in relay.smtp:
-        split = relay.smtp.split(':')
-        ret = "smtp:[{0}]:{1}".format(split[0], split[1])
-    return flask.jsonify(ret)
+    target = relay.smtp.lower()
+    port = None
+    use_lmtp = False
+    use_mx = False
+    # strip prefixes mx: and lmtp:
+    if target.startswith('mx:'):
+        target = target[3:]
+        use_mx = True
+    elif target.startswith('lmtp:'):
+        target = target[5:]
+        use_lmtp = True
+    # split host:port or [host]:port
+    if target.startswith('['):
+        if use_mx or ']' not in target:
+            # invalid target (mx: and [] or missing ])
+            flask.abort(400)
+        host, rest = target[1:].split(']', 1)
+        if rest.startswith(':'):
+            port = rest[1:]
+        elif rest:
+            # invalid target (rest should be :port)
+            flask.abort(400)
+    else:
+        if ':' in target:
+            host, port = target.rsplit(':', 1)
+        else:
+            host = target
+    # default for empty host part is mx:domain
+    if not host:
+        if not use_lmtp:
+            host = relay.name.lower()
+            use_mx = True
+        else:
+            # lmtp: needs a host part
+            flask.abort(400)
+    # detect ipv6 address or encode host
+    if ':' in host:
+        host = f'ipv6:{host}'
+    else:
+        try:
+            host = idna.encode(host).decode('ascii')
+        except idna.IDNAError:
+            # invalid host (fqdn not encodable)
+            flask.abort(400)
+    # validate port
+    if port is not None:
+        try:
+            port = int(port, 10)
+        except ValueError:
+            # invalid port (should be numeric)
+            flask.abort(400)
+    # create transport
+    transport = 'lmtp' if use_lmtp else 'smtp'
+    # use [] when not using MX lookups or host is an ipv6 address
+    if host.startswith('ipv6:') or (not use_lmtp and not use_mx):
+        host = f'[{host}]'
+    # create port suffix
+    port = '' if port is None else f':{port}'
+    return flask.jsonify(f'{transport}:{host}{port}')
 
 
 @internal.route("/postfix/recipient/map/<path:recipient>")

{"golden_diff": "diff --git a/core/admin/mailu/internal/views/postfix.py b/core/admin/mailu/internal/views/postfix.py\n--- a/core/admin/mailu/internal/views/postfix.py\n+++ b/core/admin/mailu/internal/views/postfix.py\n@@ -2,6 +2,7 @@\n from mailu.internal import internal\n \n import flask\n+import idna\n import re\n import srslib\n \n@@ -35,13 +36,67 @@\n def postfix_transport(email):\n     if email == '*' or re.match(\"(^|.*@)\\[.*\\]$\", email):\n         return flask.abort(404)\n-    localpart, domain_name = models.Email.resolve_domain(email)\n+    _, domain_name = models.Email.resolve_domain(email)\n     relay = models.Relay.query.get(domain_name) or flask.abort(404)\n-    ret = \"smtp:[{0}]\".format(relay.smtp)\n-    if \":\" in relay.smtp:\n-        split = relay.smtp.split(':')\n-        ret = \"smtp:[{0}]:{1}\".format(split[0], split[1])\n-    return flask.jsonify(ret)\n+    target = relay.smtp.lower()\n+    port = None\n+    use_lmtp = False\n+    use_mx = False\n+    # strip prefixes mx: and lmtp:\n+    if target.startswith('mx:'):\n+        target = target[3:]\n+        use_mx = True\n+    elif target.startswith('lmtp:'):\n+        target = target[5:]\n+        use_lmtp = True\n+    # split host:port or [host]:port\n+    if target.startswith('['):\n+        if use_mx or ']' not in target:\n+            # invalid target (mx: and [] or missing ])\n+            flask.abort(400)\n+        host, rest = target[1:].split(']', 1)\n+        if rest.startswith(':'):\n+            port = rest[1:]\n+        elif rest:\n+            # invalid target (rest should be :port)\n+            flask.abort(400)\n+    else:\n+        if ':' in target:\n+            host, port = target.rsplit(':', 1)\n+        else:\n+            host = target\n+    # default for empty host part is mx:domain\n+    if not host:\n+        if not use_lmtp:\n+            host = relay.name.lower()\n+            use_mx = True\n+        else:\n+            # lmtp: needs a host part\n+            flask.abort(400)\n+    # detect ipv6 address or encode host\n+    if ':' in host:\n+        host = f'ipv6:{host}'\n+    else:\n+        try:\n+            host = idna.encode(host).decode('ascii')\n+        except idna.IDNAError:\n+            # invalid host (fqdn not encodable)\n+            flask.abort(400)\n+    # validate port\n+    if port is not None:\n+        try:\n+            port = int(port, 10)\n+        except ValueError:\n+            # invalid port (should be numeric)\n+            flask.abort(400)\n+    # create transport\n+    transport = 'lmtp' if use_lmtp else 'smtp'\n+    # use [] when not using MX lookups or host is an ipv6 address\n+    if host.startswith('ipv6:') or (not use_lmtp and not use_mx):\n+        host = f'[{host}]'\n+    # create port suffix\n+    port = '' if port is None else f':{port}'\n+    return flask.jsonify(f'{transport}:{host}{port}')\n \n \n @internal.route(\"/postfix/recipient/map/<path:recipient>\")\n", "issue": "Mail relaying (Relayed domain) does't work when no Remote Host is configured.\nDescription: \r\nWhen in the Web Administration Interface in Relayed domain, a domain is added without a Remote Host, emails for this domain fail to be relayed. When no Remote Host is configured, Mailu is supposed to relay the email message directly to the relayed domain.\r\n\r\nIn case it is relevant I use the docker-compose deployment.\r\n\r\nReplication steps:\r\n1). Deploy a standard Mailu installation (no special configuration required). \r\n2). In the Web Administration interface, on Relayed domains page add a new relayed domain with\r\nRelayed domain name: test.mailu.io\r\nRemote Host:  (blank, keep it empty).\r\n3). Configure your email client SMTP settings to use your Mailu server on port 25 without any authentication.\r\n4). Send an email to admin@test.mailu.io. If you receive the message, server is busy try again. Then Rspamd has greylisted you. Try sending the email again in 10 to 15 minutes. It should be accepted now.\r\n5). Check the postfix logs (docker logs --tail 100 mailu_smtp_1 )\r\n\r\nAug 13 22:47:32 mail postfix/smtpd[270]: A1C493E2CE1: client=<redacted>.nl[xx.xxx.xx.xxx]\r\nAug 13 22:47:32 mail postfix/cleanup[315]: A1C493E2CE1: message-id=<71874e8e-c30d-e0a3-4d70-de4542b47664@yahoo.com>\r\nAug 13 22:47:33 mail postfix/qmgr[177]: A1C493E2CE1: from=<redacted@yahoo.com>, size=2765, nrcpt=1 (queue active)\r\nAug 13 22:47:33 mail postfix/smtpd[270]: disconnect from <redacted>.nl[xx.xxx.xx.xxx] ehlo=2 xclient=0/1 mail=1 rcpt=1 data=1 quit=1 commands=6/7\r\n**Aug 13 22:47:33 mail postfix/smtp[316]: fatal: valid hostname or network address required in server description: []\r\nAug 13 22:47:34 mail postfix/qmgr[177]: warning: private/smtp socket: malformed response**\r\nAug 13 22:47:34 mail postfix/qmgr[177]: warning: transport smtp failure -- see a previous warning/fatal/panic logfile record for the problem description\r\nAug 13 22:47:34 mail postfix/master[175]: warning: process /usr/libexec/postfix/smtp pid 316 exit status 1\r\nAug 13 22:47:34 mail postfix/master[175]: warning: /usr/libexec/postfix/smtp: bad command startup -- throttling\r\nAug 13 22:47:34 mail postfix/error[318]: A1C493E2CE1: to=<admin@test.mailu.io>, relay=none, delay=1.6, delays=0.59/1/0/0.01, dsn=4.3.0, status=deferred (unknown mail transport error)\r\n\r\nWorkaround:\r\nA workaround is to enter the hostname or IP address of the SMTP server of the relayed domain name as Remote Host. No MX lookup is performed for a hostname entered as Remote Host. For a public domain, you could use the mxtoolbox to lookup the SMTP server. E.g. in my example for test.mailu.io https://mxtoolbox.com/SuperTool.aspx?action=mx%3atest.mailu.io&run=toolpage .\r\n\r\nEntering 78.47.92.244 or test.mailu.io as Remote Host will work as a workaround for the above example.\nCan relay domains support relaying directly to a LMTP port?\n## Before you open your issue\r\n- [x] Check if no issue or pull-request for this already exists.\r\n- [x] Check [documentation](https://mailu.io/master/) and [FAQ](https://mailu.io/master/faq.html). (Tip, use the search function on the documentation page)\r\n- [x] You understand `Mailu` is made by volunteers in their **free time** \u2014 be conscise, civil and accept that delays can occur.\r\n- [x] The title of the issue should be short and simple. It should contain specific terms related to the actual issue. Be specific while writing the title.\r\n\r\n## Environment & Versions\r\n\r\n### Environment\r\n - [ ] docker-compose\r\n - [ ] kubernetes\r\n - [x] docker swarm\r\n\r\n### Versions\r\n\r\nWe're using the `master` docker tag.\r\n\r\n## Description\r\n\r\nWhen using relay domains in the web interface, the implementation assumes the use of SMTP. However, I am trying to relay directly using another protocol, namely, LMTP (the receiver is a mailman3 instance). \r\n\r\nWhen I see the remote host of my relay domain to `<host>:8024`, I see `refused to talk to me: 500 Error: command \"HELO\" not recognized)`. The Mailu postfix relay configuration assumes another postfix on the receiving end.\r\n\r\nIn my postfix configuration, I see it is possible to support a map such as `lmtp:/<ip>:<port>` and then postfix understands not to start with a `EHLO` command and pass the mail using LMTP (as far as I understand).\r\n\r\nSo, would it be possible to support LMTP relaying using relay domains?\r\n\r\n## Replication Steps\r\n\r\n- Setup any relay domain\r\n- Specify a receiving port of 8024\r\n- Setup a receiver on port 8024 expecting LMTP-based requests\r\n\r\n## Expected behaviour\r\n\r\nRelay domains can support LMTP.\r\n\r\n## Logs\r\n\r\n```\r\nmail_example_com_smtp.1.zh0tmwq3qnjn@autonomic-swarm    | May 23 09:21:25 mail postfix/smtp[378]: 63D4536B052: to=<doesitwork@lists.example.com>, relay=lists_example_com_core[10.0.44.41]:8024, delay=1.4, delays=1.3/0.08/0.01/0, dsn=5.0.0, status=bounced (host lists_example_com_core[10.0.52.41] refused to talk to me: 500 Error: command \"HELO\" not recognized)\r\n```\r\n\n", "before_files": [{"content": "from mailu import models\nfrom mailu.internal import internal\n\nimport flask\nimport re\nimport srslib\n\n\n@internal.route(\"/postfix/domain/<domain_name>\")\ndef postfix_mailbox_domain(domain_name):\n    if re.match(\"^\\[.*\\]$\", domain_name):\n        return flask.abort(404)\n    domain = models.Domain.query.get(domain_name) or \\\n             models.Alternative.query.get(domain_name) or \\\n             flask.abort(404)\n    return flask.jsonify(domain.name)\n\n\n@internal.route(\"/postfix/mailbox/<path:email>\")\ndef postfix_mailbox_map(email):\n    user = models.User.query.get(email) or flask.abort(404)\n    return flask.jsonify(user.email)\n\n\n@internal.route(\"/postfix/alias/<path:alias>\")\ndef postfix_alias_map(alias):\n    localpart, domain_name = models.Email.resolve_domain(alias)\n    if localpart is None:\n        return flask.jsonify(domain_name)\n    destination = models.Email.resolve_destination(localpart, domain_name)\n    return flask.jsonify(\",\".join(destination)) if destination else flask.abort(404)\n\n\n@internal.route(\"/postfix/transport/<path:email>\")\ndef postfix_transport(email):\n    if email == '*' or re.match(\"(^|.*@)\\[.*\\]$\", email):\n        return flask.abort(404)\n    localpart, domain_name = models.Email.resolve_domain(email)\n    relay = models.Relay.query.get(domain_name) or flask.abort(404)\n    ret = \"smtp:[{0}]\".format(relay.smtp)\n    if \":\" in relay.smtp:\n        split = relay.smtp.split(':')\n        ret = \"smtp:[{0}]:{1}\".format(split[0], split[1])\n    return flask.jsonify(ret)\n\n\n@internal.route(\"/postfix/recipient/map/<path:recipient>\")\ndef postfix_recipient_map(recipient):\n    \"\"\" Rewrite the envelope recipient if it is a valid SRS address.\n\n    This is meant for bounces to go back to the original sender.\n    \"\"\"\n    srs = srslib.SRS(flask.current_app.config[\"SECRET_KEY\"])\n    if srslib.SRS.is_srs_address(recipient):\n        try:\n            return flask.jsonify(srs.reverse(recipient))\n        except srslib.Error as error:\n            return flask.abort(404)\n    return flask.abort(404)\n\n\n@internal.route(\"/postfix/sender/map/<path:sender>\")\ndef postfix_sender_map(sender):\n    \"\"\" Rewrite the envelope sender in case the mail was not emitted by us.\n\n    This is for bounces to come back the reverse path properly.\n    \"\"\"\n    srs = srslib.SRS(flask.current_app.config[\"SECRET_KEY\"])\n    domain = flask.current_app.config[\"DOMAIN\"]\n    try:\n        localpart, domain_name = models.Email.resolve_domain(sender)\n    except Exception as error:\n        return flask.abort(404)\n    if models.Domain.query.get(domain_name):\n        return flask.abort(404)\n    return flask.jsonify(srs.forward(sender, domain))\n\n\n@internal.route(\"/postfix/sender/login/<path:sender>\")\ndef postfix_sender_login(sender):\n    localpart, domain_name = models.Email.resolve_domain(sender)\n    if localpart is None:\n        return flask.abort(404)\n    destination = models.Email.resolve_destination(localpart, domain_name, True)\n    return flask.jsonify(\",\".join(destination)) if destination else flask.abort(404)\n\n\n@internal.route(\"/postfix/sender/access/<path:sender>\")\ndef postfix_sender_access(sender):\n    \"\"\" Simply reject any sender that pretends to be from a local domain\n    \"\"\"\n    if not is_void_address(sender):\n        localpart, domain_name = models.Email.resolve_domain(sender)\n        return flask.jsonify(\"REJECT\") if models.Domain.query.get(domain_name) else flask.abort(404)\n    else:\n        return flask.abort(404)\n\n\ndef is_void_address(email):\n    '''True if the email is void (null) email address.\n    '''\n    if email.startswith('<') and email.endswith('>'):\n        email = email[1:-1]\n    # Some MTAs use things like '<MAILER-DAEMON>' instead of '<>'; so let's\n    # consider void any such thing.\n    return '@' not in email\n", "path": "core/admin/mailu/internal/views/postfix.py"}], "after_files": [{"content": "from mailu import models\nfrom mailu.internal import internal\n\nimport flask\nimport idna\nimport re\nimport srslib\n\n\n@internal.route(\"/postfix/domain/<domain_name>\")\ndef postfix_mailbox_domain(domain_name):\n    if re.match(\"^\\[.*\\]$\", domain_name):\n        return flask.abort(404)\n    domain = models.Domain.query.get(domain_name) or \\\n             models.Alternative.query.get(domain_name) or \\\n             flask.abort(404)\n    return flask.jsonify(domain.name)\n\n\n@internal.route(\"/postfix/mailbox/<path:email>\")\ndef postfix_mailbox_map(email):\n    user = models.User.query.get(email) or flask.abort(404)\n    return flask.jsonify(user.email)\n\n\n@internal.route(\"/postfix/alias/<path:alias>\")\ndef postfix_alias_map(alias):\n    localpart, domain_name = models.Email.resolve_domain(alias)\n    if localpart is None:\n        return flask.jsonify(domain_name)\n    destination = models.Email.resolve_destination(localpart, domain_name)\n    return flask.jsonify(\",\".join(destination)) if destination else flask.abort(404)\n\n\n@internal.route(\"/postfix/transport/<path:email>\")\ndef postfix_transport(email):\n    if email == '*' or re.match(\"(^|.*@)\\[.*\\]$\", email):\n        return flask.abort(404)\n    _, domain_name = models.Email.resolve_domain(email)\n    relay = models.Relay.query.get(domain_name) or flask.abort(404)\n    target = relay.smtp.lower()\n    port = None\n    use_lmtp = False\n    use_mx = False\n    # strip prefixes mx: and lmtp:\n    if target.startswith('mx:'):\n        target = target[3:]\n        use_mx = True\n    elif target.startswith('lmtp:'):\n        target = target[5:]\n        use_lmtp = True\n    # split host:port or [host]:port\n    if target.startswith('['):\n        if use_mx or ']' not in target:\n            # invalid target (mx: and [] or missing ])\n            flask.abort(400)\n        host, rest = target[1:].split(']', 1)\n        if rest.startswith(':'):\n            port = rest[1:]\n        elif rest:\n            # invalid target (rest should be :port)\n            flask.abort(400)\n    else:\n        if ':' in target:\n            host, port = target.rsplit(':', 1)\n        else:\n            host = target\n    # default for empty host part is mx:domain\n    if not host:\n        if not use_lmtp:\n            host = relay.name.lower()\n            use_mx = True\n        else:\n            # lmtp: needs a host part\n            flask.abort(400)\n    # detect ipv6 address or encode host\n    if ':' in host:\n        host = f'ipv6:{host}'\n    else:\n        try:\n            host = idna.encode(host).decode('ascii')\n        except idna.IDNAError:\n            # invalid host (fqdn not encodable)\n            flask.abort(400)\n    # validate port\n    if port is not None:\n        try:\n            port = int(port, 10)\n        except ValueError:\n            # invalid port (should be numeric)\n            flask.abort(400)\n    # create transport\n    transport = 'lmtp' if use_lmtp else 'smtp'\n    # use [] when not using MX lookups or host is an ipv6 address\n    if host.startswith('ipv6:') or (not use_lmtp and not use_mx):\n        host = f'[{host}]'\n    # create port suffix\n    port = '' if port is None else f':{port}'\n    return flask.jsonify(f'{transport}:{host}{port}')\n\n\n@internal.route(\"/postfix/recipient/map/<path:recipient>\")\ndef postfix_recipient_map(recipient):\n    \"\"\" Rewrite the envelope recipient if it is a valid SRS address.\n\n    This is meant for bounces to go back to the original sender.\n    \"\"\"\n    srs = srslib.SRS(flask.current_app.config[\"SECRET_KEY\"])\n    if srslib.SRS.is_srs_address(recipient):\n        try:\n            return flask.jsonify(srs.reverse(recipient))\n        except srslib.Error as error:\n            return flask.abort(404)\n    return flask.abort(404)\n\n\n@internal.route(\"/postfix/sender/map/<path:sender>\")\ndef postfix_sender_map(sender):\n    \"\"\" Rewrite the envelope sender in case the mail was not emitted by us.\n\n    This is for bounces to come back the reverse path properly.\n    \"\"\"\n    srs = srslib.SRS(flask.current_app.config[\"SECRET_KEY\"])\n    domain = flask.current_app.config[\"DOMAIN\"]\n    try:\n        localpart, domain_name = models.Email.resolve_domain(sender)\n    except Exception as error:\n        return flask.abort(404)\n    if models.Domain.query.get(domain_name):\n        return flask.abort(404)\n    return flask.jsonify(srs.forward(sender, domain))\n\n\n@internal.route(\"/postfix/sender/login/<path:sender>\")\ndef postfix_sender_login(sender):\n    localpart, domain_name = models.Email.resolve_domain(sender)\n    if localpart is None:\n        return flask.abort(404)\n    destination = models.Email.resolve_destination(localpart, domain_name, True)\n    return flask.jsonify(\",\".join(destination)) if destination else flask.abort(404)\n\n\n@internal.route(\"/postfix/sender/access/<path:sender>\")\ndef postfix_sender_access(sender):\n    \"\"\" Simply reject any sender that pretends to be from a local domain\n    \"\"\"\n    if not is_void_address(sender):\n        localpart, domain_name = models.Email.resolve_domain(sender)\n        return flask.jsonify(\"REJECT\") if models.Domain.query.get(domain_name) else flask.abort(404)\n    else:\n        return flask.abort(404)\n\n\ndef is_void_address(email):\n    '''True if the email is void (null) email address.\n    '''\n    if email.startswith('<') and email.endswith('>'):\n        email = email[1:-1]\n    # Some MTAs use things like '<MAILER-DAEMON>' instead of '<>'; so let's\n    # consider void any such thing.\n    return '@' not in email\n", "path": "core/admin/mailu/internal/views/postfix.py"}]}