improvement while reading mails
This commit is contained in:
+121
-2
@@ -26,6 +26,8 @@ from dataclasses import dataclass, field
|
||||
from email.message import Message
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
import random
|
||||
|
||||
import socks
|
||||
from dotenv import load_dotenv
|
||||
from imapclient import IMAPClient
|
||||
@@ -40,7 +42,7 @@ VALIDATION_URL_SUBJECT_FR = "Validation de votre demande de rendez-vous"
|
||||
VALIDATION_URL_SUBJECT_EN = "Please confirm your appointment request"
|
||||
VALIDATION_URL_REGEX = (
|
||||
r"https:\/\/rendezvousparis\.hermes\.com"
|
||||
r"\/client\/register\/[A-Z0-9]+\/validate\.code=[A-Z0-9]+"
|
||||
r"\/client\/register\/[A-Z0-9]+\/validate[?.]code=[A-Z0-9]+"
|
||||
)
|
||||
|
||||
DATE_FORMAT = "%d-%b-%Y"
|
||||
@@ -198,11 +200,122 @@ class ProxyIMAP4_TLS(imaplib.IMAP4):
|
||||
def shutdown(self) -> None:
|
||||
imaplib.IMAP4.shutdown(self)
|
||||
|
||||
def id(self, parameters: dict) -> tuple:
|
||||
"""
|
||||
Envoie la commande IMAP ID (RFC 2971).
|
||||
parameters : dict ex. {"name": "Thunderbird", "version": "115.0"}
|
||||
Retourne le tuple brut (typ, data) renvoyé par le serveur.
|
||||
"""
|
||||
args = " ".join(
|
||||
'"{}"'.format(str(v).replace('"', '\\"'))
|
||||
for pair in parameters.items()
|
||||
for v in pair
|
||||
)
|
||||
return self._simple_command("ID", "({})".format(args))
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# IMAPClient avec proxy
|
||||
# Profils de clients IMAP réels (pour spoofing du fingerprint)
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
_IMAP_CLIENT_PROFILES = [
|
||||
# Mozilla Thunderbird 115 (ESR) — Windows
|
||||
{
|
||||
"name": "Thunderbird",
|
||||
"version": "115.9.0",
|
||||
"vendor": "Mozilla",
|
||||
"support-url": "https://support.mozilla.org/",
|
||||
"command": "IMAP4rev1",
|
||||
"os": "Windows NT 10.0",
|
||||
"os-version": "10.0",
|
||||
},
|
||||
# Mozilla Thunderbird 115 — macOS
|
||||
{
|
||||
"name": "Thunderbird",
|
||||
"version": "115.9.0",
|
||||
"vendor": "Mozilla",
|
||||
"support-url": "https://support.mozilla.org/",
|
||||
"command": "IMAP4rev1",
|
||||
"os": "macOS",
|
||||
"os-version": "14.4",
|
||||
},
|
||||
# Apple Mail — macOS Sonoma
|
||||
{
|
||||
"name": "Mac OS X Mail",
|
||||
"version": "16.0",
|
||||
"vendor": "Apple Inc.",
|
||||
"support-url": "https://support.apple.com/mail",
|
||||
"os": "Mac OS X",
|
||||
"os-version": "14.4",
|
||||
},
|
||||
# Apple Mail — iOS
|
||||
{
|
||||
"name": "iPhone Mail",
|
||||
"version": "17.4",
|
||||
"vendor": "Apple Inc.",
|
||||
"os": "iOS",
|
||||
"os-version": "17.4",
|
||||
},
|
||||
# Outlook pour Windows (MAPI/IMAP bridge)
|
||||
{
|
||||
"name": "Microsoft Outlook",
|
||||
"version": "16.0.17531.20108",
|
||||
"vendor": "Microsoft Corporation",
|
||||
"support-url": "https://support.microsoft.com/outlook",
|
||||
"os": "Windows NT 10.0",
|
||||
"os-version": "10.0",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def _random_imap_id_params() -> dict:
|
||||
"""Retourne un profil aléatoire parmi les clients IMAP réels."""
|
||||
return random.choice(_IMAP_CLIENT_PROFILES)
|
||||
|
||||
|
||||
def send_imap_id(imap, params: Optional[dict] = None) -> None:
|
||||
"""
|
||||
Envoie la commande IMAP ID après connexion pour usurper le fingerprint
|
||||
client. Fonctionne avec IMAPClient (imapclient) et imaplib.IMAP4.
|
||||
|
||||
Paramètres
|
||||
----------
|
||||
imap : IMAPClient | imaplib.IMAP4
|
||||
params : dict, optional — si None, un profil aléatoire est choisi.
|
||||
"""
|
||||
if params is None:
|
||||
params = _random_imap_id_params()
|
||||
|
||||
try:
|
||||
if isinstance(imap, IMAPClient):
|
||||
# imapclient expose _imap (l'objet imaplib sous-jacent)
|
||||
_raw = imap._imap
|
||||
if hasattr(_raw, "id"):
|
||||
_raw.id(params)
|
||||
else:
|
||||
# Fallback : commande brute via imapclient
|
||||
args = " ".join(
|
||||
'"{}"'.format(str(v).replace('"', '\\"'))
|
||||
for pair in params.items()
|
||||
for v in pair
|
||||
)
|
||||
imap._imap._simple_command("ID", "({})".format(args))
|
||||
elif hasattr(imap, "id"):
|
||||
# ProxyIMAP4_TLS ou tout imaplib.IMAP4 patchable
|
||||
imap.id(params)
|
||||
else:
|
||||
# Dernier recours : commande brute imaplib
|
||||
args = " ".join(
|
||||
'"{}"'.format(str(v).replace('"', '\\"'))
|
||||
for pair in params.items()
|
||||
for v in pair
|
||||
)
|
||||
imap._simple_command("ID", "({})".format(args))
|
||||
except Exception as exc:
|
||||
logger.debug("IMAP ID non supporté ou ignoré : %s", exc)
|
||||
|
||||
|
||||
|
||||
class ProxyIMAPClient(IMAPClient):
|
||||
"""
|
||||
Sous-classe d'IMAPClient qui utilise un proxy SOCKS/HTTP.
|
||||
@@ -239,6 +352,12 @@ class ProxyIMAPClient(IMAPClient):
|
||||
"Utilisez ssl=True (port 993)."
|
||||
)
|
||||
|
||||
def login(self, username: str, password: str):
|
||||
"""Surcharge login() pour envoyer IMAP ID juste après l'authentification."""
|
||||
result = super().login(username, password)
|
||||
send_imap_id(self)
|
||||
return result
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# Fonctions utilitaires
|
||||
|
||||
Reference in New Issue
Block a user