buenas hoy vengo por que es escribiendo un programa de descargas y no funciona también necesito un código para que se ejecute en segundo plano para para poder pasar el examen de técnico en programación muchas gracias amigos
import os
import sys
import logging
import smtplib
import zipfile
from pathlib import Path
from email.message import EmailMessage
from datetime import datetime
# ------------------------------------------------------------------
# LOGGING
# ------------------------------------------------------------------
# Cuando el script corre automáticamente al iniciar Windows, no hay
# consola visible donde ver los print(). Por eso todo queda registrado
# también en un archivo de log dentro de la carpeta del usuario.
LOG_PATH = Path.home() / "backup_correo_log.txt"
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[
logging.FileHandler(LOG_PATH, encoding="utf-8"),
logging.StreamHandler(sys.stdout),
],
)
logger = logging.getLogger(__name__)
# ------------------------------------------------------------------
# CONFIGURACIÓN
# ------------------------------------------------------------------
# Credenciales: primero intenta leer de variables de entorno.
# Si prefieres escribirlas aquí directamente, reemplaza los os.environ.get(...)
EMAIL_ORIGEN = os.environ.get("GMAIL_USER", "
[email protected]")
APP_PASSWORD = os.environ.get("GMAIL_APP_PASSWORD", "")
EMAIL_DESTINO = os.environ.get("EMAIL_DESTINO", "
[email protected]")
SMTP_SERVIDOR = "smtp.gmail.com"
SMTP_PUERTO = 587
# Carpetas típicas del usuario en Windows
CARPETA_USUARIO = Path.home()
CARPETAS_A_RESPALDAR = {
"Descargas": CARPETA_USUARIO / "descargas",
"Videos": CARPETA_USUARIO / "tutoriales",
"Imagenes": CARPETA_USUARIO / "musica",
"Documentos": CARPETA_USUARIO / "videos",
"Musica": CARPETA_USUARIO / "Musica"
}
# Carpeta donde se guardarán temporalmente los .zip generados
CARPETA_SALIDA_ZIPS = CARPETA_USUARIO / "backup_zips_temp"
# Límite seguro de adjunto. Gmail permite ~25 MB, pero el correo
# codifica en base64 (~+37% de tamaño), así que dejamos margen real.
LIMITE_ADJUNTO_MB = 18
LIMITE_ADJUNTO_BYTES = LIMITE_ADJUNTO_MB * 1024 * 1024
# ------------------------------------------------------------------
# FUNCIONES
# ------------------------------------------------------------------
def comprimir_carpeta(nombre: str, ruta: Path, carpeta_salida: Path) -> Path | None:
"""Comprime el contenido de 'ruta' en un .zip dentro de carpeta_salida.
Devuelve la ruta del zip generado, o None si la carpeta no existe/está vacía."""
if not ruta.exists():
logger.warning(f" La carpeta '{nombre}' no existe en {ruta}, se omite.")
return None
archivos = list(ruta.rglob("*"))
if not archivos:
logger.warning(f" La carpeta '{nombre}' está vacía, se omite.")
return None
carpeta_salida.mkdir(exist_ok=True)
zip_path = carpeta_salida / f"{nombre}.zip"
logger.info(f" Comprimiendo '{nombre}' ({len(archivos)} elementos)...")
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
for archivo in archivos:
if archivo.is_file():
zf.write(archivo, arcname=archivo.relative_to(ruta.parent))
tamano_mb = zip_path.stat().st_size / (1024 * 1024)
logger.info(f" '{nombre}' comprimido -> {zip_path.name} ({tamano_mb:.1f} MB)")
return zip_path
def enviar_correo(adjuntos_ok: list[Path], omitidos: list[tuple[str, Path, float]]):
"""Envía un correo con los adjuntos que sí caben y menciona
en el cuerpo los que se omitieron por tamaño."""
msg = EmailMessage()
msg["Subject"] = f"Backup de carpetas - {datetime.now().strftime('%Y-%m-%d %H:%M')}"
msg["From"] = EMAIL_ORIGEN
msg["To"] = EMAIL_DESTINO
cuerpo = "Hola,\n\nAdjunto el backup comprimido de las siguientes carpetas:\n"
if adjuntos_ok:
for zp in adjuntos_ok:
cuerpo += f" - {zp.name}\n"
else:
cuerpo += " (ninguna carpeta pudo enviarse por correo)\n"
if omitidos:
cuerpo += (
f"\nLas siguientes carpetas NO se adjuntaron por superar el límite "
f"de {LIMITE_ADJUNTO_MB} MB permitido para el correo. "
f"Quedaron guardadas en tu equipo en: {CARPETA_SALIDA_ZIPS}\n\n"
)
for nombre, ruta_zip, tamano_mb in omitidos:
cuerpo += f" - {nombre}: {ruta_zip.name} ({tamano_mb:.1f} MB)\n"
cuerpo += (
"\nSugerencia: súbelas a Google Drive/OneDrive y comparte el enlace, "
"o envíalas por WeTransfer.\n"
)
cuerpo += "\nSaludos."
msg.set_content(cuerpo)
for zp in adjuntos_ok:
with open(zp, "rb") as f:
datos = f.read()
msg.add_attachment(
datos,
maintype="application",
subtype="zip",
filename=zp.name,
)
logger.info(" Conectando al servidor SMTP de Gmail...")
with smtplib.SMTP(SMTP_SERVIDOR, SMTP_PUERTO) as servidor:
servidor.starttls()
servidor.login(EMAIL_ORIGEN, APP_PASSWORD)
servidor.send_message(msg)
logger.info(" Correo enviado correctamente.")
def main():
if "PON_AQUI" in APP_PASSWORD or "tu_correo" in EMAIL_ORIGEN:
logger.error(
"Debes configurar EMAIL_ORIGEN y APP_PASSWORD "
"(variables de entorno o directamente en el script) antes de ejecutar."
)
return
zips_generados = []
for nombre, ruta in CARPETAS_A_RESPALDAR.items():
zip_path = comprimir_carpeta(nombre, ruta, CARPETA_SALIDA_ZIPS)
if zip_path:
zips_generados.append((nombre, zip_path))
if not zips_generados:
logger.warning(" No se encontró contenido en ninguna carpeta. No se enviará correo.")
return
adjuntos_ok = []
omitidos = []
for nombre, zip_path in zips_generados:
tamano_bytes = zip_path.stat().st_size
tamano_mb = tamano_bytes / (1024 * 1024)
if tamano_bytes <= LIMITE_ADJUNTO_BYTES:
adjuntos_ok.append(zip_path)
else:
omitidos.append((nombre, zip_path, tamano_mb))
logger.warning(
f"'{nombre}' pesa {tamano_mb:.1f} MB, supera el límite "
f"de {LIMITE_ADJUNTO_MB} MB. No se adjuntará."
)
enviar_correo(adjuntos_ok, omitidos)
if __name__ == "__main__":
try:
logger.info("=== Inicio de ejecución del backup ===")
main()
logger.info("=== Fin de ejecución del backup ===")
except Exception:
logger.exception("Fallo inesperado durante la ejecución del backup.")