bugfix retry

This commit is contained in:
Andreas Knuth 2025-06-14 21:22:31 -05:00
parent d98a9086ca
commit 3deaedc235
1 changed files with 33 additions and 22 deletions

View File

@ -175,9 +175,10 @@ def retry_domain_emails(domain):
return jsonify({'error': 'Unauthorized'}), 401 return jsonify({'error': 'Unauthorized'}), 401
bucket = domain.replace('.', '-') + '-emails' bucket = domain.replace('.', '-') + '-emails'
# 1) Sammle alle Keys, die noch nicht processed=true sind
unprocessed = []
paginator = s3_client.get_paginator('list_objects_v2') paginator = s3_client.get_paginator('list_objects_v2')
# keys, die noch nicht processed='true' sind
unprocessed = []
for page in paginator.paginate(Bucket=bucket): for page in paginator.paginate(Bucket=bucket):
for obj in page.get('Contents', []): for obj in page.get('Contents', []):
head = s3_client.head_object(Bucket=bucket, Key=obj['Key']) head = s3_client.head_object(Bucket=bucket, Key=obj['Key'])
@ -191,56 +192,66 @@ def retry_domain_emails(domain):
for key in unprocessed: for key in unprocessed:
try: try:
# E-Mail laden und parsen # Datei und E-Mail parsen
body = s3_client.get_object(Bucket=bucket, Key=key)['Body'].read() body = s3_client.get_object(Bucket=bucket, Key=key)['Body'].read()
msg = BytesParser(policy=default).parsebytes(body) msg = BytesParser(policy=default).parsebytes(body)
from_addr = ( from_addr = (
getaddresses(msg.get_all('from', []))[0][1] getaddresses(msg.get_all('from', []))[0][1]
if msg.get_all('from') else f'retry@{domain}' if msg.get_all('from') else f'retry@{domain}'
) )
to_addrs = [addr for _n, addr in getaddresses(msg.get_all('to', []))] to_addrs = [a for _n, a in getaddresses(msg.get_all('to', []))]
cc_addrs = [addr for _n, addr in getaddresses(msg.get_all('cc', []))] cc_addrs = [a for _n, a in getaddresses(msg.get_all('cc', []))]
bcc_addrs = [addr for _n, addr in getaddresses(msg.get_all('bcc', []))] bcc_addrs = [a for _n, a in getaddresses(msg.get_all('bcc', []))]
recipients = to_addrs + cc_addrs + bcc_addrs recipients = to_addrs + cc_addrs + bcc_addrs
if not recipients: if not recipients:
# keine Empfänger → nichts markieren # keine Empfänger → nur als failed markieren
results['failed'].append(f"{key}: no recipients") results['failed'].append({'key': key, 'error': 'no recipients'})
continue continue
try: try:
# Versuch, die Mail zuzustellen # Zustellen
with smtplib.SMTP(SMTP_HOST, SMTP_PORT) as smtp: with smtplib.SMTP(SMTP_HOST, SMTP_PORT) as smtp:
smtp.sendmail(from_addr, recipients, body) smtp.sendmail(from_addr, recipients, body)
# bei Erfolg → processed=true # Erfolg
mark_email_as_processed(bucket, key, 'true') mark_email_as_processed(bucket, key, 'true')
results['processed'].append(key) results['processed'].append(key)
except smtplib.SMTPRecipientsRefused as e: except smtplib.SMTPRecipientsRefused as e:
# bei abgelehnten Adressen → unknownUser vs unknownDomain # Einzelne Adressen abgelehnt
refused = e.recipients # dict: {addr: (code, msg), ...} refused = e.recipients # dict { addr: (code, msg_bytes) }
# check, ob eine abgelehnte Adresse zur eigenen Domain gehört # bestimme Status
if any(addr.split('@')[-1] == domain for addr in refused): status = (
status = 'unknownUser' 'unknownUser'
else: if any(addr.split('@')[-1] == domain for addr in refused)
status = 'unknownDomain' else 'unknownDomain'
)
# bytes → string
clean = {}
for addr, (code, msg) in refused.items():
msg_str = msg.decode('utf-8', errors='ignore') if isinstance(msg, bytes) else str(msg)
clean[addr] = {'code': code, 'message': msg_str}
mark_email_as_processed(bucket, key, status) mark_email_as_processed(bucket, key, status)
results['processed'].append(key) results['processed'].append(key)
results['failed'].append({key: refused}) results['failed'].append({'key': key, 'refused': clean})
except Exception as e: except Exception as e:
# andere SMTP-/Verbindungs-Fehler → nicht markieren # andere SMTP-Fehler
results['failed'].append(f"{key}: {e}") mark_email_as_processed(bucket, key, 'unknownDomain')
results['processed'].append(key)
results['failed'].append({'key': key, 'error': str(e)})
except Exception as e: except Exception as e:
# Fehler beim Laden/Parsen der Objekte # Fehler beim Laden/Parsen
results['failed'].append(f"{key}: {e}") results['failed'].append({'key': key, 'error': str(e)})
return jsonify(results), 200 return jsonify(results), 200
@app.route('/health', methods=['GET']) @app.route('/health', methods=['GET'])
def health_check(): def health_check():
return jsonify({'status': 'OK'}), 200 return jsonify({'status': 'OK'}), 200