mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2026-11-08 18:13:37 +00:00
54 lines
1.9 KiB
Python
Executable File
54 lines
1.9 KiB
Python
Executable File
#!/usr/bin/python3
|
|
# Policy service of the mail policies (mailcow-policy in master.cf, spawned by Postfix): reads the policy requests
|
|
# of smtpd and asks the mailcow UI for the action (nginx:8081/mailpolicy.php). Without an answer the recipient is
|
|
# deferred; smtpd only asks while policies or internal aliases exist (mysql_mail_policy_maps.cf).
|
|
|
|
import http.client
|
|
import re
|
|
import socket
|
|
import sys
|
|
from urllib.parse import urlencode
|
|
|
|
# one line: DUNNO or a rejection with code and text
|
|
valid_action = re.compile(rb'DUNNO|[45]\d\d [45]\.\d{1,3}\.\d{1,3} [\x20-\x7e]{1,200}')
|
|
unavailable = b'DEFER_IF_PERMIT Mail policy check temporarily unavailable'
|
|
# address of nginx, resolved once per process (a lookup costs more than the check)
|
|
nginx = None
|
|
|
|
def check(request):
|
|
global nginx
|
|
body = urlencode(sorted(request.items())).encode()
|
|
try:
|
|
if nginx is None:
|
|
nginx = socket.gethostbyname('nginx')
|
|
# http.client sets TCP_NODELAY, so the body is not held back until the headers are acknowledged
|
|
conn = http.client.HTTPConnection(nginx, 8081, timeout=10)
|
|
try:
|
|
conn.request('POST', '/mailpolicy.php', body, {'Host': 'nginx', 'Content-Type': 'application/x-www-form-urlencoded'})
|
|
response = conn.getresponse()
|
|
action = response.read()
|
|
finally:
|
|
conn.close()
|
|
except (OSError, http.client.HTTPException):
|
|
# nginx may have a new address after a restart
|
|
nginx = None
|
|
return unavailable
|
|
return action if response.status == 200 and valid_action.fullmatch(action) else unavailable
|
|
|
|
def main():
|
|
request = {}
|
|
# attributes as bytes: addresses may contain any 8-bit characters
|
|
for line in sys.stdin.buffer:
|
|
line = line.rstrip(b'\r\n')
|
|
if line:
|
|
name, separator, value = line.partition(b'=')
|
|
if separator:
|
|
request[name] = value
|
|
continue
|
|
sys.stdout.buffer.write(b'action=' + check(request) + b'\n\n')
|
|
sys.stdout.buffer.flush()
|
|
request = {}
|
|
|
|
if __name__ == '__main__':
|
|
main()
|