moved
This commit is contained in:
80
email-worker/email_processing/parser.py
Normal file
80
email-worker/email_processing/parser.py
Normal file
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Email parsing utilities
|
||||
"""
|
||||
|
||||
from typing import Tuple, Optional
|
||||
from email.parser import BytesParser
|
||||
from email.policy import SMTP as SMTPPolicy
|
||||
|
||||
|
||||
class EmailParser:
|
||||
"""Email parsing utilities"""
|
||||
|
||||
@staticmethod
|
||||
def parse_bytes(raw_bytes: bytes):
|
||||
"""Parse raw email bytes into email.message object"""
|
||||
return BytesParser(policy=SMTPPolicy).parsebytes(raw_bytes)
|
||||
|
||||
@staticmethod
|
||||
def extract_body_parts(parsed) -> Tuple[str, Optional[str]]:
|
||||
"""
|
||||
Extract both text/plain and text/html body parts
|
||||
|
||||
Args:
|
||||
parsed: Parsed email message object
|
||||
|
||||
Returns:
|
||||
Tuple of (text_body, html_body or None)
|
||||
"""
|
||||
text_body = ''
|
||||
html_body = None
|
||||
|
||||
if parsed.is_multipart():
|
||||
for part in parsed.walk():
|
||||
content_type = part.get_content_type()
|
||||
|
||||
if content_type == 'text/plain':
|
||||
try:
|
||||
text_body += part.get_payload(decode=True).decode('utf-8', errors='ignore')
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
elif content_type == 'text/html':
|
||||
try:
|
||||
html_body = part.get_payload(decode=True).decode('utf-8', errors='ignore')
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
payload = parsed.get_payload(decode=True)
|
||||
if payload:
|
||||
decoded = payload.decode('utf-8', errors='ignore')
|
||||
if parsed.get_content_type() == 'text/html':
|
||||
html_body = decoded
|
||||
else:
|
||||
text_body = decoded
|
||||
except Exception:
|
||||
text_body = str(parsed.get_payload())
|
||||
|
||||
return text_body.strip() if text_body else '(No body content)', html_body
|
||||
|
||||
@staticmethod
|
||||
def is_processed_by_worker(parsed) -> bool:
|
||||
"""
|
||||
Check if email was already processed by our worker (loop detection)
|
||||
|
||||
Args:
|
||||
parsed: Parsed email message object
|
||||
|
||||
Returns:
|
||||
True if already processed
|
||||
"""
|
||||
x_worker_processed = parsed.get('X-SES-Worker-Processed', '')
|
||||
auto_submitted = parsed.get('Auto-Submitted', '')
|
||||
|
||||
# Only skip if OUR header is present
|
||||
is_processed_by_us = bool(x_worker_processed)
|
||||
is_our_auto_reply = auto_submitted == 'auto-replied' and x_worker_processed
|
||||
|
||||
return is_processed_by_us or is_our_auto_reply
|
||||
Reference in New Issue
Block a user