Automatizar correos electrónicos con Python permite enviar informes, alertas, confirmaciones y recordatorios sin repetir tareas manuales. La biblioteca estándar incluye smtplib para comunicarse con un servidor SMTP y el paquete email para construir mensajes con texto, HTML y archivos adjuntos.
En esta guía crearás una solución reutilizable con credenciales en variables de entorno, destinatarios múltiples, adjuntos, manejo de errores y una estructura preparada para programarse. Antes de instalar herramientas adicionales, revisa cómo crear entornos virtuales con Python.
Cómo funciona el envío de correo
Tu programa no entrega directamente el mensaje al destinatario. Se conecta a un servidor SMTP autorizado, inicia una sesión segura, se autentica y solicita el envío. Cada proveedor define host, puerto, requisitos de TLS y métodos de autenticación.
La documentación oficial de smtplib describe las conexiones SMTP, SSL, STARTTLS y las excepciones disponibles.
Guardar credenciales de forma segura
No escribas contraseñas ni tokens dentro del archivo Python. Utiliza variables de entorno:
export SMTP_USER="[email protected]"
export SMTP_PASSWORD="clave-de-aplicacion"import os
usuario = os.getenv("SMTP_USER")
contrasena = os.getenv("SMTP_PASSWORD")
if not usuario or not contrasena:
raise RuntimeError("Faltan las credenciales SMTP")La guía para leer variables de entorno en Python explica archivos .env, validación y despliegue.
Crear un mensaje de texto
from email.message import EmailMessage
mensaje = EmailMessage()
mensaje["From"] = "[email protected]"
mensaje["To"] = "[email protected]"
mensaje["Subject"] = "Informe semanal"
mensaje.set_content(
"Hola,\n\nEl informe semanal ya está disponible.\n"
)EmailMessage organiza cabeceras, cuerpos alternativos y adjuntos. Consulta la referencia oficial de email.message.
Enviar con STARTTLS
import os
import smtplib
from email.message import EmailMessage
HOST = "smtp.example.com"
PUERTO = 587
usuario = os.environ["SMTP_USER"]
contrasena = os.environ["SMTP_PASSWORD"]
mensaje = EmailMessage()
mensaje["From"] = usuario
mensaje["To"] = "[email protected]"
mensaje["Subject"] = "Prueba desde Python"
mensaje.set_content("Mensaje enviado correctamente.")
with smtplib.SMTP(HOST, PUERTO, timeout=20) as servidor:
servidor.ehlo()
servidor.starttls()
servidor.ehlo()
servidor.login(usuario, contrasena)
servidor.send_message(mensaje)Usa los datos oficiales de tu proveedor. Algunos servicios exigen una contraseña de aplicación o un método moderno de autenticación.
Enviar contenido HTML
mensaje.set_content(
"Tu cliente de correo no muestra HTML. El informe está listo."
)
mensaje.add_alternative(
"""
<html>
<body>
<h1>Informe listo</h1>
<p>Los datos fueron procesados correctamente.</p>
</body>
</html>
""",
subtype="html",
)Mantén una versión de texto para clientes que no renderizan HTML. No insertes contenido externo sin escapar.
Añadir un archivo adjunto
import mimetypes
from pathlib import Path
ruta = Path("informes") / "ventas.csv"
tipo, _ = mimetypes.guess_type(ruta.name)
tipo_principal, subtipo = (tipo or "application/octet-stream").split("/", 1)
mensaje.add_attachment(
ruta.read_bytes(),
maintype=tipo_principal,
subtype=subtipo,
filename=ruta.name,
)Comprueba que el archivo exista y limita su tamaño. Para trabajar con rutas de forma portable, consulta pathlib en Python.
Destinatarios múltiples
destinatarios = [
"[email protected]",
"[email protected]",
]
mensaje["To"] = ", ".join(destinatarios)Para envíos masivos, no expongas direcciones privadas en una cabecera compartida. Usa Bcc o genera mensajes individuales, respetando las políticas del proveedor y las normas aplicables.
Crear una función reutilizable
import os
import smtplib
from email.message import EmailMessage
def enviar_correo(destinatarios, asunto, texto):
usuario = os.environ["SMTP_USER"]
contrasena = os.environ["SMTP_PASSWORD"]
mensaje = EmailMessage()
mensaje["From"] = usuario
mensaje["To"] = ", ".join(destinatarios)
mensaje["Subject"] = asunto
mensaje.set_content(texto)
with smtplib.SMTP("smtp.example.com", 587, timeout=20) as servidor:
servidor.starttls()
servidor.login(usuario, contrasena)
servidor.send_message(mensaje)Separar la lógica en una función facilita las pruebas y el mantenimiento. La guía de funciones en Python explica parámetros, retornos y responsabilidades pequeñas.
Manejar errores y registrar resultados
import logging
import smtplib
try:
enviar_correo(
["[email protected]"],
"Alerta",
"El proceso terminó.",
)
except smtplib.SMTPAuthenticationError:
logging.exception("Autenticación SMTP rechazada")
except smtplib.SMTPException:
logging.exception("Error al enviar el correo")
except OSError:
logging.exception("Problema de red o del sistema")Evita registrar credenciales o el contenido sensible del mensaje. La guía del módulo logging ayuda a crear registros útiles, y try y except en Python muestra cómo capturar excepciones específicas.
Programar el envío
Para una tarea diaria, la opción más fiable suele ser ejecutar el script mediante cron, el Programador de tareas de Windows o un servicio administrado. El propio script debe realizar una única ejecución, devolver un código de salida claro y registrar el resultado.
Cuando el asunto o el nombre del archivo incluyen fechas, utiliza objetos estructurados. La guía de datetime en Python explica formatos y zonas horarias.
Buenas prácticas
- Usa conexiones cifradas y la configuración oficial del proveedor.
- Guarda credenciales fuera del código y del repositorio.
- Configura timeouts y captura errores SMTP específicos.
- No reintentes indefinidamente mensajes rechazados.
- Valida destinatarios, asunto, adjuntos y tamaño total.
- Evita enviar información sensible sin una política adecuada.
- Prueba primero con una cuenta y una lista de destinatarios controlada.
Conclusión
Automatizar correos con Python requiere más que llamar a una función de envío. Un flujo fiable protege credenciales, usa TLS, construye mensajes con EmailMessage, configura timeouts y registra los errores sin revelar secretos. Empieza con un mensaje de texto simple y añade HTML, adjuntos y programación solamente después de validar el envío básico.


