email-amazon/unified-worker/email-worker/email/bounce_handler.py

92 lines
3.2 KiB
Python

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