165 lines
5.8 KiB
Python
165 lines
5.8 KiB
Python
import msal
|
|
import requests
|
|
import warnings
|
|
import base64
|
|
import os
|
|
from datetime import datetime, timedelta
|
|
from config_loader import CONFIG
|
|
|
|
warnings.filterwarnings("ignore")
|
|
|
|
########################################################
|
|
def get_access_token():
|
|
"""
|
|
Obtiene un token de acceso de Microsoft Graph usando las credenciales
|
|
configuradas en config.json (Client ID, Client Secret y Tenant ID).
|
|
"""
|
|
if not CONFIG or not CONFIG.outlook:
|
|
raise ValueError("La configuración de Outlook no está cargada correctamente.")
|
|
|
|
authority = f"https://login.microsoftonline.com/{CONFIG.outlook.tenant_id}"
|
|
|
|
app = msal.ConfidentialClientApplication(
|
|
CONFIG.outlook.client_id,
|
|
authority=authority,
|
|
client_credential=CONFIG.outlook.client_secret,
|
|
verify=CONFIG.outlook.verify_ssl
|
|
)
|
|
|
|
scopes = ["https://graph.microsoft.com/.default"]
|
|
result = app.acquire_token_for_client(scopes=scopes)
|
|
|
|
if "access_token" in result:
|
|
return result["access_token"]
|
|
else:
|
|
error = result.get("error")
|
|
error_description = result.get("error_description")
|
|
correlation_id = result.get("correlation_id")
|
|
raise Exception(f"Error al obtener token: {error} - {error_description} (ID: {correlation_id})")
|
|
|
|
########################################################
|
|
def get_emails(user_email, token, fecha_inicio, fecha_fin):
|
|
"""
|
|
Obtiene los correos de una cuenta específica en un rango de fechas.
|
|
Retorna una lista de JSON con: id, fecha (ajustada -5h), sender, subject y has_attach.
|
|
"""
|
|
headers = {
|
|
"Authorization": f"Bearer {token}",
|
|
"Content-Type": "application/json"
|
|
}
|
|
|
|
dt_inicio_utc = datetime.strptime(fecha_inicio, "%Y-%m-%d") + timedelta(hours=5)
|
|
dt_fin_utc = datetime.strptime(fecha_fin, "%Y-%m-%d") + timedelta(days=1, hours=5)
|
|
|
|
filter_query = (
|
|
f"receivedDateTime ge {dt_inicio_utc.strftime('%Y-%m-%dT%H:%M:%SZ')} and "
|
|
f"receivedDateTime lt {dt_fin_utc.strftime('%Y-%m-%dT%H:%M:%SZ')}"
|
|
)
|
|
|
|
params = {
|
|
"$filter": filter_query,
|
|
"$select": "id,receivedDateTime,hasAttachments,subject,from",
|
|
"$top": 50
|
|
}
|
|
|
|
url = f"https://graph.microsoft.com/v1.0/users/{user_email}/messages"
|
|
all_mails = []
|
|
|
|
while url:
|
|
response = requests.get(
|
|
url,
|
|
headers=headers,
|
|
params=params,
|
|
verify=CONFIG.outlook.verify_ssl
|
|
)
|
|
|
|
if response.status_code != 200:
|
|
raise Exception(f"Error Graph API ({user_email}): {response.status_code} - {response.text}")
|
|
|
|
data = response.json()
|
|
messages = data.get("value", [])
|
|
|
|
for msg in messages:
|
|
utc_str = msg.get("receivedDateTime")
|
|
dt_utc = datetime.fromisoformat(utc_str.replace("Z", "+00:00"))
|
|
dt_local = dt_utc - timedelta(hours=5)
|
|
|
|
from_obj = msg.get("from", {})
|
|
sender = from_obj.get("emailAddress", {}).get("address", "Desconocido")
|
|
|
|
all_mails.append({
|
|
"id": msg.get("id"),
|
|
"fecha": dt_local.strftime("%Y-%m-%d %H:%M:%S"),
|
|
"sender": sender,
|
|
"subject": msg.get("subject", ""),
|
|
"has_attach": msg.get("hasAttachments")
|
|
})
|
|
|
|
url = data.get("@odata.nextLink")
|
|
params = None
|
|
|
|
return all_mails
|
|
|
|
########################################################
|
|
def download_attachments(user_email, message_id, token, download_path):
|
|
"""
|
|
Descarga los adjuntos de un mensaje específico y los guarda en la ruta indicada.
|
|
Retorna una lista con los nombres de los archivos descargados.
|
|
"""
|
|
if not os.path.exists(download_path):
|
|
os.makedirs(download_path, exist_ok=True)
|
|
|
|
headers = {
|
|
"Authorization": f"Bearer {token}",
|
|
"Content-Type": "application/json"
|
|
}
|
|
|
|
url = f"https://graph.microsoft.com/v1.0/users/{user_email}/messages/{message_id}/attachments"
|
|
|
|
response = requests.get(url, headers=headers, verify=CONFIG.outlook.verify_ssl)
|
|
|
|
if response.status_code != 200:
|
|
raise Exception(f"Error al obtener adjuntos ({message_id}): {response.status_code} - {response.text}")
|
|
|
|
attachments = response.json().get("value", [])
|
|
downloaded_files = []
|
|
|
|
for attachment in attachments:
|
|
if attachment.get("@odata.type") == "#microsoft.graph.fileAttachment":
|
|
file_name = attachment.get("name")
|
|
content_bytes = attachment.get("contentBytes")
|
|
|
|
if content_bytes:
|
|
file_path = os.path.join(download_path, file_name)
|
|
with open(file_path, "wb") as f:
|
|
f.write(base64.b64decode(content_bytes))
|
|
downloaded_files.append(file_name)
|
|
|
|
return downloaded_files
|
|
|
|
########################################################
|
|
if __name__ == "__main__":
|
|
try:
|
|
print("Intentando obtener token de acceso...")
|
|
token = get_access_token()
|
|
print("✅ Token obtenido exitosamente.")
|
|
|
|
if CONFIG.mails:
|
|
test_email = CONFIG.mails[0].email
|
|
hoy = datetime.now()
|
|
ayer = hoy - timedelta(days=1)
|
|
f_inicio = ayer.strftime("%Y-%m-%d")
|
|
f_fin = hoy.strftime("%Y-%m-%d")
|
|
|
|
print(f"\nBuscando correos para {test_email}...")
|
|
emails = get_emails(test_email, token, f_inicio, f_fin)
|
|
print(f"✅ Se encontraron {len(emails)} correos.")
|
|
|
|
for e in emails:
|
|
if e['has_attach']:
|
|
print(f"Probando descarga para correo ID: {e['id'][:10]}...")
|
|
archivos = download_attachments(test_email, e['id'], token, "./test_download")
|
|
print(f"Descargados: {archivos}")
|
|
break
|
|
except Exception as e:
|
|
print(f"❌ Error: {e}") |