Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- """
- Yahoo Mail Client - OAuth 2.0 Version
- Supports SOCKS5 Proxy (with Auth)
- Authentication: XOAUTH2
- """
- import os
- import sys
- import imaplib
- import smtplib
- import socket
- import socks
- import email
- import base64
- import json
- import logging
- import requests
- from email.mime.text import MIMEText
- from email.mime.multipart import MIMEMultipart
- from typing import List, Optional, Union, Dict, Any
- from pathlib import Path
- from datetime import datetime, timedelta
- # Logging Configuration
- logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
- logger = logging.getLogger(__name__)
- class Socks5ProxyAdapter(requests.adapters.HTTPAdapter):
- """Requests adapter supporting SOCKS5 proxy"""
- def __init__(self, proxy_host: str, proxy_port: int,
- proxy_user: Optional[str] = None,
- proxy_pass: Optional[str] = None, *args, **kwargs):
- self.proxy_host = proxy_host
- self.proxy_port = proxy_port
- self.proxy_user = proxy_user
- self.proxy_pass = proxy_pass
- super().__init__(*args, **kwargs)
- def init_poolmanager(self, *args, **kwargs):
- # Setup SOCKS5 proxy
- socks.set_default_proxy(
- socks.SOCKS5,
- self.proxy_host,
- self.proxy_port,
- username=self.proxy_user,
- password=self.proxy_pass
- )
- socket.socket = socks.socksocket
- return super().init_poolmanager(*args, **kwargs)
- class YahooOAuth2Client:
- """Yahoo OAuth 2.0 Authentication Client"""
- # Yahoo OAuth 2.0 Endpoints
- TOKEN_URL = "https://api.login.yahoo.com/oauth2/get_token"
- AUTH_URL = "https://api.login.yahoo.com/oauth2/request_auth"
- # Yahoo Mail Servers
- SMTP_SERVER = "smtp.mail.yahoo.com"
- SMTP_PORT = 587 # TLS
- IMAP_SERVER = "imap.mail.yahoo.com"
- IMAP_PORT = 993
- def __init__(self, email_address: str,
- client_id: str,
- refresh_token: str,
- proxy_host: Optional[str] = None,
- proxy_port: Optional[int] = None,
- proxy_username: Optional[str] = None,
- proxy_password: Optional[str] = None):
- """
- Initialize Yahoo OAuth 2.0 Client
- """
- self.email_address = email_address
- self.client_id = client_id
- self.refresh_token = refresh_token
- self.access_token = None
- self.token_expiry = None
- self.proxy_host = proxy_host
- self.proxy_port = proxy_port
- self.proxy_username = proxy_username
- self.proxy_password = proxy_password
- # Setup proxy
- self._setup_proxy()
- # Save original socket
- self.original_socket = socket.socket
- def _setup_proxy(self):
- """Configure SOCKS5 Proxy"""
- if self.proxy_host and self.proxy_port:
- if self.proxy_username and self.proxy_password:
- socks.set_default_proxy(
- socks.SOCKS5,
- self.proxy_host,
- self.proxy_port,
- username=self.proxy_username,
- password=self.proxy_password
- )
- else:
- socks.set_default_proxy(
- socks.SOCKS5,
- self.proxy_host,
- self.proxy_port
- )
- socket.socket = socks.socksocket
- logger.info(f"SOCKS5 Proxy enabled: {self.proxy_host}:{self.proxy_port}")
- def _disable_proxy(self):
- """Disable Proxy"""
- socket.socket = self.original_socket
- def get_access_token(self, force_refresh: bool = False) -> Optional[str]:
- """
- Retrieve Access Token (Auto-refresh)
- """
- if not force_refresh and self.access_token and self.token_expiry:
- if datetime.now() < self.token_expiry:
- return self.access_token
- logger.info("Refreshing Access Token...")
- payload = {
- "grant_type": "refresh_token",
- "client_id": self.client_id,
- "refresh_token": self.refresh_token
- }
- headers = {
- "Content-Type": "application/x-www-form-urlencoded"
- }
- try:
- response = requests.post(
- self.TOKEN_URL,
- data=payload,
- headers=headers,
- timeout=15
- )
- response.raise_for_status()
- result = response.json()
- new_token = result.get("access_token")
- expires_in = result.get("expires_in", 3600)
- if new_token:
- self.access_token = new_token
- self.token_expiry = datetime.now() + timedelta(seconds=expires_in)
- logger.info("Access Token refreshed successfully.")
- return new_token
- else:
- logger.error(f"Refresh failed: 'access_token' missing in response. Data: {result}")
- return None
- except requests.exceptions.Timeout:
- logger.error("Error: Yahoo connection timed out (Check proxy/network)")
- except requests.exceptions.ConnectionError:
- logger.error("Error: Connection failed (Check if proxy is active)")
- except requests.exceptions.HTTPError as e:
- logger.error(f"Error: HTTP request failed (Status: {response.status_code})")
- logger.error(f"Response: {response.text}")
- except Exception as e:
- logger.error(f"Unexpected error: {str(e)}")
- return None
- def _create_xoauth2_string(self) -> str:
- """Create XOAUTH2 Authentication String"""
- if not self.access_token:
- self.get_access_token()
- auth_string = f"user={self.email_address}\x01auth=Bearer {self.access_token}\x01\x01"
- return base64.b64encode(auth_string.encode('utf-8')).decode('utf-8')
- def send_email(self, to_addrs: Union[str, List[str]], subject: str,
- body: str, body_type: str = 'plain') -> bool:
- """
- Send Email via SMTP (XOAUTH2)
- """
- try:
- if isinstance(to_addrs, str):
- to_addrs = [to_addrs]
- msg = MIMEMultipart()
- msg['From'] = self.email_address
- msg['To'] = ', '.join(to_addrs)
- msg['Subject'] = subject
- msg.attach(MIMEText(body, body_type, 'utf-8'))
- logger.info("Connecting to SMTP server...")
- server = smtplib.SMTP(self.SMTP_SERVER, self.SMTP_PORT, timeout=30)
- server.starttls()
- auth_string = self._create_xoauth2_string()
- server.docmd('AUTH', f'XOAUTH2 {auth_string}')
- logger.info("SMTP Authentication successful.")
- server.sendmail(self.email_address, to_addrs, msg.as_string())
- logger.info(f"Email sent successfully: '{subject}'")
- server.quit()
- return True
- except Exception as e:
- logger.error(f"Failed to send email: {e}")
- return False
- def receive_emails(self, folder: str = 'INBOX',
- max_emails: int = 10) -> List[Dict[str, Any]]:
- """
- Receive Emails via IMAP (XOAUTH2)
- """
- emails = []
- mail = None
- try:
- logger.info("Connecting to IMAP server...")
- mail = imaplib.IMAP4_SSL(self.IMAP_SERVER, self.IMAP_PORT)
- auth_string = f"user={self.email_address}\x01auth=Bearer {self.access_token}\x01\x01"
- mail.authenticate('XOAUTH2', lambda x: auth_string.encode('utf-8'))
- logger.info("IMAP Authentication successful.")
- mail.select(folder)
- status, message_ids = mail.search(None, 'ALL')
- if status != 'OK':
- logger.error("Failed to search emails.")
- return emails
- id_list = message_ids[0].split()
- logger.info(f"Found {len(id_list)} emails total.")
- for msg_id in id_list[-max_emails:]:
- status, msg_data = mail.fetch(msg_id, '(RFC822)')
- if status != 'OK':
- continue
- email_body = msg_data[0][1]
- msg = email.message_from_bytes(email_body)
- emails.append({
- 'subject': self._decode_header(msg.get('Subject', 'No Subject')),
- 'from': self._decode_header(msg.get('From', 'Unknown')),
- 'date': msg.get('Date', ''),
- 'body': self._get_email_body(msg)
- })
- logger.info(f"Successfully retrieved {len(emails)} emails.")
- except Exception as e:
- logger.error(f"Failed to receive emails: {e}")
- finally:
- if mail:
- try:
- mail.close()
- mail.logout()
- except:
- pass
- return emails
- def _get_email_body(self, msg) -> str:
- if msg.is_multipart():
- for part in msg.walk():
- if part.get_content_type() == 'text/plain':
- try:
- return part.get_payload(decode=True).decode('utf-8', errors='ignore')
- except:
- pass
- else:
- try:
- return msg.get_payload(decode=True).decode('utf-8', errors='ignore')
- except:
- pass
- return ""
- def _decode_header(self, header: str) -> str:
- if not header:
- return ""
- try:
- decoded_parts = email.header.decode_header(header)
- result = []
- for part, charset in decoded_parts:
- if isinstance(part, bytes):
- if charset:
- result.append(part.decode(charset, errors='ignore'))
- else:
- result.append(part.decode('utf-8', errors='ignore'))
- else:
- result.append(part)
- return ' '.join(result)
- except:
- return header
- def __enter__(self):
- return self
- def __exit__(self, exc_type, exc_val, exc_tb):
- self._disable_proxy()
- def main():
- """Main Program"""
- print("=== Yahoo Mail Client (OAuth 2.0) ===\n")
- # Credentials
- EMAIL = "[email protected]"
- CLIENT_ID = "dj0yJmk9RDNqOWdZc0wwZm40JmQ9WVdrOU5FTkdZbFE1YlZBbWNHbzlNQT09JnM9Y29uc3VtZXJzZWNyZXQmc3Y9MCZ4PWNi"
- REFRESH_TOKEN = "ALiaoGnXJpbq3Y7WJwjXcH2pUsr0~001~fh2nne1vPVUZp4UocDMn"
- # Proxy Configuration
- PROXY_HOST = None # e.g., "127.0.0.1"
- PROXY_PORT = None # e.g., 1080
- PROXY_USER = None
- PROXY_PASS = None
- # Init Client
- with YahooOAuth2Client(
- email_address=EMAIL,
- client_id=CLIENT_ID,
- refresh_token=REFRESH_TOKEN,
- proxy_host=PROXY_HOST,
- proxy_port=PROXY_PORT,
- proxy_username=PROXY_USER,
- proxy_password=PROXY_PASS
- ) as client:
- print("Testing Access Token retrieval...")
- token = client.get_access_token()
- if token:
- print(f"✅ Access Token retrieved: {token[:20]}...")
- else:
- print("❌ Failed to retrieve Access Token.")
- return
- # Main Menu
- while True:
- print("\nSelect an action:")
- print("1. Send Email")
- print("2. Receive Latest Emails")
- print("3. Refresh Token")
- print("4. Exit")
- choice = input("Enter option (1-4): ").strip()
- if choice == '1':
- to_addr = input("To: ").strip()
- subject = input("Subject: ").strip()
- body = input("Body: ").strip()
- if client.send_email(to_addr, subject, body):
- print("✅ Sent successfully")
- else:
- print("❌ Failed to send")
- elif choice == '2':
- emails = client.receive_emails(max_emails=5)
- print(f"\nLatest {len(emails)} Emails:")
- for i, email_data in enumerate(emails, 1):
- print(f"{i}. {email_data['subject']}")
- print(f" From: {email_data['from']}")
- print(f" Date: {email_data['date']}")
- print("-" * 20)
- elif choice == '3':
- token = client.get_access_token(force_refresh=True)
- if token:
- print(f"✅ Token refreshed successfully.")
- else:
- print("❌ Token refresh failed.")
- elif choice == '4':
- print("Goodbye!")
- break
- if __name__ == "__main__":
- main()
Add Comment
Please, Sign In to add comment