import os
import logging
from pathlib import Path
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
SCOPES = [
"https://www.googleapis.com/auth/gmail.readonly",
"https://www.googleapis.com/auth/gmail.compose"
]
# Find project root by looking for pyproject.toml
def find_project_root():
current = Path(__file__).resolve()
for parent in current.parents:
if (parent / "pyproject.toml").exists():
return str(parent)
# Fallback to going up 3 levels
return str(current.parent.parent.parent)
BASE_DIR = find_project_root()
CREDENTIALS_PATH = os.path.join(BASE_DIR, "client_secret_oauth_gcp.json")
TOKEN_PATH = os.path.join(BASE_DIR, "token.json")
def get_credentials():
creds = None
if os.path.exists(TOKEN_PATH):
try:
creds = Credentials.from_authorized_user_file(TOKEN_PATH, SCOPES)
except Exception as e:
# If token file exists but can't be loaded (e.g., scope mismatch), delete it
logging.warning(f"Could not load existing token: {e}. Will re-authenticate.")
os.remove(TOKEN_PATH)
creds = None
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
try:
creds.refresh(Request())
except Exception as e:
# If refresh fails (e.g., scope mismatch), delete token and re-authenticate
logging.warning(f"Token refresh failed: {e}. Will re-authenticate.")
if os.path.exists(TOKEN_PATH):
os.remove(TOKEN_PATH)
creds = None
if not creds:
# Need to re-authenticate
flow = InstalledAppFlow.from_client_secrets_file(
CREDENTIALS_PATH, SCOPES
)
creds = flow.run_local_server(port=0)
with open(TOKEN_PATH, "w") as token:
token.write(creds.to_json())
return creds
def gmail_service():
creds = get_credentials()
return build("gmail", "v1", credentials=creds)