Correcciones documentales. Creado el proyecto envio-reportes-correo
This commit is contained in:
@@ -1,3 +1,10 @@
|
|||||||
# utilidades-python
|
# utilidades-python
|
||||||
|
|
||||||
Solo un conjunto de scripts python que he escrito bajo alguna necesidad. Si alguno de estos proyectos necesita atención especial, crear un repo exclusivo para el.
|
Solo un conjunto de scripts python que he escrito bajo alguna necesidad. Si alguno de estos proyectos necesita atención especial, crear un repo exclusivo para el.
|
||||||
|
|
||||||
|
# Indice
|
||||||
|
|
||||||
|
- [renombrado-sercop](/renombrado-sercop/README.md)
|
||||||
|
- [envio-reportes-correo](/envio-reportes-correo/README.md)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
15
envio-reportes-correo/.env.example
Normal file
15
envio-reportes-correo/.env.example
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Configuraciones de Zimbra SMTP
|
||||||
|
SMTP_SERVER=mail.tudominio.com
|
||||||
|
SMTP_PORT=587
|
||||||
|
USER=tu.usuario@tudominio.com
|
||||||
|
PASS=TuContrasenaSegura
|
||||||
|
|
||||||
|
# Configuraciones del Correo
|
||||||
|
REMITENTE=tu.usuario@tudominio.com
|
||||||
|
DESTINATARIO_TO=destinatario@ejemplo.com
|
||||||
|
DESTINATARIO_CC=copia@ejemplo.com
|
||||||
|
ASUNTO_CORREO="Informe Automático - Archivo Reciente"
|
||||||
|
CUERPO_CORREO="Hola, Adjunto reporte automatico generado"
|
||||||
|
|
||||||
|
# Ruta a la carpeta de adjuntos (usa barras diagonales /)
|
||||||
|
CARPETA_ADJUNTOS=./mis_informes
|
||||||
30
envio-reportes-correo/README.md
Normal file
30
envio-reportes-correo/README.md
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Envio de Reportes
|
||||||
|
|
||||||
|
Un Script rápido para enviar el archivo mas reciente de un directorio, a una direccion de correo electronica y con copia a otra direccion.
|
||||||
|
|
||||||
|
Este script es para automatizacion y no cuenta con interfaz grafica.
|
||||||
|
|
||||||
|
# Reglas
|
||||||
|
|
||||||
|
- Dados los datos del achivo ```.env``` se elije el archivo mas reciente del directorio configurado y se envia a las direcciones configuradas.
|
||||||
|
|
||||||
|
# Modo de uso
|
||||||
|
|
||||||
|
- Ejecutar con python 3.x
|
||||||
|
- Instalar los siguientes modulos:
|
||||||
|
- smtplib
|
||||||
|
- dotenv
|
||||||
|
- renombrar o copiar el archivo [.env.example](.env.example) a ```.env```
|
||||||
|
- Llenar los datos necesarios en el archivo ```.env```
|
||||||
|
|
||||||
|
# Detalles
|
||||||
|
|
||||||
|
|||
|
||||||
|
|---|---|
|
||||||
|
|**Autor**|drk0027|
|
||||||
|
|**Fecha Creacion**|16-12-2025|
|
||||||
|
|**tags**|automatizaciones, correo-electronico|
|
||||||
|
|
||||||
|
# Observaciones
|
||||||
|
|
||||||
|
¿Funciona? si. Pero no lo pude aprovechar por restricciones que desconocía a la hora de escribir este codigo.
|
||||||
99
envio-reportes-correo/enviar-reporte.py
Normal file
99
envio-reportes-correo/enviar-reporte.py
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
import smtplib
|
||||||
|
from email.mime.multipart import MIMEMultipart
|
||||||
|
from email.mime.text import MIMEText
|
||||||
|
from email.mime.base import MIMEBase
|
||||||
|
from email import encoders
|
||||||
|
import os
|
||||||
|
import glob
|
||||||
|
from dotenv import load_dotenv # Importamos la función para cargar el .env
|
||||||
|
|
||||||
|
# Cargar las variables de entorno desde el archivo .env
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
def enviar_correo_con_adjunto_reciente(
|
||||||
|
servidor_smtp, puerto_smtp, usuario, contrasena,
|
||||||
|
remitente, destinatario_principal, destinatario_cc,
|
||||||
|
asunto, cuerpo_mensaje, carpeta_adjuntos
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Busca el archivo más reciente en una carpeta y lo envía por correo.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# 1. Encontrar el archivo más reciente en la carpeta dada
|
||||||
|
try:
|
||||||
|
ruta_completa = os.path.abspath(carpeta_adjuntos)
|
||||||
|
archivos = glob.glob(os.path.join(ruta_completa, '*'))
|
||||||
|
if not archivos:
|
||||||
|
print(f"No se encontraron archivos en la carpeta: {ruta_completa}")
|
||||||
|
return
|
||||||
|
|
||||||
|
archivos.sort(key=os.path.getmtime, reverse=True)
|
||||||
|
archivo_mas_reciente = archivos[0] # Tomamos el primer elemento (el más reciente)
|
||||||
|
nombre_archivo = os.path.basename(archivo_mas_reciente)
|
||||||
|
print(f"Archivo más reciente encontrado: {nombre_archivo}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error al buscar archivos en la carpeta: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 2. Crear el mensaje de correo
|
||||||
|
msg = MIMEMultipart()
|
||||||
|
msg['From'] = remitente
|
||||||
|
msg['To'] = destinatario_principal
|
||||||
|
msg['Cc'] = destinatario_cc
|
||||||
|
msg['Subject'] = asunto
|
||||||
|
|
||||||
|
msg.attach(MIMEText(cuerpo_mensaje, 'plain'))
|
||||||
|
|
||||||
|
# 3. Adjuntar el archivo
|
||||||
|
try:
|
||||||
|
with open(archivo_mas_reciente, "rb") as attachment:
|
||||||
|
parte = MIMEBase("application", "octet-stream")
|
||||||
|
parte.set_payload(attachment.read())
|
||||||
|
encoders.encode_base64(parte)
|
||||||
|
parte.add_header(
|
||||||
|
"Content-Disposition",
|
||||||
|
f"attachment; filename={nombre_archivo}",
|
||||||
|
)
|
||||||
|
msg.attach(parte)
|
||||||
|
except IOError as e:
|
||||||
|
print(f"Error al adjuntar el archivo {archivo_mas_reciente}: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 4. Enviar el correo usando SMTP de Zimbra
|
||||||
|
try:
|
||||||
|
servidor = smtplib.SMTP(servidor_smtp, puerto_smtp)
|
||||||
|
servidor.ehlo()
|
||||||
|
servidor.starttls()
|
||||||
|
servidor.ehlo()
|
||||||
|
|
||||||
|
servidor.login(usuario, contrasena)
|
||||||
|
|
||||||
|
destinatarios_totales = [destinatario_principal, destinatario_cc]
|
||||||
|
servidor.sendmail(remitente, destinatarios_totales, msg.as_string())
|
||||||
|
|
||||||
|
servidor.quit()
|
||||||
|
|
||||||
|
print("Correo enviado exitosamente.")
|
||||||
|
|
||||||
|
except smtplib.SMTPException as e:
|
||||||
|
print(f"Error al enviar el correo: {e}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Ocurrió un error inesperado: {e}")
|
||||||
|
|
||||||
|
# --- INVOCACIÓN DE LA FUNCIÓN USANDO VARIABLES DE ENTORNO ---
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# Obtenemos los valores del archivo .env usando os.getenv()
|
||||||
|
enviar_correo_con_adjunto_reciente(
|
||||||
|
servidor_smtp=os.getenv("SMTP_SERVER"),
|
||||||
|
puerto_smtp=int(os.getenv("SMTP_PORT")), # Convertimos el puerto a entero
|
||||||
|
usuario=os.getenv("USER"),
|
||||||
|
contrasena=os.getenv("PASS"),
|
||||||
|
remitente=os.getenv("REMITENTE"),
|
||||||
|
destinatario_principal=os.getenv("DESTINATARIO_TO"),
|
||||||
|
destinatario_cc=os.getenv("DESTINATARIO_CC"),
|
||||||
|
asunto=os.getenv("ASUNTO_CORREO"),
|
||||||
|
cuerpo_mensaje=os.getenv("CUERPO_CORREO"),
|
||||||
|
carpeta_adjuntos=os.getenv("CARPETA_ADJUNTOS")
|
||||||
|
)
|
||||||
30
renombrado-sercop/README.md
Normal file
30
renombrado-sercop/README.md
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Utilidades de renombrado
|
||||||
|
|
||||||
|
Renombrado de archivos pdf segun las reglas del SERCOP.
|
||||||
|
|
||||||
|
El Script [renombrar-archivo.py](renombrar-archivo.py) solo funciona con un archivo a la vez.
|
||||||
|
|
||||||
|
El Script [renombrar-archivos-carpeta.py](renombrar-archivos-carpeta.py) trabaja sobre todos los archivos PDF de una carpeta y crea una nueva con el prefijo sercopready_ en el mismo directorio que contiene a la carpeta de origen.
|
||||||
|
|
||||||
|
# Reglas
|
||||||
|
|
||||||
|
- Reemplazar espacios por guiones bajos
|
||||||
|
- Reemplazar eñes por 'enes'
|
||||||
|
- Eliminar caracteres especiales dejando solo letras, números y guiones bajos
|
||||||
|
- Solo archivos PDF
|
||||||
|
|
||||||
|
# Modo de uso
|
||||||
|
|
||||||
|
Super sencillo. Se asume que tiene python 3.x con tkinter para los dialogos.
|
||||||
|
|
||||||
|
# Detalles
|
||||||
|
|
||||||
|
|||
|
||||||
|
|--|--|
|
||||||
|
|**Autor**|drk0027|
|
||||||
|
|**Fecha creacion**|08-01-2025|
|
||||||
|
|**Tags**|renombrado, tkinter|
|
||||||
|
|
||||||
|
# Observaciones
|
||||||
|
|
||||||
|
¿Funciona? Si. Esta perfecto para obtener un archivo o carpeta de archivos listos para ser subidos al SERCOP segun sus reglas.
|
||||||
41
renombrado-sercop/renombrar-archivo.py
Normal file
41
renombrado-sercop/renombrar-archivo.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import os
|
||||||
|
import re
|
||||||
|
from tkinter import Tk, filedialog, messagebox
|
||||||
|
|
||||||
|
def limpiar_nombre_archivo(nombre):
|
||||||
|
# Cambiar espacios en blanco por guiones bajos
|
||||||
|
nombre = nombre.replace(' ', '_')
|
||||||
|
# Cambiar eñes por enes
|
||||||
|
nombre = nombre.replace('ñ', 'n')
|
||||||
|
# Eliminar caracteres especiales (dejando solo letras, números y guiones bajos)
|
||||||
|
nombre = re.sub(r'[^a-zA-Z0-9_]', '', nombre)
|
||||||
|
return nombre
|
||||||
|
|
||||||
|
def seleccionar_archivo():
|
||||||
|
root = Tk()
|
||||||
|
root.withdraw() # Ocultar la ventana principal de Tkinter
|
||||||
|
archivo = filedialog.askopenfilename(title="Seleccionar archivo")
|
||||||
|
|
||||||
|
if archivo:
|
||||||
|
# Obtener el directorio y el nombre del archivo
|
||||||
|
directorio = os.path.dirname(archivo)
|
||||||
|
nombre_archivo = os.path.basename(archivo)
|
||||||
|
|
||||||
|
# Limpiar el nombre del archivo
|
||||||
|
nombre_limpio = limpiar_nombre_archivo(nombre_archivo)
|
||||||
|
|
||||||
|
# Crear nuevo nombre de archivo con la misma extensión
|
||||||
|
nombre_nuevo = f"{nombre_limpio}{os.path.splitext(nombre_archivo)[1]}"
|
||||||
|
ruta_nueva = os.path.join(directorio, nombre_nuevo)
|
||||||
|
|
||||||
|
# Crear la copia del archivo
|
||||||
|
with open(archivo, 'rb') as f_original:
|
||||||
|
with open(ruta_nueva, 'wb') as f_copia:
|
||||||
|
f_copia.write(f_original.read())
|
||||||
|
|
||||||
|
messagebox.showinfo("Éxito", f"Copia creada: {ruta_nueva}")
|
||||||
|
else:
|
||||||
|
messagebox.showwarning("Advertencia", "No se seleccionó ningún archivo.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
seleccionar_archivo()
|
||||||
47
renombrado-sercop/renombrar-archivos-carpeta.py
Normal file
47
renombrado-sercop/renombrar-archivos-carpeta.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import os
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
from tkinter import Tk, filedialog
|
||||||
|
|
||||||
|
def limpiar_nombre(nombre):
|
||||||
|
# Reemplazar espacios por guiones bajos
|
||||||
|
nombre = nombre.replace(' ', '_')
|
||||||
|
# Reemplazar eñes por 'enes'
|
||||||
|
nombre = nombre.replace('ñ', 'en')
|
||||||
|
nombre = nombre.replace('Ñ', 'En')
|
||||||
|
# Eliminar caracteres especiales dejando solo letras, números y guiones bajos
|
||||||
|
nombre = re.sub(r'[^a-zA-Z0-9_\.]', '', nombre)
|
||||||
|
return nombre
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Crear ventana de Tkinter y esconderla
|
||||||
|
root = Tk()
|
||||||
|
root.withdraw()
|
||||||
|
|
||||||
|
# Seleccionar carpeta
|
||||||
|
carpeta_origen = filedialog.askdirectory(title="Selecciona la carpeta con los archivos PDF")
|
||||||
|
if not carpeta_origen:
|
||||||
|
print("No se seleccionó ninguna carpeta.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Crear carpeta destino
|
||||||
|
carpeta_destino = os.path.join(os.path.dirname(carpeta_origen), f"sercopready_{os.path.basename(carpeta_origen)}")
|
||||||
|
os.makedirs(carpeta_destino, exist_ok=True)
|
||||||
|
|
||||||
|
# Procesar archivos PDF
|
||||||
|
for filename in os.listdir(carpeta_origen):
|
||||||
|
if filename.lower().endswith('.pdf'):
|
||||||
|
# Limpiar nombre
|
||||||
|
nuevo_nombre = limpiar_nombre(filename)
|
||||||
|
# Mantener extensión .pdf
|
||||||
|
nuevo_nombre = nuevo_nombre if nuevo_nombre.lower().endswith('.pdf') else nuevo_nombre + '.pdf'
|
||||||
|
# Rutas completas
|
||||||
|
ruta_origen = os.path.join(carpeta_origen, filename)
|
||||||
|
ruta_destino = os.path.join(carpeta_destino, nuevo_nombre)
|
||||||
|
# Copiar y renombrar archivo
|
||||||
|
shutil.copy2(ruta_origen, ruta_destino)
|
||||||
|
|
||||||
|
print(f"Archivos procesados y copiados en: {carpeta_destino}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user