ahora se procesa de inicio a fin correo por correo
This commit is contained in:
1 parent
8cdd075d15
commit
603243b7e0
25 files changed
+2234
-334
No files matched your search
+114
-26
@@ -4,41 +4,52 @@ import warnings
|
||||
import base64
|
||||
import os
|
||||
from datetime import datetime, timedelta
|
||||
from config_loader import CONFIG
|
||||
|
||||
from dotenv import load_dotenv
|
||||
warnings.filterwarnings("ignore")
|
||||
|
||||
########################################################
|
||||
def get_access_token():
|
||||
# ============================================================================
|
||||
# CONFIGURACIÓN
|
||||
# ============================================================================
|
||||
|
||||
# Cargar variables de entorno desde .env
|
||||
load_dotenv(dotenv_path=".env.dev")
|
||||
|
||||
# Configuración de la API
|
||||
CLIENT_ID = os.getenv("CLIENT_ID", "")
|
||||
CLIENT_SECRET = os.getenv("CLIENT_SECRET", "")
|
||||
TENANT_ID = os.getenv("TENANT_ID", "")
|
||||
DOWNLOAD_FOLDER = os.getenv("DOWNLOAD_FOLDER","")
|
||||
VERIFY_SSL = os.getenv("VERIFI_SSL", "False").lower() == "true"
|
||||
|
||||
# ============================================================================
|
||||
def get_access_token() -> str:
|
||||
"""
|
||||
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}"
|
||||
authority = f"https://login.microsoftonline.com/{TENANT_ID}"
|
||||
|
||||
app = msal.ConfidentialClientApplication(
|
||||
CONFIG.outlook.client_id,
|
||||
CLIENT_ID,
|
||||
authority=authority,
|
||||
client_credential=CONFIG.outlook.client_secret,
|
||||
verify=CONFIG.outlook.verify_ssl
|
||||
client_credential=CLIENT_SECRET,
|
||||
verify=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})")
|
||||
if result:
|
||||
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):
|
||||
# ============================================================================
|
||||
def get_emails(user_email: str, token: str, fecha_inicio: str, fecha_fin: str) -> list[dict]:
|
||||
"""
|
||||
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.
|
||||
@@ -62,7 +73,7 @@ def get_emails(user_email, token, fecha_inicio, fecha_fin):
|
||||
"$top": 50
|
||||
}
|
||||
|
||||
url = f"https://graph.microsoft.com/v1.0/users/{user_email}/messages"
|
||||
url = f"https://graph.microsoft.com/v1.0/users/{user_email}/mailFolders/Inbox/messages"
|
||||
all_mails = []
|
||||
|
||||
while url:
|
||||
@@ -70,7 +81,7 @@ def get_emails(user_email, token, fecha_inicio, fecha_fin):
|
||||
url,
|
||||
headers=headers,
|
||||
params=params,
|
||||
verify=CONFIG.outlook.verify_ssl
|
||||
verify=VERIFY_SSL
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
@@ -100,8 +111,8 @@ def get_emails(user_email, token, fecha_inicio, fecha_fin):
|
||||
|
||||
return all_mails
|
||||
|
||||
########################################################
|
||||
def download_attachments(user_email, message_id, token, download_path):
|
||||
# ============================================================================
|
||||
def download_attachments(user_email: str, message_id: str, token: str, download_path: str) -> list[str]:
|
||||
"""
|
||||
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.
|
||||
@@ -116,7 +127,7 @@ def download_attachments(user_email, message_id, token, download_path):
|
||||
|
||||
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)
|
||||
response = requests.get(url, headers=headers, verify=VERIFY_SSL)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(f"Error al obtener adjuntos ({message_id}): {response.status_code} - {response.text}")
|
||||
@@ -137,4 +148,81 @@ def download_attachments(user_email, message_id, token, download_path):
|
||||
|
||||
return downloaded_files
|
||||
|
||||
########################################################
|
||||
# ============================================================================
|
||||
def send_email(access_token: str, from_email: str, to_recipients: list[str], subject: str, html_body: str, attachment_paths: list[str] | None = None) -> bool:
|
||||
"""
|
||||
Envía un correo electrónico con cuerpo HTML y múltiples adjuntos PDF.
|
||||
|
||||
:param access_token: Token de acceso de Microsoft Graph API.
|
||||
:param from_email: Correo electrónico del remitente (cuenta de Office 365).
|
||||
:param to_recipients: Lista de correos electrónicos de los destinatarios.
|
||||
:param subject: Asunto del correo.
|
||||
:param html_body: Contenido del correo en formato HTML.
|
||||
:param attachment_paths: Lista de rutas a los archivos PDF que se adjuntarán.
|
||||
:return: True si se envió correctamente, False en caso contrario.
|
||||
"""
|
||||
url = f"https://graph.microsoft.com/v1.0/users/{from_email}/sendMail"
|
||||
headers = {
|
||||
'Authorization': f'Bearer {access_token}',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
verify_ssl = False #True if os.getenv('OUTLOOK_VERIFY_SSL').lower() == 'true' else False
|
||||
|
||||
# Construir lista de destinatarios para Graph API
|
||||
recipients_payload = []
|
||||
for email in to_recipients:
|
||||
recipients_payload.append({
|
||||
"emailAddress": {
|
||||
"address": email
|
||||
}
|
||||
})
|
||||
|
||||
# Construir lista de adjuntos
|
||||
attachments_payload = []
|
||||
if attachment_paths:
|
||||
for path in attachment_paths:
|
||||
if os.path.exists(path):
|
||||
with open(path, "rb") as f:
|
||||
content_bytes = f.read()
|
||||
|
||||
# Codificar el contenido en Base64
|
||||
encoded_content = base64.b64encode(content_bytes).decode('utf-8')
|
||||
filename = os.path.basename(path)
|
||||
|
||||
attachments_payload.append({
|
||||
"@odata.type": "#microsoft.graph.fileAttachment",
|
||||
"name": filename,
|
||||
"contentType": "application/pdf",
|
||||
"contentBytes": encoded_content
|
||||
})
|
||||
else:
|
||||
print(f"Advertencia: El archivo no existe y no se adjuntará: {path}")
|
||||
|
||||
# Estructura del mensaje para la API
|
||||
email_data = {
|
||||
"message": {
|
||||
"subject": subject,
|
||||
"body": {
|
||||
"contentType": "HTML",
|
||||
"content": html_body
|
||||
},
|
||||
"toRecipients": recipients_payload,
|
||||
"attachments": attachments_payload
|
||||
},
|
||||
"saveToSentItems": "true"
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(url, headers=headers, json=email_data, verify=verify_ssl)
|
||||
if response.status_code == 202:
|
||||
print(f" ├── SUCCESS: Correo enviado exitosamente a: {', '.join(to_recipients)}")
|
||||
return True
|
||||
else:
|
||||
print(f" ├── ERROR: Al enviar correo: {response.status_code} - {response.text}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f" ├── ERROR: Excepcion al enviar correo: {e}")
|
||||
return False
|
||||
|
||||
# ============================================================================
|
||||
Reference in new issue
Block a user