84 lines
No EOL
3.3 KiB
Python
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
|
|
|