check for valid recipients

This commit is contained in:
Andreas Knuth 2025-06-16 19:38:45 -05:00
parent b2a0c6e611
commit c645f71225
1 changed files with 40 additions and 15 deletions

View File

@ -53,6 +53,17 @@ def domain_exists(domain):
# domains ist eine Liste von Objekten mit key 'domain_name' # domains ist eine Liste von Objekten mit key 'domain_name'
return any(d.get('domain_name') == domain for d in domains) return any(d.get('domain_name') == domain for d in domains)
def inbox_exists(domain, local_part):
"""
Prüft, ob für `local_part@domain` ein Postfach angelegt ist.
"""
url = f"{MAILCOW_API}/get/mailbox/all/{domain}"
headers = {'X-API-Key': API_KEY}
resp = requests.get(url, headers=headers, timeout=5)
resp.raise_for_status()
mailboxes = resp.json()
return any(m.get('local_part') == local_part for m in mailboxes)
def mark_email_as_processed(bucket, key, status, processor='rest-api'): def mark_email_as_processed(bucket, key, status, processor='rest-api'):
"""Setzt processed-Metadaten auf einen beliebigen Status.""" """Setzt processed-Metadaten auf einen beliebigen Status."""
try: try:
@ -158,6 +169,7 @@ def process_email(domain):
f"payload_summary={payload_summary}" f"payload_summary={payload_summary}"
) )
# 1) E-Mail decodieren und parsen wie gehabt
content = data.get('email_content') content = data.get('email_content')
compressed = data.get('compressed', False) compressed = data.get('compressed', False)
raw = base64.b64decode(content) raw = base64.b64decode(content)
@ -165,27 +177,40 @@ def process_email(domain):
msg = BytesParser(policy=default).parsebytes(email_bytes) msg = BytesParser(policy=default).parsebytes(email_bytes)
from_addr = getaddresses(msg.get_all('from', []))[0][1] if msg.get_all('from') else f'lambda@{domain}' from_addr = getaddresses(msg.get_all('from', []))[0][1] if msg.get_all('from') else f'lambda@{domain}'
recipients = [] recipients = []
for hdr in ('to', 'cc', 'bcc'): for hdr in ('to','cc','bcc'):
recipients += [addr for _n, addr in getaddresses(msg.get_all(hdr, []))] recipients += [addr for _n, addr in getaddresses(msg.get_all(hdr, []))]
logger.debug(f"[{request_id}] Parsed email: from={from_addr}, recipients={recipients}")
if not recipients: if not recipients:
return jsonify({'error': 'No recipients'}), 400 return jsonify({'error': 'No recipients'}), 400
# Domain-Check # 2) Filter: nur Postfächer der angefragten Domain, die auch existieren
recipient_domains = {addr.split('@')[-1] for addr in recipients} valid_recipients = []
if not any(domain_exists(d) for d in recipient_domains): for addr in recipients:
logger.info(f"[{request_id}] No known recipient domains ({recipient_domains}) skip.") try:
return jsonify({'message': 'Unknown domain skipped'}), 404 local, dom = addr.split('@', 1)
except ValueError:
continue
if dom.lower() != domain.lower():
# andere Domain: überspringen
continue
if inbox_exists(domain, local):
valid_recipients.append(addr)
else:
logger.info(f"Skipping non-existent inbox: {addr}")
if not valid_recipients:
logger.info(f"[{request_id}] Keine gültigen Inboxes für {domain} skip.")
return jsonify({'message': 'No valid inboxes skipped'}), 404
# 3) Senden an die gefilterten Adressen
with smtplib.SMTP(SMTP_HOST, SMTP_PORT) as smtp: with smtplib.SMTP(SMTP_HOST, SMTP_PORT) as smtp:
smtp.sendmail(from_addr, recipients, email_bytes) smtp.sendmail(from_addr, valid_recipients, email_bytes)
# Keine Markierung hier mehr; übernimmt Lambda return jsonify({
return jsonify({'message': 'Email forwarded', 'recipients': recipients}), 200 'message': 'Email forwarded',
'forwarded_to': valid_recipients
}), 200
@app.route('/retry/<domain>', methods=['GET']) @app.route('/retry/<domain>', methods=['GET'])