144-python-email-extractor/src/services/gmail_api.py
2026-10-05 14:18:15 +11:00

84 lines
No EOL
3.3 KiB
Python

# 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