from google.oauth2.credentials import Credentials from google_auth_oauthlib.flow import InstalledAppFlow from googleapiclient.discovery import build import base64, os from dotenv import load_dotenv load_dotenv() SCOPES = ['https://www.googleapis.com/auth/gmail.modify'] def get_gmail_service(): creds = None if os.path.exists(os.getenv("GOOGLE_TOKEN_FILE")): creds = Credentials.from_authorized_user_file(os.getenv("GOOGLE_TOKEN_FILE"), SCOPES) if not creds or not creds.valid: flow = InstalledAppFlow.from_client_secrets_file(os.getenv("GOOGLE_CREDENTIALS_FILE"), SCOPES) creds = flow.run_local_server(port=0) with open(os.getenv("GOOGLE_TOKEN_FILE"), 'w') as f: f.write(creds.to_json()) return build('gmail', 'v1', credentials=creds) def fetch_unread_emails(max_results=10): service = get_gmail_service() results = service.users().messages().list( userId='me', labelIds=['INBOX', 'UNREAD'], maxResults=max_results ).execute() messages = results.get('messages', []) emails = [] for msg in messages: full = service.users().messages().get(userId='me', id=msg['id'], format='full').execute() headers = {h['name']: h['value'] for h in full['payload']['headers']} body = '' if 'parts' in full['payload']: for part in full['payload']['parts']: if part['mimeType'] == 'text/plain': body = base64.urlsafe_b64decode(part['body']['data']).decode('utf-8') emails.append({ 'id': msg['id'], 'from': headers.get('From', ''), 'subject': headers.get('Subject', ''), 'body': body[:1000] # truncate for LLM context }) return emails def send_reply(service, original_msg_id, to, subject, body_text): import email.mime.text, email.mime.multipart msg = email.mime.multipart.MIMEMultipart() msg['To'] = to msg['Subject'] = f"Re: {subject}" msg.attach(email.mime.text.MIMEText(body_text, 'plain')) raw = base64.urlsafe_b64encode(msg.as_bytes()).decode() service.users().messages().send(userId='me', body={'raw': raw}).execute()