ProyectoFinalPython/correo_server/MailClient.py

173 lines
6.5 KiB
Python

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