import smtplib import socket import imaplib import email from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from email.utils import formatdate class MailClient: def __init__(self): """ Inicializa el cliente de correo con la configuración del servidor. Atributos: server_ip (str): Dirección del servidor de correo. ports (dict): Diccionario con los puertos para SMTP e IMAP. """ self.server_ip = "s1.ieslamar.org" self.ports = { "SMTP": 25, # SMTP sin seguridad "SMTP-SUBMISSION": 587, # SMTP autenticado sin SSL "IMAP": 143 # IMAP sin SSL } def check_smtp_connection(self, port): """ Verifica si el servidor SMTP responde en un puerto específico. Args: port (int): Número del puerto a verificar. Returns: bool: `True` si la conexión es exitosa, `False` en caso contrario. """ try: with socket.create_connection((self.server_ip, port), timeout=15): return True except (socket.timeout, ConnectionRefusedError): return False def send_email(self, sender_email, sender_password, recipient, subject, body): """ Envía un correo utilizando el protocolo SMTP. Args: sender_email (str): Dirección de correo del remitente. sender_password (str): Contraseña del remitente. recipient (str): Dirección de correo del destinatario. subject (str): Asunto del correo. body (str): Cuerpo del correo. Returns: str: Mensaje indicando el resultado del envío. """ try: # Crear el mensaje de correo message = MIMEMultipart() message["From"] = sender_email message["To"] = recipient message["Date"] = formatdate(localtime=True) message["Subject"] = subject message.attach(MIMEText(body, "plain", "utf-8")) # Lista de puertos disponibles para SMTP smtp_ports = [587, 25] # Prioriza 587 y luego 25 puerto_activo = None # Verificar qué puerto está disponible for smtp_port in smtp_ports: if self.check_smtp_connection(smtp_port): puerto_activo = smtp_port break if not puerto_activo: return "Error: No se pudo conectar con el servidor SMTP en los puertos (587, 25)." try: # Conectar al servidor SMTP with smtplib.SMTP(self.server_ip, puerto_activo, timeout=15) as server: if puerto_activo == 587: server.starttls() # Activar TLS si se usa el puerto 587 server.login(sender_email, sender_password) # Autenticación server.sendmail(sender_email, recipient, message.as_string()) # Enviar el correo return f"Correo enviado correctamente a {recipient} usando el puerto {puerto_activo}" except smtplib.SMTPAuthenticationError: return "Error: Autenticación fallida. Verifica tu correo y contraseña." except smtplib.SMTPConnectError: return f"Error: No se pudo conectar al servidor en el puerto {puerto_activo}." except smtplib.SMTPException as e: return f"Error SMTP en el puerto {puerto_activo}: {str(e)}" except Exception as e: return f"Error inesperado al enviar el correo: {str(e)}" def fetch_emails(self, email_address, password): """ Recupera los correos electrónicos de la bandeja de entrada usando IMAP. Args: email_address (str): Dirección de correo del usuario. password (str): Contraseña del usuario. Returns: list: Lista de tuplas con los correos (`email_id`, `subject`, `sender`). str: Mensaje de error si la autenticación falla. """ try: # Conectar al servidor IMAP mail = imaplib.IMAP4(self.server_ip, self.ports["IMAP"]) mail.login(email_address, password) mail.select("inbox") # Buscar todos los correos en la bandeja de entrada status, messages = mail.search(None, "ALL") email_ids = messages[0].split() emails = [] # Obtener los últimos 10 correos for email_id in email_ids[-10:]: status, msg_data = mail.fetch(email_id, "(RFC822)") for response_part in msg_data: if isinstance(response_part, tuple): msg = email.message_from_bytes(response_part[1]) # Decodificar el asunto del correo subject, encoding = email.header.decode_header(msg["Subject"])[0] if isinstance(subject, bytes): subject = subject.decode(encoding or "utf-8") sender = msg.get("From") emails.append((email_id, subject, sender)) mail.logout() return emails except imaplib.IMAP4.error: return "Error: Fallo de autenticación en IMAP. Verifica tu correo y contraseña." except Exception as e: return f"Error al recibir los correos: {str(e)}" def delete_email(self, email_address, password, email_id): """ Elimina un correo electrónico utilizando IMAP. Args: email_address (str): Dirección de correo del usuario. password (str): Contraseña del usuario. email_id (bytes): ID del correo a eliminar. Returns: str: Mensaje indicando si la eliminación fue exitosa o no. """ try: # Conectar al servidor IMAP mail = imaplib.IMAP4(self.server_ip, self.ports["IMAP"]) mail.login(email_address, password) mail.select("inbox") # Marcar el correo como eliminado mail.store(email_id, "+FLAGS", "\\Deleted") mail.expunge() # Eliminar definitivamente los correos marcados mail.logout() return f"Correo con ID {email_id} eliminado correctamente." except imaplib.IMAP4.error: return "Error: Fallo de autenticación en IMAP. Verifica tu correo y contraseña." except Exception as e: return f"Error al eliminar el correo: {str(e)}"