check for valid recipients
This commit is contained in:
parent
b2a0c6e611
commit
c645f71225
|
|
@ -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:
|
||||||
|
|
@ -144,7 +155,7 @@ def process_email(domain):
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
if not data:
|
if not data:
|
||||||
return jsonify({'error': 'Invalid payload'}), 400
|
return jsonify({'error': 'Invalid payload'}), 400
|
||||||
|
|
||||||
request_id = data.get('request_id', 'no-request-id')
|
request_id = data.get('request_id', 'no-request-id')
|
||||||
|
|
||||||
payload_summary = {
|
payload_summary = {
|
||||||
|
|
@ -157,35 +168,49 @@ def process_email(domain):
|
||||||
f"[{request_id}] INCOMING POST /process/{domain}: "
|
f"[{request_id}] INCOMING POST /process/{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)
|
||||||
email_bytes = gzip.decompress(raw) if compressed else raw
|
email_bytes = gzip.decompress(raw) if compressed else raw
|
||||||
|
|
||||||
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'])
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue