diff --git a/email_api/email_api/app.py b/email_api/email_api/app.py index dc205f6..fbc0aee 100644 --- a/email_api/email_api/app.py +++ b/email_api/email_api/app.py @@ -53,6 +53,17 @@ def domain_exists(domain): # domains ist eine Liste von Objekten mit key 'domain_name' 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'): """Setzt processed-Metadaten auf einen beliebigen Status.""" try: @@ -144,7 +155,7 @@ def process_email(domain): data = request.get_json() if not data: return jsonify({'error': 'Invalid payload'}), 400 - + request_id = data.get('request_id', 'no-request-id') payload_summary = { @@ -157,35 +168,49 @@ def process_email(domain): f"[{request_id}] INCOMING POST /process/{domain}: " f"payload_summary={payload_summary}" ) - + + # 1) E-Mail decodieren und parsen wie gehabt content = data.get('email_content') compressed = data.get('compressed', False) raw = base64.b64decode(content) email_bytes = gzip.decompress(raw) if compressed else raw - + 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}' - recipients = [] - for hdr in ('to', 'cc', 'bcc'): + for hdr in ('to','cc','bcc'): 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: return jsonify({'error': 'No recipients'}), 400 - # Domain-Check - recipient_domains = {addr.split('@')[-1] for addr in recipients} - if not any(domain_exists(d) for d in recipient_domains): - logger.info(f"[{request_id}] No known recipient domains ({recipient_domains}) – skip.") - return jsonify({'message': 'Unknown domain – skipped'}), 404 + # 2) Filter: nur Postfächer der angefragten Domain, die auch existieren + valid_recipients = [] + for addr in recipients: + try: + 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: - smtp.sendmail(from_addr, recipients, email_bytes) + smtp.sendmail(from_addr, valid_recipients, email_bytes) - # Keine Markierung hier mehr; übernimmt Lambda - return jsonify({'message': 'Email forwarded', 'recipients': recipients}), 200 + return jsonify({ + 'message': 'Email forwarded', + 'forwarded_to': valid_recipients + }), 200 @app.route('/retry/', methods=['GET'])