Files
descarga_adjuntos_correos_cpe/outlook_utilities.py
T

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}")