Add selective Postfix SRS installation and management
This commit is contained in:
Executable
+177
@@ -0,0 +1,177 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import smtplib
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
SMTP_HOST = "127.0.0.1"
|
||||
SMTP_PORT = 10028
|
||||
|
||||
DECISION_SCRIPT = "/usr/local/sbin/srs-alias-decision.py"
|
||||
SRS_MAP = "socketmap:inet:127.0.0.1:10003:forward"
|
||||
|
||||
EX_TEMPFAIL = 75
|
||||
EX_UNAVAILABLE = 69
|
||||
|
||||
|
||||
def run_command(args):
|
||||
result = subprocess.run(
|
||||
args,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=30
|
||||
)
|
||||
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError(
|
||||
result.stderr.strip()
|
||||
or result.stdout.strip()
|
||||
or f"Exit-Code {result.returncode}"
|
||||
)
|
||||
|
||||
return result.stdout.strip()
|
||||
|
||||
|
||||
def determine_sender(sender, recipient, original_recipient):
|
||||
decision = run_command([
|
||||
DECISION_SCRIPT,
|
||||
sender,
|
||||
recipient,
|
||||
original_recipient
|
||||
])
|
||||
|
||||
if decision.startswith("NO_SRS:"):
|
||||
return sender
|
||||
|
||||
if not decision.startswith("SRS:"):
|
||||
raise RuntimeError(
|
||||
f"Keine eindeutige SRS-Entscheidung: {decision}"
|
||||
)
|
||||
|
||||
rewritten_sender = run_command([
|
||||
"/usr/sbin/postmap",
|
||||
"-q",
|
||||
sender,
|
||||
SRS_MAP
|
||||
])
|
||||
|
||||
if not rewritten_sender:
|
||||
raise RuntimeError("PostSRSd lieferte keinen Absender")
|
||||
|
||||
if not rewritten_sender.lower().endswith("@srs.warenform.de"):
|
||||
raise RuntimeError(
|
||||
f"Unerwartete SRS-Domain: {rewritten_sender}"
|
||||
)
|
||||
|
||||
if not rewritten_sender.upper().startswith(("SRS0=", "SRS1=")):
|
||||
raise RuntimeError(
|
||||
f"Ungueltige SRS-Adresse: {rewritten_sender}"
|
||||
)
|
||||
|
||||
return rewritten_sender
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) not in (5, 6):
|
||||
print(
|
||||
"Aufruf: srs-forward.py "
|
||||
"sender recipient original_recipient queue_id [envid]",
|
||||
file=sys.stderr
|
||||
)
|
||||
return EX_TEMPFAIL
|
||||
|
||||
sender, recipient, original_recipient, queue_id = sys.argv[1:5]
|
||||
envid = sys.argv[5] if len(sys.argv) == 6 else ""
|
||||
|
||||
if envid.startswith("envid="):
|
||||
envid = envid[len("envid="):]
|
||||
|
||||
try:
|
||||
envelope_sender = determine_sender(
|
||||
sender,
|
||||
recipient,
|
||||
original_recipient
|
||||
)
|
||||
|
||||
message = sys.stdin.buffer.read()
|
||||
|
||||
with smtplib.SMTP(
|
||||
SMTP_HOST,
|
||||
SMTP_PORT,
|
||||
timeout=30
|
||||
) as smtp:
|
||||
smtp.ehlo()
|
||||
|
||||
mail_options = []
|
||||
rcpt_options = []
|
||||
|
||||
if envid:
|
||||
if not smtp.has_extn("dsn"):
|
||||
raise RuntimeError(
|
||||
"SMTP-Ziel unterstuetzt kein DSN/ENVID"
|
||||
)
|
||||
mail_options.append(f"ENVID={envid}")
|
||||
|
||||
if original_recipient and smtp.has_extn("dsn"):
|
||||
rcpt_options.append(
|
||||
f"ORCPT=rfc822;{original_recipient}"
|
||||
)
|
||||
|
||||
smtp.sendmail(
|
||||
envelope_sender,
|
||||
[recipient],
|
||||
message,
|
||||
mail_options=mail_options,
|
||||
rcpt_options=rcpt_options
|
||||
)
|
||||
|
||||
except smtplib.SMTPRecipientsRefused as exc:
|
||||
codes = [
|
||||
code
|
||||
for code, response in exc.recipients.values()
|
||||
]
|
||||
|
||||
permanent = bool(codes) and all(
|
||||
500 <= code < 600 for code in codes
|
||||
)
|
||||
|
||||
result = EX_UNAVAILABLE if permanent else EX_TEMPFAIL
|
||||
enhanced_status = "5.0.0" if permanent else "4.0.0"
|
||||
|
||||
print(
|
||||
f"{enhanced_status} SRS queue_id={queue_id}: "
|
||||
f"SMTP-Empfaengerablehnung: {exc.recipients!r}",
|
||||
file=sys.stderr
|
||||
)
|
||||
return result
|
||||
|
||||
except smtplib.SMTPResponseException as exc:
|
||||
code = exc.smtp_code
|
||||
result = EX_UNAVAILABLE if 500 <= code < 600 else EX_TEMPFAIL
|
||||
|
||||
enhanced_status = "5.0.0" if result == EX_UNAVAILABLE else "4.0.0"
|
||||
|
||||
print(
|
||||
f"{enhanced_status} SRS queue_id={queue_id}: "
|
||||
f"SMTP {code}: {exc.smtp_error!r}",
|
||||
file=sys.stderr
|
||||
)
|
||||
return result
|
||||
|
||||
except (
|
||||
subprocess.TimeoutExpired,
|
||||
RuntimeError,
|
||||
smtplib.SMTPException,
|
||||
OSError
|
||||
) as exc:
|
||||
print(
|
||||
f"SRS queue_id={queue_id}: temporaerer Fehler: {exc}",
|
||||
file=sys.stderr
|
||||
)
|
||||
return EX_TEMPFAIL
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user