Files

178 lines
4.3 KiB
Python
Executable File

#!/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())