Compare commits

...

2 Commits

1 changed files with 89 additions and 18 deletions

View File

@ -77,7 +77,8 @@ class RulesProcessor:
forwards,
domain,
worker_name,
metrics_callback
metrics_callback,
rule=rule
)
def _handle_ooo(
@ -141,34 +142,104 @@ class RulesProcessor:
forwards: list,
domain: str,
worker_name: str,
metrics_callback=None
metrics_callback=None,
rule: dict = None # NEU
):
"""Handle email forwarding"""
# NEU: SMTP Override aus Rule lesen
smtp_override = None
if rule:
smtp_override = rule.get('forward_smtp_override')
for forward_to in forwards:
try:
fwd_msg = self._create_forward_message(parsed, recipient, forward_to, original_from)
fwd_msg = self._create_forward_message(
parsed, recipient, forward_to, original_from
)
fwd_bytes = fwd_msg.as_bytes()
# Distinguish: Internal (Port 2525) vs External (SES)
if is_internal_address(forward_to):
# Internal address → direct via Port 2525 (no loop!)
success = self._send_internal_email(recipient, forward_to, fwd_bytes, worker_name)
# NEU: Legacy SMTP Override (Migration)
if smtp_override:
success = self._send_via_legacy_smtp(
recipient, forward_to, fwd_bytes,
smtp_override, worker_name
)
if success:
log(f"✓ Forwarded internally to {forward_to}", 'SUCCESS', worker_name)
log(f"✓ Forwarded via legacy SMTP to {forward_to} "
f"({smtp_override.get('host', '?')})",
'SUCCESS', worker_name)
else:
log(f"⚠ Internal forward failed to {forward_to}", 'WARNING', worker_name)
else:
# External address → via SES
success = self.ses.send_raw_email(recipient, forward_to, fwd_bytes, worker_name)
log(f"⚠ Legacy SMTP forward failed to {forward_to}",
'WARNING', worker_name)
elif is_internal_address(forward_to):
success = self._send_internal_email(
recipient, forward_to, fwd_bytes, worker_name
)
if success:
log(f"✓ Forwarded externally to {forward_to} via SES", 'SUCCESS', worker_name)
log(f"✓ Forwarded internally to {forward_to}",
'SUCCESS', worker_name)
else:
log(f"⚠ Internal forward failed to {forward_to}",
'WARNING', worker_name)
else:
success = self.ses.send_raw_email(
recipient, forward_to, fwd_bytes, worker_name
)
if success:
log(f"✓ Forwarded externally to {forward_to} via SES",
'SUCCESS', worker_name)
if metrics_callback:
metrics_callback('forward', domain)
except Exception as e:
log(f"⚠ Forward failed to {forward_to}: {e}", 'ERROR', worker_name)
log(f"⚠ Forward failed to {forward_to}: {e}",
'ERROR', worker_name)
@staticmethod
def _send_via_legacy_smtp(
from_addr: str,
to_addr: str,
raw_message: bytes,
smtp_config: dict,
worker_name: str
) -> bool:
"""
Send email directly to a legacy SMTP server (for migration).
Bypasses SES completely to avoid mail loops.
"""
try:
host = smtp_config.get('host', '')
# DynamoDB speichert Zahlen als Decimal, daher int()
port = int(smtp_config.get('port', 25))
use_tls = smtp_config.get('tls', False)
username = smtp_config.get('username')
password = smtp_config.get('password')
if not host:
log(f" ✗ Legacy SMTP: no host configured", 'ERROR', worker_name)
return False
with smtplib.SMTP(host, port, timeout=30) as conn:
conn.ehlo()
if use_tls:
conn.starttls()
conn.ehlo()
if username and password:
conn.login(username, password)
conn.sendmail(from_addr, [to_addr], raw_message)
return True
except Exception as e:
log(
f" ✗ Legacy SMTP failed ({smtp_config.get('host', '?')}:"
f"{smtp_config.get('port', '?')}): {e}",
'ERROR', worker_name
)
return False
@staticmethod
def _send_internal_email(from_addr: str, to_addr: str, raw_message: bytes, worker_name: str) -> bool:
"""