# src/services/gmail_api.py import os import re import base64 from google_auth_oauthlib.flow import InstalledAppFlow from googleapiclient.discovery import build from google.auth.transport.requests import Request from google.oauth2.credentials import Credentials STORAGE_DIR = os.path.abspath("./storage") def sanitize_filename(name): clean = re.sub(r'[\\/*?:"<>|]', "", name or "Untitled") return clean[:80].strip() class GmailDownloader: SCOPES = ['https://www.googleapis.com/auth/gmail.readonly'] def __init__(self, credentials_json="credentials.json", account_email="slohning@gmail.com"): self.account_email = account_email self.creds_json = credentials_json self.service = self._authenticate() def _authenticate(self): if not os.path.exists(self.creds_json): return None creds = None token_file = 'token_gmail.json' if os.path.exists(token_file): creds = Credentials.from_authorized_user_file(token_file, self.SCOPES) if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file(self.creds_json, self.SCOPES) creds = flow.run_local_server(port=0) with open(token_file, 'w') as token: token.write(creds.to_json()) return build('gmail', 'v1', credentials=creds) def download_inbox(self, callback_signal): if not self.service: callback_signal.emit(f"[{self.account_email}] Auth Error: Missing {self.creds_json} configuration.") return [] results = self.service.users().messages().list(userId='me', maxResults=20, q="label:INBOX").execute() messages = results.get('messages', []) extracted = [] os.makedirs(STORAGE_DIR, exist_ok=True) for m in messages: msg_id = m['id'] # Fetch raw RFC 822 format raw_msg = self.service.users().messages().get(userId='me', id=msg_id, format='raw').execute() meta_msg = self.service.users().messages().get(userId='me', id=msg_id, format='full').execute() headers = meta_msg.get('payload', {}).get('headers', []) subject = next((h['value'] for h in headers if h['name'].lower() == 'subject'), 'No Subject') sender = next((h['value'] for h in headers if h['name'].lower() == 'from'), 'Unknown') date_str = next((h['value'] for h in headers if h['name'].lower() == 'date'), 'UnknownDate') eml_data = base64.urlsafe_b64decode(raw_msg['raw'].encode('ASCII')) fname = f"GMAIL_{sanitize_filename(subject)}_{msg_id[-6:]}.eml" fpath = os.path.abspath(os.path.join(STORAGE_DIR, fname)) with open(fpath, "wb") as f: f.write(eml_data) extracted.append({ "account": self.account_email, "id": msg_id, "subject": subject, "sender": sender, "date": date_str, "path": fpath }) callback_signal.emit(f"[{self.account_email}] Downloaded: {fname}") return extracted