================================================================================ GMAIL CLEANUP - CHALLENGE 1 SOLUTION Chapter 3: Gmail API Fundamentals Challenge: Connect to Gmail API ================================================================================ PROBLEM: Create gmail_utils.py with: 1. Write get_gmail_service() function 2. Handle OAuth authentication and token caching 3. Return authenticated Gmail service object SOLUTION: ================================================================================ File: gmail_utils.py import os 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.modify'] def get_gmail_service(): """Get authenticated Gmail service.""" creds = None # Try to load existing token if os.path.exists('token.json'): try: creds = Credentials.from_authorized_user_file('token.json', SCOPES) except Exception: creds = None # If token invalid or missing, get new one if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: # Token expired, refresh it creds.refresh(Request()) else: # Need full OAuth flow flow = InstalledAppFlow.from_client_secrets_file( 'credentials.json', SCOPES ) creds = flow.run_local_server(port=0) # Save token for next time with open('token.json', 'w') as token: token.write(creds.to_json()) # Build and return Gmail service service = build('gmail', 'v1', credentials=creds) return service HOW IT WORKS ================================================================================ 1. CHECK FOR TOKEN if os.path.exists('token.json'): - If token from previous run exists, try to load it - Avoids re-authenticating every time 2. VALIDATE TOKEN if not creds.valid: - Checks if token is still valid - If expired but refreshable, refreshes it - If invalid, runs OAuth flow 3. RUN OAUTH FLOW (if needed) flow = InstalledAppFlow.from_client_secrets_file(...) - Opens browser for user to authorize - Gets access token 4. SAVE TOKEN with open('token.json', 'w') as token: - Saves token for next run - Avoids re-authorization 5. RETURN SERVICE return build('gmail', 'v1', credentials=creds) - Returns authenticated Gmail API service - Ready to use for queries USAGE ================================================================================ from gmail_utils import get_gmail_service service = get_gmail_service() # First run: Opens browser for authorization # Future runs: Uses saved token (no browser) # Now you can use service to query Gmail: results = service.users().messages().list( userId='me', q='before:2020/01/01' ).execute() ERROR HANDLING ================================================================================ - Missing credentials.json: Will raise error (must download from Google Cloud) - OAuth timeout: Browser closes after 5 minutes - Network error: Will raise error (check internet) - Token revoked: Re-authorize by deleting token.json ================================================================================