#!/usr/bin/env python3 """ Bounce detection and header rewriting """ from typing import Tuple, Any from logger import log from aws.dynamodb_handler import DynamoDBHandler class BounceHandler: """Handles bounce detection and header rewriting""" def __init__(self, dynamodb: DynamoDBHandler): self.dynamodb = dynamodb @staticmethod def is_ses_bounce_notification(parsed_email) -> bool: """Check if email is from SES MAILER-DAEMON""" from_header = (parsed_email.get('From') or '').lower() return 'mailer-daemon@' in from_header and 'amazonses.com' in from_header def apply_bounce_logic( self, parsed, subject: str, worker_name: str = 'unified' ) -> Tuple[Any, bool]: """ Check for SES Bounce, lookup in DynamoDB and rewrite headers Args: parsed: Parsed email message object subject: Email subject worker_name: Worker name for logging Returns: Tuple of (parsed_email_object, was_modified_bool) """ if not self.is_ses_bounce_notification(parsed): return parsed, False log("🔍 Detected SES MAILER-DAEMON bounce notification", 'INFO', worker_name) # Extract Message-ID from header message_id = (parsed.get('Message-ID') or '').strip('<>').split('@')[0] if not message_id: log("⚠ Could not extract Message-ID from bounce notification", 'WARNING', worker_name) return parsed, False log(f" Looking up Message-ID: {message_id}", 'INFO', worker_name) # Lookup in DynamoDB bounce_info = self.dynamodb.get_bounce_info(message_id, worker_name) if not bounce_info: return parsed, False # Bounce Info ausgeben original_source = bounce_info['original_source'] bounced_recipients = bounce_info['bouncedRecipients'] bounce_type = bounce_info['bounceType'] bounce_subtype = bounce_info['bounceSubType'] log(f"✓ Found bounce info:", 'INFO', worker_name) log(f" Original sender: {original_source}", 'INFO', worker_name) log(f" Bounce type: {bounce_type}/{bounce_subtype}", 'INFO', worker_name) log(f" Bounced recipients: {bounced_recipients}", 'INFO', worker_name) if bounced_recipients: new_from = bounced_recipients[0] # Rewrite Headers parsed['X-Original-SES-From'] = parsed.get('From', '') parsed['X-Bounce-Type'] = f"{bounce_type}/{bounce_subtype}" parsed.replace_header('From', new_from) if not parsed.get('Reply-To'): parsed['Reply-To'] = new_from # Subject anpassen if 'delivery status notification' in subject.lower() or 'thanks for your submission' in subject.lower(): parsed.replace_header('Subject', f"Delivery Status: {new_from}") log(f"✓ Rewritten FROM: {new_from}", 'SUCCESS', worker_name) return parsed, True log("⚠ No bounced recipients found in bounce info", 'WARNING', worker_name) return parsed, False