prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Provide a "slow" transport for Postfix
  ## Environment & Versions
  ### Environment
   - [x] docker-compose
   - [ ] kubernetes
   - [ ] docker swarm
  
  ### Versions
  1.9
  
  ## Description
  Orange, a mainstream french ISP, and a few others, have a rate limit : without a slow transport, I get deferred messages with this : "Too many connections, slow down." It is a known issue https://blog.network-studio.fr/2011/06/30/too-many-connections-slow-down/
  
  I managed to get it done with the overrides/ files :
  
  overrides/postfix.cf :
  
  ```
  transport_maps = socketmap:unix:/tmp/podop.socket:transport lmdb:/etc/postfix/transport.map
  
  slow_destination_concurrency_limit = 1
  slow_destination_recipient_limit = 20
  slow_destination_rate_delay = 5s
  slow_destination_concurrency_failed_cohort_limit=10
  
  ```
  overrides/postfix.master :
  
  ```
  slow/unix= slow unix - - n - 5 smtp -o syslog_name=postfix-slow
  ```
  
  overrides/transport.map :
  
  ```
  wanadoo.com slow:
  wanadoo.fr slow:
  orange.com slow:
  orange.fr slow:
  laposte.net slow:
  free.fr slow:
  hotmail.fr slow:
  outlook.fr slow:
  yahoo.fr slow:
  ```
  I did not have time to fully test it, but it seems to work. Configuration values may need a fine tuning...
  
  It would be nice to have such "slow" transport built in in Mailu, with an override possibility to edit the domain list.
  
  --- 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/postfix/start.py`
  Content:
  ```
  1 #!/usr/bin/python3
  2 
  3 import os
  4 import glob
  5 import shutil
  6 import multiprocessing
  7 import logging as log
  8 import sys
  9 
  10 from podop import run_server
  11 from pwd import getpwnam
  12 from socrate import system, conf
  13 
  14 log.basicConfig(stream=sys.stderr, level=os.environ.get("LOG_LEVEL", "WARNING"))
  15 
  16 def start_podop():
  17     os.setuid(getpwnam('postfix').pw_uid)
  18     os.mkdir('/dev/shm/postfix',mode=0o700)
  19     url = "http://" + os.environ["ADMIN_ADDRESS"] + "/internal/postfix/"
  20     # TODO: Remove verbosity setting from Podop?
  21     run_server(0, "postfix", "/tmp/podop.socket", [
  22         ("transport", "url", url + "transport/§"),
  23         ("alias", "url", url + "alias/§"),
  24         ("dane", "url", url + "dane/§"),
  25         ("domain", "url", url + "domain/§"),
  26         ("mailbox", "url", url + "mailbox/§"),
  27         ("recipientmap", "url", url + "recipient/map/§"),
  28         ("sendermap", "url", url + "sender/map/§"),
  29         ("senderaccess", "url", url + "sender/access/§"),
  30         ("senderlogin", "url", url + "sender/login/§"),
  31         ("senderrate", "url", url + "sender/rate/§")
  32     ])
  33 
  34 def start_mta_sts_daemon():
  35     os.chmod("/root/", 0o755) # read access to /root/.netrc required
  36     os.setuid(getpwnam('postfix').pw_uid)
  37     from postfix_mta_sts_resolver import daemon
  38     daemon.main()
  39 
  40 def is_valid_postconf_line(line):
  41     return not line.startswith("#") \
  42             and not line == ''
  43 
  44 # Actual startup script
  45 os.environ['DEFER_ON_TLS_ERROR'] = os.environ['DEFER_ON_TLS_ERROR'] if 'DEFER_ON_TLS_ERROR' in os.environ else 'True'
  46 os.environ["FRONT_ADDRESS"] = system.get_host_address_from_environment("FRONT", "front")
  47 os.environ["ADMIN_ADDRESS"] = system.get_host_address_from_environment("ADMIN", "admin")
  48 os.environ["ANTISPAM_MILTER_ADDRESS"] = system.get_host_address_from_environment("ANTISPAM_MILTER", "antispam:11332")
  49 os.environ["LMTP_ADDRESS"] = system.get_host_address_from_environment("LMTP", "imap:2525")
  50 os.environ["POSTFIX_LOG_SYSLOG"] = os.environ.get("POSTFIX_LOG_SYSLOG","local")
  51 os.environ["POSTFIX_LOG_FILE"] = os.environ.get("POSTFIX_LOG_FILE", "")
  52 
  53 for postfix_file in glob.glob("/conf/*.cf"):
  54     conf.jinja(postfix_file, os.environ, os.path.join("/etc/postfix", os.path.basename(postfix_file)))
  55 
  56 if os.path.exists("/overrides/postfix.cf"):
  57     for line in open("/overrides/postfix.cf").read().strip().split("\n"):
  58         if is_valid_postconf_line(line):
  59             os.system('postconf -e "{}"'.format(line))
  60 
  61 if os.path.exists("/overrides/postfix.master"):
  62     for line in open("/overrides/postfix.master").read().strip().split("\n"):
  63         if is_valid_postconf_line(line):
  64             os.system('postconf -Me "{}"'.format(line))
  65 
  66 for map_file in glob.glob("/overrides/*.map"):
  67     destination = os.path.join("/etc/postfix", os.path.basename(map_file))
  68     shutil.copyfile(map_file, destination)
  69     os.system("postmap {}".format(destination))
  70     os.remove(destination)
  71 
  72 if os.path.exists("/overrides/mta-sts-daemon.yml"):
  73     shutil.copyfile("/overrides/mta-sts-daemon.yml", "/etc/mta-sts-daemon.yml")
  74 else:
  75     conf.jinja("/conf/mta-sts-daemon.yml", os.environ, "/etc/mta-sts-daemon.yml")
  76 
  77 if not os.path.exists("/etc/postfix/tls_policy.map.lmdb"):
  78     open("/etc/postfix/tls_policy.map", "a").close()
  79     os.system("postmap /etc/postfix/tls_policy.map")
  80 
  81 if "RELAYUSER" in os.environ:
  82     path = "/etc/postfix/sasl_passwd"
  83     conf.jinja("/conf/sasl_passwd", os.environ, path)
  84     os.system("postmap {}".format(path))
  85 
  86 # Configure and start local rsyslog server
  87 conf.jinja("/conf/rsyslog.conf", os.environ, "/etc/rsyslog.conf")
  88 os.system("/usr/sbin/rsyslogd -niNONE &")
  89 # Configure logrotate and start crond
  90 if os.environ["POSTFIX_LOG_FILE"] != "":
  91     conf.jinja("/conf/logrotate.conf", os.environ, "/etc/logrotate.d/postfix.conf")
  92     os.system("/usr/sbin/crond")
  93     if os.path.exists("/overrides/logrotate.conf"):
  94         shutil.copyfile("/overrides/logrotate.conf", "/etc/logrotate.d/postfix.conf")
  95 
  96 # Run Podop and Postfix
  97 multiprocessing.Process(target=start_podop).start()
  98 multiprocessing.Process(target=start_mta_sts_daemon).start()
  99 os.system("/usr/libexec/postfix/post-install meta_directory=/etc/postfix create-missing")
  100 # Before starting postfix, we need to check permissions on /queue
  101 # in the event that postfix,postdrop id have changed
  102 os.system("postfix set-permissions")
  103 os.system("postfix start-fg")
  104
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/core/postfix/start.py b/core/postfix/start.py
  --- a/core/postfix/start.py
  +++ b/core/postfix/start.py
  @@ -74,9 +74,10 @@
   else:
       conf.jinja("/conf/mta-sts-daemon.yml", os.environ, "/etc/mta-sts-daemon.yml")
   
  -if not os.path.exists("/etc/postfix/tls_policy.map.lmdb"):
  -    open("/etc/postfix/tls_policy.map", "a").close()
  -    os.system("postmap /etc/postfix/tls_policy.map")
  +for policy in ['tls_policy', 'transport']:
  +    if not os.path.exists(f'/etc/postfix/{policy}.map.lmdb'):
  +        open(f'/etc/postfix/{policy}.map', 'a').close()
  +        os.system(f'postmap /etc/postfix/{policy}.map')
   
   if "RELAYUSER" in os.environ:
       path = "/etc/postfix/sasl_passwd"
  
verification_info: {"golden_diff": "diff --git a/core/postfix/start.py b/core/postfix/start.py\n--- a/core/postfix/start.py\n+++ b/core/postfix/start.py\n@@ -74,9 +74,10 @@\n else:\n     conf.jinja(\"/conf/mta-sts-daemon.yml\", os.environ, \"/etc/mta-sts-daemon.yml\")\n \n-if not os.path.exists(\"/etc/postfix/tls_policy.map.lmdb\"):\n-    open(\"/etc/postfix/tls_policy.map\", \"a\").close()\n-    os.system(\"postmap /etc/postfix/tls_policy.map\")\n+for policy in ['tls_policy', 'transport']:\n+    if not os.path.exists(f'/etc/postfix/{policy}.map.lmdb'):\n+        open(f'/etc/postfix/{policy}.map', 'a').close()\n+        os.system(f'postmap /etc/postfix/{policy}.map')\n \n if \"RELAYUSER\" in os.environ:\n     path = \"/etc/postfix/sasl_passwd\"\n", "issue": "Provide a \"slow\" transport for Postfix\n## Environment & Versions\r\n### Environment\r\n - [x] docker-compose\r\n - [ ] kubernetes\r\n - [ ] docker swarm\r\n\r\n### Versions\r\n1.9\r\n\r\n## Description\r\nOrange, a mainstream french ISP, and a few others, have a rate limit : without a slow transport, I get deferred messages with this : \"Too many connections, slow down.\" It is a known issue https://blog.network-studio.fr/2011/06/30/too-many-connections-slow-down/\r\n\r\nI managed to get it done with the overrides/ files :\r\n\r\noverrides/postfix.cf :\r\n\r\n```\r\ntransport_maps = socketmap:unix:/tmp/podop.socket:transport lmdb:/etc/postfix/transport.map\r\n\r\nslow_destination_concurrency_limit = 1\r\nslow_destination_recipient_limit = 20\r\nslow_destination_rate_delay = 5s\r\nslow_destination_concurrency_failed_cohort_limit=10\r\n\r\n```\r\noverrides/postfix.master :\r\n\r\n```\r\nslow/unix= slow unix - - n - 5 smtp -o syslog_name=postfix-slow\r\n```\r\n\r\noverrides/transport.map :\r\n\r\n```\r\nwanadoo.com slow:\r\nwanadoo.fr slow:\r\norange.com slow:\r\norange.fr slow:\r\nlaposte.net slow:\r\nfree.fr slow:\r\nhotmail.fr slow:\r\noutlook.fr slow:\r\nyahoo.fr slow:\r\n```\r\nI did not have time to fully test it, but it seems to work. Configuration values may need a fine tuning...\r\n\r\nIt would be nice to have such \"slow\" transport built in in Mailu, with an override possibility to edit the domain list.\n", "before_files": [{"content": "#!/usr/bin/python3\n\nimport os\nimport glob\nimport shutil\nimport multiprocessing\nimport logging as log\nimport sys\n\nfrom podop import run_server\nfrom pwd import getpwnam\nfrom socrate import system, conf\n\nlog.basicConfig(stream=sys.stderr, level=os.environ.get(\"LOG_LEVEL\", \"WARNING\"))\n\ndef start_podop():\n    os.setuid(getpwnam('postfix').pw_uid)\n    os.mkdir('/dev/shm/postfix',mode=0o700)\n    url = \"http://\" + os.environ[\"ADMIN_ADDRESS\"] + \"/internal/postfix/\"\n    # TODO: Remove verbosity setting from Podop?\n    run_server(0, \"postfix\", \"/tmp/podop.socket\", [\n        (\"transport\", \"url\", url + \"transport/\u00a7\"),\n        (\"alias\", \"url\", url + \"alias/\u00a7\"),\n        (\"dane\", \"url\", url + \"dane/\u00a7\"),\n        (\"domain\", \"url\", url + \"domain/\u00a7\"),\n        (\"mailbox\", \"url\", url + \"mailbox/\u00a7\"),\n        (\"recipientmap\", \"url\", url + \"recipient/map/\u00a7\"),\n        (\"sendermap\", \"url\", url + \"sender/map/\u00a7\"),\n        (\"senderaccess\", \"url\", url + \"sender/access/\u00a7\"),\n        (\"senderlogin\", \"url\", url + \"sender/login/\u00a7\"),\n        (\"senderrate\", \"url\", url + \"sender/rate/\u00a7\")\n    ])\n\ndef start_mta_sts_daemon():\n    os.chmod(\"/root/\", 0o755) # read access to /root/.netrc required\n    os.setuid(getpwnam('postfix').pw_uid)\n    from postfix_mta_sts_resolver import daemon\n    daemon.main()\n\ndef is_valid_postconf_line(line):\n    return not line.startswith(\"#\") \\\n            and not line == ''\n\n# Actual startup script\nos.environ['DEFER_ON_TLS_ERROR'] = os.environ['DEFER_ON_TLS_ERROR'] if 'DEFER_ON_TLS_ERROR' in os.environ else 'True'\nos.environ[\"FRONT_ADDRESS\"] = system.get_host_address_from_environment(\"FRONT\", \"front\")\nos.environ[\"ADMIN_ADDRESS\"] = system.get_host_address_from_environment(\"ADMIN\", \"admin\")\nos.environ[\"ANTISPAM_MILTER_ADDRESS\"] = system.get_host_address_from_environment(\"ANTISPAM_MILTER\", \"antispam:11332\")\nos.environ[\"LMTP_ADDRESS\"] = system.get_host_address_from_environment(\"LMTP\", \"imap:2525\")\nos.environ[\"POSTFIX_LOG_SYSLOG\"] = os.environ.get(\"POSTFIX_LOG_SYSLOG\",\"local\")\nos.environ[\"POSTFIX_LOG_FILE\"] = os.environ.get(\"POSTFIX_LOG_FILE\", \"\")\n\nfor postfix_file in glob.glob(\"/conf/*.cf\"):\n    conf.jinja(postfix_file, os.environ, os.path.join(\"/etc/postfix\", os.path.basename(postfix_file)))\n\nif os.path.exists(\"/overrides/postfix.cf\"):\n    for line in open(\"/overrides/postfix.cf\").read().strip().split(\"\\n\"):\n        if is_valid_postconf_line(line):\n            os.system('postconf -e \"{}\"'.format(line))\n\nif os.path.exists(\"/overrides/postfix.master\"):\n    for line in open(\"/overrides/postfix.master\").read().strip().split(\"\\n\"):\n        if is_valid_postconf_line(line):\n            os.system('postconf -Me \"{}\"'.format(line))\n\nfor map_file in glob.glob(\"/overrides/*.map\"):\n    destination = os.path.join(\"/etc/postfix\", os.path.basename(map_file))\n    shutil.copyfile(map_file, destination)\n    os.system(\"postmap {}\".format(destination))\n    os.remove(destination)\n\nif os.path.exists(\"/overrides/mta-sts-daemon.yml\"):\n    shutil.copyfile(\"/overrides/mta-sts-daemon.yml\", \"/etc/mta-sts-daemon.yml\")\nelse:\n    conf.jinja(\"/conf/mta-sts-daemon.yml\", os.environ, \"/etc/mta-sts-daemon.yml\")\n\nif not os.path.exists(\"/etc/postfix/tls_policy.map.lmdb\"):\n    open(\"/etc/postfix/tls_policy.map\", \"a\").close()\n    os.system(\"postmap /etc/postfix/tls_policy.map\")\n\nif \"RELAYUSER\" in os.environ:\n    path = \"/etc/postfix/sasl_passwd\"\n    conf.jinja(\"/conf/sasl_passwd\", os.environ, path)\n    os.system(\"postmap {}\".format(path))\n\n# Configure and start local rsyslog server\nconf.jinja(\"/conf/rsyslog.conf\", os.environ, \"/etc/rsyslog.conf\")\nos.system(\"/usr/sbin/rsyslogd -niNONE &\")\n# Configure logrotate and start crond\nif os.environ[\"POSTFIX_LOG_FILE\"] != \"\":\n    conf.jinja(\"/conf/logrotate.conf\", os.environ, \"/etc/logrotate.d/postfix.conf\")\n    os.system(\"/usr/sbin/crond\")\n    if os.path.exists(\"/overrides/logrotate.conf\"):\n        shutil.copyfile(\"/overrides/logrotate.conf\", \"/etc/logrotate.d/postfix.conf\")\n\n# Run Podop and Postfix\nmultiprocessing.Process(target=start_podop).start()\nmultiprocessing.Process(target=start_mta_sts_daemon).start()\nos.system(\"/usr/libexec/postfix/post-install meta_directory=/etc/postfix create-missing\")\n# Before starting postfix, we need to check permissions on /queue\n# in the event that postfix,postdrop id have changed\nos.system(\"postfix set-permissions\")\nos.system(\"postfix start-fg\")\n", "path": "core/postfix/start.py"}], "after_files": [{"content": "#!/usr/bin/python3\n\nimport os\nimport glob\nimport shutil\nimport multiprocessing\nimport logging as log\nimport sys\n\nfrom podop import run_server\nfrom pwd import getpwnam\nfrom socrate import system, conf\n\nlog.basicConfig(stream=sys.stderr, level=os.environ.get(\"LOG_LEVEL\", \"WARNING\"))\n\ndef start_podop():\n    os.setuid(getpwnam('postfix').pw_uid)\n    os.mkdir('/dev/shm/postfix',mode=0o700)\n    url = \"http://\" + os.environ[\"ADMIN_ADDRESS\"] + \"/internal/postfix/\"\n    # TODO: Remove verbosity setting from Podop?\n    run_server(0, \"postfix\", \"/tmp/podop.socket\", [\n        (\"transport\", \"url\", url + \"transport/\u00a7\"),\n        (\"alias\", \"url\", url + \"alias/\u00a7\"),\n        (\"dane\", \"url\", url + \"dane/\u00a7\"),\n        (\"domain\", \"url\", url + \"domain/\u00a7\"),\n        (\"mailbox\", \"url\", url + \"mailbox/\u00a7\"),\n        (\"recipientmap\", \"url\", url + \"recipient/map/\u00a7\"),\n        (\"sendermap\", \"url\", url + \"sender/map/\u00a7\"),\n        (\"senderaccess\", \"url\", url + \"sender/access/\u00a7\"),\n        (\"senderlogin\", \"url\", url + \"sender/login/\u00a7\"),\n        (\"senderrate\", \"url\", url + \"sender/rate/\u00a7\")\n    ])\n\ndef start_mta_sts_daemon():\n    os.chmod(\"/root/\", 0o755) # read access to /root/.netrc required\n    os.setuid(getpwnam('postfix').pw_uid)\n    from postfix_mta_sts_resolver import daemon\n    daemon.main()\n\ndef is_valid_postconf_line(line):\n    return not line.startswith(\"#\") \\\n            and not line == ''\n\n# Actual startup script\nos.environ['DEFER_ON_TLS_ERROR'] = os.environ['DEFER_ON_TLS_ERROR'] if 'DEFER_ON_TLS_ERROR' in os.environ else 'True'\nos.environ[\"FRONT_ADDRESS\"] = system.get_host_address_from_environment(\"FRONT\", \"front\")\nos.environ[\"ADMIN_ADDRESS\"] = system.get_host_address_from_environment(\"ADMIN\", \"admin\")\nos.environ[\"ANTISPAM_MILTER_ADDRESS\"] = system.get_host_address_from_environment(\"ANTISPAM_MILTER\", \"antispam:11332\")\nos.environ[\"LMTP_ADDRESS\"] = system.get_host_address_from_environment(\"LMTP\", \"imap:2525\")\nos.environ[\"POSTFIX_LOG_SYSLOG\"] = os.environ.get(\"POSTFIX_LOG_SYSLOG\",\"local\")\nos.environ[\"POSTFIX_LOG_FILE\"] = os.environ.get(\"POSTFIX_LOG_FILE\", \"\")\n\nfor postfix_file in glob.glob(\"/conf/*.cf\"):\n    conf.jinja(postfix_file, os.environ, os.path.join(\"/etc/postfix\", os.path.basename(postfix_file)))\n\nif os.path.exists(\"/overrides/postfix.cf\"):\n    for line in open(\"/overrides/postfix.cf\").read().strip().split(\"\\n\"):\n        if is_valid_postconf_line(line):\n            os.system('postconf -e \"{}\"'.format(line))\n\nif os.path.exists(\"/overrides/postfix.master\"):\n    for line in open(\"/overrides/postfix.master\").read().strip().split(\"\\n\"):\n        if is_valid_postconf_line(line):\n            os.system('postconf -Me \"{}\"'.format(line))\n\nfor map_file in glob.glob(\"/overrides/*.map\"):\n    destination = os.path.join(\"/etc/postfix\", os.path.basename(map_file))\n    shutil.copyfile(map_file, destination)\n    os.system(\"postmap {}\".format(destination))\n    os.remove(destination)\n\nif os.path.exists(\"/overrides/mta-sts-daemon.yml\"):\n    shutil.copyfile(\"/overrides/mta-sts-daemon.yml\", \"/etc/mta-sts-daemon.yml\")\nelse:\n    conf.jinja(\"/conf/mta-sts-daemon.yml\", os.environ, \"/etc/mta-sts-daemon.yml\")\n\nfor policy in ['tls_policy', 'transport']:\n    if not os.path.exists(f'/etc/postfix/{policy}.map.lmdb'):\n        open(f'/etc/postfix/{policy}.map', 'a').close()\n        os.system(f'postmap /etc/postfix/{policy}.map')\n\nif \"RELAYUSER\" in os.environ:\n    path = \"/etc/postfix/sasl_passwd\"\n    conf.jinja(\"/conf/sasl_passwd\", os.environ, path)\n    os.system(\"postmap {}\".format(path))\n\n# Configure and start local rsyslog server\nconf.jinja(\"/conf/rsyslog.conf\", os.environ, \"/etc/rsyslog.conf\")\nos.system(\"/usr/sbin/rsyslogd -niNONE &\")\n# Configure logrotate and start crond\nif os.environ[\"POSTFIX_LOG_FILE\"] != \"\":\n    conf.jinja(\"/conf/logrotate.conf\", os.environ, \"/etc/logrotate.d/postfix.conf\")\n    os.system(\"/usr/sbin/crond\")\n    if os.path.exists(\"/overrides/logrotate.conf\"):\n        shutil.copyfile(\"/overrides/logrotate.conf\", \"/etc/logrotate.d/postfix.conf\")\n\n# Run Podop and Postfix\nmultiprocessing.Process(target=start_podop).start()\nmultiprocessing.Process(target=start_mta_sts_daemon).start()\nos.system(\"/usr/libexec/postfix/post-install meta_directory=/etc/postfix create-missing\")\n# Before starting postfix, we need to check permissions on /queue\n# in the event that postfix,postdrop id have changed\nos.system(\"postfix set-permissions\")\nos.system(\"postfix start-fg\")\n", "path": "core/postfix/start.py"}]}