Merge branch 'main' into contabo

This commit is contained in:
Andreas Knuth 2026-03-07 12:02:22 -06:00
commit 4324a5785f
4 changed files with 54 additions and 28 deletions

View File

@ -1,3 +1,12 @@
[DEFAULT] [DEFAULT]
# Whitelist: Localhost, private Docker-Netze und die Office-IP in Texas # Whitelist: Localhost, private Docker-Netze und die Office-IP in Texas
ignoreip = 127.0.0.1/8 ::1 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 69.223.70.143 ignoreip = 127.0.0.1/8 ::1 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 69.223.70.143
[dovecot]
# Erhöht die Anzahl der erlaubten Fehlversuche auf 20
maxretry = 20
[postfix]
# Erhöht die Anzahl der erlaubten Fehlversuche auf 20
maxretry = 20

0
DMS/docker-data/dms/config/user-patches.sh Normal file → Executable file
View File

View File

@ -18,9 +18,9 @@ class BlocklistChecker:
self.dynamodb = dynamodb self.dynamodb = dynamodb
def is_sender_blocked( def is_sender_blocked(
self, self,
recipient: str, recipient: str,
sender: str, sender: str,
worker_name: str worker_name: str
) -> bool: ) -> bool:
""" """
@ -54,17 +54,17 @@ class BlocklistChecker:
return False return False
def batch_check_blocked_senders( def batch_check_blocked_senders(
self, self,
recipients: List[str], recipients: List[str],
sender: str, senders: List[str], # <-- Geändert: Erwartet nun eine Liste
worker_name: str worker_name: str
) -> Dict[str, bool]: ) -> Dict[str, bool]:
""" """
Batch check if sender is blocked for multiple recipients (more efficient) Batch check if ANY of the senders are blocked for multiple recipients (more efficient)
Args: Args:
recipients: List of recipient email addresses recipients: List of recipient email addresses
sender: Sender email address senders: List of sender email addresses (Envelope & Header)
worker_name: Worker name for logging worker_name: Worker name for logging
Returns: Returns:
@ -73,7 +73,8 @@ class BlocklistChecker:
# Get all blocked patterns in one batch call # Get all blocked patterns in one batch call
patterns_by_recipient = self.dynamodb.batch_get_blocked_patterns(recipients) patterns_by_recipient = self.dynamodb.batch_get_blocked_patterns(recipients)
sender_clean = parseaddr(sender)[1].lower() # Alle übergebenen Adressen bereinigen
senders_clean = [parseaddr(s)[1].lower() for s in senders if s]
result = {} result = {}
for recipient in recipients: for recipient in recipients:
@ -81,15 +82,18 @@ class BlocklistChecker:
is_blocked = False is_blocked = False
for pattern in patterns: for pattern in patterns:
if fnmatch.fnmatch(sender_clean, pattern.lower()): for sender_clean in senders_clean:
log( if fnmatch.fnmatch(sender_clean, pattern.lower()):
f"⛔ BLOCKED: Sender {sender_clean} matches pattern '{pattern}' " log(
f"for inbox {recipient}", f"⛔ BLOCKED: Sender {sender_clean} matches pattern '{pattern}' "
'WARNING', f"for inbox {recipient}",
worker_name 'WARNING',
) worker_name
is_blocked = True )
break is_blocked = True
break # Bricht die Senders-Schleife ab
if is_blocked:
break # Bricht die Pattern-Schleife ab
result[recipient] = is_blocked result[recipient] = is_blocked

View File

@ -4,12 +4,9 @@ Email message processing worker
""" """
import json import json
import time
import traceback import traceback
from typing import List, Tuple
from logger import log from logger import log
from config import config, domain_to_bucket_name
from aws import S3Handler, SQSHandler, SESHandler, DynamoDBHandler from aws import S3Handler, SQSHandler, SESHandler, DynamoDBHandler
from email_processing import EmailParser, BounceHandler, RulesProcessor, BlocklistChecker from email_processing import EmailParser, BounceHandler, RulesProcessor, BlocklistChecker
from smtp.delivery import EmailDelivery from smtp.delivery import EmailDelivery
@ -17,6 +14,7 @@ from metrics.prometheus import MetricsCollector
from email.parser import BytesParser # War wahrscheinlich schon da, prüfen from email.parser import BytesParser # War wahrscheinlich schon da, prüfen
from email.policy import compat32 # <--- NEU: Hinzufügen from email.policy import compat32 # <--- NEU: Hinzufügen
class MessageProcessor: class MessageProcessor:
"""Processes individual email messages""" """Processes individual email messages"""
@ -105,7 +103,6 @@ class MessageProcessor:
log("⚠ Warning: No recipients in event", 'WARNING', worker_name) log("⚠ Warning: No recipients in event", 'WARNING', worker_name)
return True return True
bucket = domain_to_bucket_name(domain)
key = message_id key = message_id
# Compact single-line log for email processing # Compact single-line log for email processing
@ -123,7 +120,7 @@ class MessageProcessor:
skip_rules = self.parser.is_processed_by_worker(temp_parsed) skip_rules = self.parser.is_processed_by_worker(temp_parsed)
if skip_rules: if skip_rules:
log(f"🔄 Loop prevention: Already processed by worker", 'INFO', worker_name) log("🔄 Loop prevention: Already processed by worker", 'INFO', worker_name)
# 5. PARSING & BOUNCE LOGIC # 5. PARSING & BOUNCE LOGIC
try: try:
@ -146,7 +143,7 @@ class MessageProcessor:
log(f" 🔧 Sanitized malformed Message-ID via Legacy Mode: {clean_id}", 'INFO', worker_name) log(f" 🔧 Sanitized malformed Message-ID via Legacy Mode: {clean_id}", 'INFO', worker_name)
if self.metrics: if self.metrics:
self.metrics.increment_bounce(domain, 'sanitized_header') self.metrics.increment_bounce(domain, 'sanitized_header')
except Exception as e_sanitize: except Exception as e_sanitize:
# Sollte nicht passieren, aber wir wollen hier nicht abbrechen # Sollte nicht passieren, aber wir wollen hier nicht abbrechen
@ -163,7 +160,7 @@ class MessageProcessor:
# Klammern entfernen, aber spitze Klammern behalten # Klammern entfernen, aber spitze Klammern behalten
clean_id = current_msg_id.replace('[', '').replace(']', '') clean_id = current_msg_id.replace('[', '').replace(']', '')
parsed.replace_header('Message-ID', clean_id) parsed.replace_header('Message-ID', clean_id)
log(f" 🔧 Sanitized malformed Message-ID", 'INFO', worker_name) log(" 🔧 Sanitized malformed Message-ID", 'INFO', worker_name)
# --- FIX END --- # --- FIX END ---
subject = parsed.get('Subject', '(no subject)') subject = parsed.get('Subject', '(no subject)')
@ -203,9 +200,25 @@ class MessageProcessor:
skip_rules = False skip_rules = False
# 6. BLOCKLIST CHECK (Batch for efficiency) # 6. BLOCKLIST CHECK (Batch for efficiency)
senders_to_check = []
# 1. Die Envelope-Adresse (aus dem SES Event / Return-Path)
if from_addr:
senders_to_check.append(from_addr)
# 2. Die echte Header-Adresse (aus der MIME-E-Mail geparst)
header_from = parsed.get('From')
if header_from and header_from not in senders_to_check:
senders_to_check.append(header_from)
# 3. Falls die Bounce-Logik die Adresse umgeschrieben hat
if from_addr_final and from_addr_final not in senders_to_check:
senders_to_check.append(from_addr_final)
# Prüfe nun alle extrahierten Adressen gegen die Datenbank
blocked_by_recipient = self.blocklist.batch_check_blocked_senders( blocked_by_recipient = self.blocklist.batch_check_blocked_senders(
recipients, recipients,
from_addr_final, senders_to_check, # <-- Übergabe der Liste
worker_name worker_name
) )