update
This commit is contained in:
parent
a3e86add49
commit
df0d92ba27
|
|
@ -11,10 +11,21 @@ sqs = boto3.client('sqs', region_name='us-east-2')
|
|||
# AWS Region
|
||||
AWS_REGION = 'us-east-2'
|
||||
|
||||
# Dynamo Table
|
||||
dynamo = boto3.resource('dynamodb', region_name=AWS_REGION)
|
||||
msg_table = dynamo.Table('ses-outbound-messages')
|
||||
|
||||
# Metadata Keys
|
||||
PROCESSED_KEY = 'processed'
|
||||
PROCESSED_VALUE = 'true'
|
||||
|
||||
def is_ses_autoresponse(parsed):
|
||||
from_h = (parsed.get('From') or '').lower()
|
||||
auto_sub = (parsed.get('Auto-Submitted') or '').lower()
|
||||
return (
|
||||
'mailer-daemon@us-east-2.amazonses.com' in from_h
|
||||
and 'auto-replied' in auto_sub
|
||||
)
|
||||
|
||||
def domain_to_bucket(domain: str) -> str:
|
||||
"""Konvertiert Domain zu S3 Bucket Namen"""
|
||||
|
|
@ -323,19 +334,91 @@ def lambda_handler(event, context):
|
|||
|
||||
# E-Mail laden um Subject zu extrahieren
|
||||
subject = '(unknown)'
|
||||
raw_bytes = b''
|
||||
parsed = None
|
||||
modified = False
|
||||
|
||||
try:
|
||||
print(f"\n📖 Reading email for metadata...")
|
||||
obj = s3.get_object(Bucket=bucket, Key=key)
|
||||
raw_bytes = obj['Body'].read()
|
||||
|
||||
# Nur Headers parsen (schneller)
|
||||
metadata = obj.get('Metadata', {}) or {}
|
||||
|
||||
# Header parsen
|
||||
parsed = BytesParser(policy=SMTPPolicy).parsebytes(raw_bytes)
|
||||
subject = parsed.get('subject', '(no subject)')
|
||||
|
||||
print(f" Subject: {subject}")
|
||||
|
||||
|
||||
# 🔁 SES Auto-Response erkennen
|
||||
if is_ses_autoresponse(parsed):
|
||||
print(" Detected SES auto-response (out-of-office)")
|
||||
|
||||
# Message-ID der ursprünglichen Mail aus In-Reply-To / References holen
|
||||
in_reply_to = (parsed.get('In-Reply-To') or '').strip()
|
||||
if not in_reply_to:
|
||||
refs = (parsed.get('References') or '').strip()
|
||||
# nimm die erste ID aus References
|
||||
in_reply_to = refs.split()[0] if refs else ''
|
||||
|
||||
lookup_id = ''
|
||||
if in_reply_to.startswith('<') and '>' in in_reply_to:
|
||||
lookup_id = in_reply_to[1:in_reply_to.find('>')]
|
||||
else:
|
||||
lookup_id = in_reply_to
|
||||
|
||||
original = None
|
||||
if lookup_id:
|
||||
try:
|
||||
res = msg_table.get_item(Key={'MessageId': lookup_id})
|
||||
original = res.get('Item')
|
||||
print(f" Dynamo lookup for {lookup_id}: {'hit' if original else 'miss'}")
|
||||
except Exception as e:
|
||||
print(f"⚠ Dynamo lookup failed: {e}")
|
||||
|
||||
if original:
|
||||
orig_from = original.get('source', '')
|
||||
destinations = original.get('destinations', []) or []
|
||||
# einfache Variante: nimm den ersten Empfänger
|
||||
orig_to = destinations[0] if destinations else ''
|
||||
|
||||
# Domain hast du oben bereits aus recipients[0] extrahiert
|
||||
display = f"Out of Office from {orig_to}" if orig_to else "Out of Office"
|
||||
|
||||
# ursprüngliche Infos sichern
|
||||
parsed['X-SES-Original-From'] = parsed.get('From', '')
|
||||
parsed['X-SES-Original-Recipient'] = orig_to
|
||||
|
||||
# From für den User "freundlich" machen
|
||||
parsed.replace_header('From', f'"{display}" <no-reply@{domain}>')
|
||||
|
||||
# Antworten trotzdem an den Absender deiner ursprünglichen Mail
|
||||
if orig_from:
|
||||
parsed['Reply-To'] = orig_from
|
||||
|
||||
subj = parsed.get('Subject', 'out of office')
|
||||
if not subj.lower().startswith('out of office'):
|
||||
parsed.replace_header('Subject', f"Out of office: {subj}")
|
||||
|
||||
# geänderte Mail zurück in Bytes
|
||||
raw_bytes = parsed.as_bytes()
|
||||
modified = True
|
||||
print(" Auto-response rewritten for delivery to user inbox")
|
||||
else:
|
||||
print(" No original send record found for auto-response")
|
||||
|
||||
# Wenn wir die Mail verändert haben, aktualisieren wir das S3-Objekt
|
||||
if modified:
|
||||
s3.put_object(
|
||||
Bucket=bucket,
|
||||
Key=key,
|
||||
Body=raw_bytes,
|
||||
Metadata=metadata
|
||||
)
|
||||
print(" Updated S3 object with rewritten auto-response")
|
||||
|
||||
except Exception as e:
|
||||
print(f" ⚠ Could not parse email (continuing): {e}")
|
||||
|
||||
|
||||
# In Queue einreihen (EINE Message mit ALLEN Recipients)
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
import boto3
|
||||
import os
|
||||
|
||||
dynamo = boto3.resource('dynamodb', region_name='us-east-2')
|
||||
table = dynamo.Table('ses-outbound-messages')
|
||||
|
||||
def lambda_handler(event, context):
|
||||
detail = event['detail']
|
||||
mail = detail['mail']
|
||||
msg_id = mail['messageId']
|
||||
source = mail['source']
|
||||
destinations = mail['destination'] # Liste
|
||||
|
||||
if not msg_id:
|
||||
print("No MessageId in event")
|
||||
return
|
||||
|
||||
if event_type == 'SEND':
|
||||
# wie bisher
|
||||
source = mail.get('source')
|
||||
destinations = mail.get('destination', [])
|
||||
table.put_item(
|
||||
Item={
|
||||
'MessageId': msg_id,
|
||||
'source': source,
|
||||
'destinations': destinations,
|
||||
'timestamp': mail.get('timestamp')
|
||||
}
|
||||
)
|
||||
return
|
||||
|
||||
if event_type == 'BOUNCE':
|
||||
bounce = detail.get('bounce', {})
|
||||
bounced = [
|
||||
r.get('emailAddress')
|
||||
for r in bounce.get('bouncedRecipients', [])
|
||||
if r.get('emailAddress')
|
||||
]
|
||||
if not bounced:
|
||||
print("No bouncedRecipients in bounce event")
|
||||
return
|
||||
|
||||
# in DynamoDB anhängen
|
||||
table.update_item(
|
||||
Key={'MessageId': msg_id},
|
||||
UpdateExpression="ADD bouncedRecipients :b",
|
||||
ExpressionAttributeValues={
|
||||
':b': set(bounced) # String-Set
|
||||
}
|
||||
)
|
||||
print(f"Updated {msg_id} with bouncedRecipients={bounced}")
|
||||
return
|
||||
|
||||
if event_type == 'COMPLAINT':
|
||||
complaint = detail.get('complaint', {})
|
||||
complained = [
|
||||
r.get('emailAddress')
|
||||
for r in complaint.get('complainedRecipients', [])
|
||||
if r.get('emailAddress')
|
||||
]
|
||||
if not complained:
|
||||
return
|
||||
|
||||
table.update_item(
|
||||
Key={'MessageId': msg_id},
|
||||
UpdateExpression="ADD complaintRecipients :c",
|
||||
ExpressionAttributeValues={
|
||||
':c': set(complained)
|
||||
}
|
||||
)
|
||||
print(f"Updated {msg_id} with complaintRecipients={complained}")
|
||||
return
|
||||
Loading…
Reference in New Issue