This commit is contained in:
parent
dc9e679298
commit
c4b0cca277
125
Main.py
125
Main.py
|
@ -1,117 +1,10 @@
|
|||
import poplib
|
||||
import email
|
||||
import pymongo
|
||||
from email.utils import parsedate_to_datetime
|
||||
import tkinter as tk
|
||||
from controlador import CorreoControlador
|
||||
from vista import CorreoVista
|
||||
|
||||
# Configuración del servidor POP3 (Sin SSL)
|
||||
POP3_SERVER = "192.168.120.103"
|
||||
POP3_PORT = 110 # Puerto POP3 estándar sin SSL
|
||||
EMAIL_USER = "kevin@psp.ieslamar.org"
|
||||
EMAIL_PASS = "1234"
|
||||
|
||||
# Configuración de la base de datos MongoDB
|
||||
MONGO_CLIENT = "mongodb://localhost:27017/"
|
||||
DB_NAME = "correo_db"
|
||||
COLLECTION_NAME = "correos"
|
||||
|
||||
# Conectar a MongoDB
|
||||
client = pymongo.MongoClient(MONGO_CLIENT)
|
||||
db = client[DB_NAME]
|
||||
collection = db[COLLECTION_NAME]
|
||||
|
||||
def correo_existe(remitente, asunto, fecha):
|
||||
""" Verifica si un correo ya existe en la base de datos. """
|
||||
return collection.find_one({"remitente": remitente, "asunto": asunto, "fecha": fecha}) is not None
|
||||
|
||||
def guardar_correo(remitente, asunto, fecha, cuerpo):
|
||||
""" Guarda un correo en la base de datos si no existe. """
|
||||
if correo_existe(remitente, asunto, fecha):
|
||||
print("⚠️ Correo ya guardado, se omite.")
|
||||
return
|
||||
|
||||
correo = {
|
||||
"remitente": remitente,
|
||||
"asunto": asunto,
|
||||
"fecha": fecha,
|
||||
"cuerpo": cuerpo
|
||||
}
|
||||
collection.insert_one(correo)
|
||||
print("✅ Correo guardado en la base de datos.")
|
||||
|
||||
def descargar_correos():
|
||||
""" Descarga correos desde el servidor y solo guarda los nuevos. """
|
||||
try:
|
||||
print("📡 Conectando al servidor POP3 para descargar correos...\n")
|
||||
mail = poplib.POP3(POP3_SERVER, POP3_PORT)
|
||||
mail.user(EMAIL_USER)
|
||||
mail.pass_(EMAIL_PASS)
|
||||
|
||||
num_mensajes = len(mail.list()[1])
|
||||
print(f"📩 Se encontraron {num_mensajes} correos en la bandeja de entrada.\n")
|
||||
|
||||
for i in range(1, num_mensajes + 1):
|
||||
response, lines, octets = mail.retr(i)
|
||||
raw_email = b"\n".join(lines)
|
||||
msg = email.message_from_bytes(raw_email)
|
||||
|
||||
remitente = msg["From"]
|
||||
asunto = msg["Subject"]
|
||||
fecha = msg["Date"]
|
||||
|
||||
if fecha:
|
||||
try:
|
||||
fecha = parsedate_to_datetime(fecha).strftime("%Y-%m-%d %H:%M:%S")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
cuerpo = ""
|
||||
if msg.is_multipart():
|
||||
for part in msg.walk():
|
||||
if part.get_content_type() == "text/plain":
|
||||
cuerpo = part.get_payload(decode=True).decode(errors="ignore")
|
||||
break
|
||||
else:
|
||||
cuerpo = msg.get_payload(decode=True).decode(errors="ignore")
|
||||
|
||||
guardar_correo(remitente, asunto, fecha, cuerpo.strip())
|
||||
|
||||
mail.quit()
|
||||
print("✅ Descarga de correos completada.\n")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error al descargar correos: {e}")
|
||||
|
||||
def mostrar_correos():
|
||||
""" Muestra todos los correos almacenados en MongoDB. """
|
||||
print("📂 Mostrando correos almacenados en la base de datos...\n")
|
||||
correos = collection.find()
|
||||
|
||||
for correo in correos:
|
||||
print(f"📅 Fecha: {correo['fecha']}")
|
||||
print(f"🔹 Remitente: {correo['remitente']}")
|
||||
print(f"📌 Asunto: {correo['asunto']}")
|
||||
print(f"📝 Mensaje:\n{correo['cuerpo']}")
|
||||
print("-" * 40)
|
||||
|
||||
def menu():
|
||||
""" Menú interactivo para ejecutar las opciones del programa. """
|
||||
while True:
|
||||
print("\n📬 MENÚ:")
|
||||
print("1. Descargar correos nuevos")
|
||||
print("2. Mostrar correos almacenados")
|
||||
print("3. Salir")
|
||||
|
||||
opcion = input("Seleccione una opción: ")
|
||||
|
||||
if opcion == "1":
|
||||
descargar_correos()
|
||||
elif opcion == "2":
|
||||
mostrar_correos()
|
||||
elif opcion == "3":
|
||||
print("👋 Saliendo...")
|
||||
break
|
||||
else:
|
||||
print("❌ Opción no válida, intente de nuevo.")
|
||||
|
||||
# Ejecutar el menú interactivo
|
||||
menu()
|
||||
if __name__ == "__main__":
|
||||
root = tk.Tk()
|
||||
controlador = CorreoControlador()
|
||||
vista = CorreoVista(root, controlador)
|
||||
controlador.vista = vista
|
||||
root.mainloop()
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,17 @@
|
|||
from modelo import CorreoModelo
|
||||
from tkinter import messagebox
|
||||
|
||||
class CorreoControlador:
|
||||
def __init__(self):
|
||||
self.modelo = CorreoModelo()
|
||||
|
||||
def descargar_correos(self):
|
||||
resultado = self.modelo.descargar_correos()
|
||||
if resultado is True:
|
||||
messagebox.showinfo("Éxito", "Correos descargados correctamente")
|
||||
else:
|
||||
messagebox.showerror("Error", f"Error al descargar correos: {resultado}")
|
||||
self.vista.actualizar_lista()
|
||||
|
||||
def obtener_correos(self):
|
||||
return self.modelo.obtener_correos()
|
|
@ -0,0 +1,110 @@
|
|||
import poplib
|
||||
import email
|
||||
import pymongo
|
||||
from email.utils import parsedate_to_datetime
|
||||
|
||||
class CorreoModelo:
|
||||
POP3_SERVER = "192.168.120.103"
|
||||
POP3_PORT = 110
|
||||
EMAIL_USER = "kevin@psp.ieslamar.org"
|
||||
EMAIL_PASS = "1234"
|
||||
|
||||
MONGO_CLIENT = "mongodb://localhost:27017/"
|
||||
DB_NAME = "correo_db"
|
||||
COLLECTION_NAME = "correos"
|
||||
|
||||
def __init__(self):
|
||||
self.client = pymongo.MongoClient(self.MONGO_CLIENT)
|
||||
self.db = self.client[self.DB_NAME]
|
||||
self.collection = self.db[self.COLLECTION_NAME]
|
||||
|
||||
def correo_existe(self, remitente, asunto, fecha):
|
||||
return self.collection.find_one({"remitente": remitente, "asunto": asunto, "fecha": fecha}) is not None
|
||||
|
||||
def guardar_correo(self, remitente, asunto, fecha, cuerpo):
|
||||
if self.correo_existe(remitente, asunto, fecha):
|
||||
return
|
||||
correo = {"remitente": remitente, "asunto": asunto, "fecha": fecha, "cuerpo": cuerpo}
|
||||
self.collection.insert_one(correo)
|
||||
|
||||
def descargar_correos(self):
|
||||
try:
|
||||
mail = poplib.POP3(self.POP3_SERVER, self.POP3_PORT)
|
||||
mail.user(self.EMAIL_USER)
|
||||
mail.pass_(self.EMAIL_PASS)
|
||||
|
||||
num_mensajes = len(mail.list()[1])
|
||||
mensajes_nuevos = False
|
||||
|
||||
for i in range(1, num_mensajes + 1):
|
||||
response, lines, octets = mail.retr(i)
|
||||
raw_email = b"\n".join(lines)
|
||||
msg = email.message_from_bytes(raw_email)
|
||||
|
||||
remitente = msg["From"]
|
||||
asunto = msg["Subject"]
|
||||
fecha = msg["Date"]
|
||||
|
||||
if fecha:
|
||||
try:
|
||||
fecha = parsedate_to_datetime(fecha).strftime("%Y-%m-%d %H:%M:%S")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
cuerpo = ""
|
||||
if msg.is_multipart():
|
||||
for part in msg.walk():
|
||||
if part.get_content_type() == "text/plain":
|
||||
cuerpo = part.get_payload(decode=True).decode(errors="ignore")
|
||||
break
|
||||
else:
|
||||
cuerpo = msg.get_payload(decode=True).decode(errors="ignore")
|
||||
|
||||
if not self.correo_existe(remitente, asunto, fecha):
|
||||
self.guardar_correo(remitente, asunto, fecha, cuerpo.strip())
|
||||
mensajes_nuevos = True
|
||||
|
||||
mail.quit()
|
||||
return True
|
||||
except Exception as e:
|
||||
return str(e)
|
||||
|
||||
def obtener_correos(self):
|
||||
return list(self.collection.find())
|
||||
|
||||
def hay_mensajes_nuevos(self):
|
||||
"""
|
||||
Verifica si hay correos nuevos en el servidor POP3 que no estén en la base de datos.
|
||||
"""
|
||||
try:
|
||||
mail = poplib.POP3(self.POP3_SERVER, self.POP3_PORT)
|
||||
mail.user(self.EMAIL_USER)
|
||||
mail.pass_(self.EMAIL_PASS)
|
||||
|
||||
num_mensajes = len(mail.list()[1])
|
||||
|
||||
for i in range(1, num_mensajes + 1):
|
||||
response, lines, octets = mail.retr(i)
|
||||
raw_email = b"\n".join(lines)
|
||||
msg = email.message_from_bytes(raw_email)
|
||||
|
||||
remitente = msg["From"]
|
||||
asunto = msg["Subject"]
|
||||
fecha = msg["Date"]
|
||||
|
||||
if fecha:
|
||||
try:
|
||||
fecha = parsedate_to_datetime(fecha).strftime("%Y-%m-%d %H:%M:%S")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if not self.correo_existe(remitente, asunto, fecha):
|
||||
mail.quit()
|
||||
return True # Hay al menos un mensaje nuevo
|
||||
|
||||
mail.quit()
|
||||
return False # No hay mensajes nuevos
|
||||
|
||||
except Exception as e:
|
||||
return False # En caso de error, asumimos que no hay nuevos mensajes
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
import tkinter as tk
|
||||
from tkinter import ttk, messagebox, scrolledtext
|
||||
from controlador import CorreoControlador
|
||||
import threading
|
||||
import time
|
||||
|
||||
class CorreoVista:
|
||||
def __init__(self, root, controlador):
|
||||
self.root = root
|
||||
self.controlador = controlador
|
||||
self.root.title("📬 Gestor de Correos")
|
||||
self.root.geometry("900x600")
|
||||
self.root.configure(bg="#f4f4f4")
|
||||
|
||||
# Frame del menú izquierdo
|
||||
self.menu_frame = tk.Frame(self.root, bg="#333333", width=200)
|
||||
self.menu_frame.pack(side=tk.LEFT, fill=tk.Y)
|
||||
|
||||
# Botones del menú
|
||||
self.btn_f1 = tk.Button(self.menu_frame, text="📋 Listado", font=("Arial", 12), bg="#555555", fg="white", relief=tk.FLAT, command=self.mostrar_frame_f1)
|
||||
self.btn_f1.pack(fill=tk.X, pady=5, padx=5)
|
||||
|
||||
self.btn_f2 = tk.Button(self.menu_frame, text="⚙️ Configuración", font=("Arial", 12), bg="#555555", fg="white", relief=tk.FLAT, command=self.mostrar_frame_f2)
|
||||
self.btn_f2.pack(fill=tk.X, pady=5, padx=5)
|
||||
|
||||
# Frame principal derecho
|
||||
self.main_frame = tk.Frame(self.root, bg="#f4f4f4")
|
||||
self.main_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
|
||||
|
||||
# Barra inferior
|
||||
self.footer_frame = tk.Frame(self.root, bg="#1E90FF", height=30)
|
||||
self.footer_frame.place(relx=0, rely=1.0, relwidth=1, anchor="sw")
|
||||
|
||||
self.footer_label = tk.Label(self.footer_frame, text="Gestor de Correos - 2025", bg="#1E90FF", fg="white", font=("Arial", 10))
|
||||
self.footer_label.pack(side=tk.RIGHT, padx=10)
|
||||
|
||||
# Frames individuales para cada sección
|
||||
self.frame_f1 = tk.Frame(self.main_frame, bg="#f4f4f4")
|
||||
self.frame_f2 = tk.Frame(self.main_frame, bg="#f4f4f4")
|
||||
|
||||
self.crear_frame_f1()
|
||||
self.crear_frame_f2()
|
||||
|
||||
# Mostrar el primer frame por defecto
|
||||
self.frame_f1.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
# Iniciar el hilo de actualización de la barra
|
||||
self.ejecutar_hilo_actualizacion_barra()
|
||||
|
||||
def mostrar_frame_f1(self):
|
||||
self.frame_f2.pack_forget()
|
||||
self.frame_f1.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
def mostrar_frame_f2(self):
|
||||
self.frame_f1.pack_forget()
|
||||
self.frame_f2.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
def crear_frame_f1(self):
|
||||
frame_top = tk.Frame(self.frame_f1, bg="#f4f4f4")
|
||||
frame_top.pack(pady=10, fill=tk.X)
|
||||
|
||||
btn_descargar = ttk.Button(frame_top, text="📥 Descargar Correos", command=self.controlador.descargar_correos)
|
||||
btn_descargar.pack(side=tk.LEFT, padx=10)
|
||||
|
||||
btn_mostrar = ttk.Button(frame_top, text="🔍 Mostrar Correo", command=self.mostrar_correo)
|
||||
btn_mostrar.pack(side=tk.LEFT, padx=10)
|
||||
|
||||
frame_list = tk.Frame(self.frame_f1, bg="#ffffff", bd=2, relief=tk.GROOVE)
|
||||
frame_list.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
|
||||
|
||||
self.tree = ttk.Treeview(frame_list, columns=("Remitente", "Asunto", "Fecha", "Cuerpo"), show="headings")
|
||||
self.tree.heading("Remitente", text="✉️ Remitente")
|
||||
self.tree.heading("Asunto", text="📌 Asunto")
|
||||
self.tree.heading("Fecha", text="📅 Fecha")
|
||||
self.tree.heading("Cuerpo", text="📝 Cuerpo")
|
||||
self.tree.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
frame_details = tk.Frame(self.frame_f1, bg="#ffffff", bd=2, relief=tk.GROOVE)
|
||||
frame_details.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
|
||||
|
||||
self.detalle_text = scrolledtext.ScrolledText(frame_details, wrap=tk.WORD, height=10, font=("Arial", 10))
|
||||
self.detalle_text.pack(fill=tk.BOTH, expand=True)
|
||||
|
||||
def crear_frame_f2(self):
|
||||
label_config = tk.Label(self.frame_f2, text="⚙️ Configuración", font=("Arial", 16), bg="#f4f4f4")
|
||||
label_config.pack(pady=20)
|
||||
|
||||
def mostrar_correo(self):
|
||||
seleccionado = self.tree.selection()
|
||||
if not seleccionado:
|
||||
messagebox.showwarning("⚠️ Advertencia", "Seleccione un correo")
|
||||
return
|
||||
|
||||
correo_id = seleccionado[0]
|
||||
correo = self.tree.item(correo_id, "values")
|
||||
|
||||
self.detalle_text.delete("1.0", tk.END)
|
||||
self.detalle_text.insert(tk.END, f"📧 Remitente: {correo[0]}\n")
|
||||
self.detalle_text.insert(tk.END, f"📌 Asunto: {correo[1]}\n")
|
||||
self.detalle_text.insert(tk.END, f"📅 Fecha: {correo[2]}\n\n")
|
||||
self.detalle_text.insert(tk.END, f"📝 Mensaje:\n{correo[3]}")
|
||||
|
||||
def actualizar_lista(self):
|
||||
self.tree.delete(*self.tree.get_children())
|
||||
for correo in self.controlador.obtener_correos():
|
||||
self.tree.insert("", "end", values=(correo["remitente"], correo["asunto"], correo["fecha"], correo["cuerpo"]))
|
||||
|
||||
def ejecutar_hilo_actualizacion_barra(self):
|
||||
""" Inicia un hilo para actualizar el color de la barra inferior cada 5 segundos. """
|
||||
hilo = threading.Thread(target=self.actualizar_barra_periodicamente, daemon=True)
|
||||
hilo.start()
|
||||
|
||||
def actualizar_barra_periodicamente(self):
|
||||
""" Cambia el color de la barra inferior cada 5 segundos según si hay nuevos correos. """
|
||||
while True:
|
||||
hay_nuevos = self.controlador.modelo.hay_mensajes_nuevos()
|
||||
|
||||
# Cambiar color de la barra en el hilo principal de Tkinter
|
||||
self.root.after(0, self.cambiar_color_barra, "#FF0000" if hay_nuevos else "#1E90FF")
|
||||
|
||||
time.sleep(5) # Esperar 5 segundos antes de verificar nuevamente
|
||||
|
||||
def cambiar_color_barra(self, color):
|
||||
""" Cambia el color de la barra inferior. """
|
||||
self.footer_frame.configure(bg=color)
|
||||
self.footer_label.configure(bg=color)
|
Loading…
Reference in New Issue