certmundo.
es‑mx

6 min de lectura

¿Cómo automatizar el envío de correos electrónicos con Python?

Puedes automatizar el envío de correos electrónicos con Python usando las bibliotecas smtplib y email, que vienen incluidas en la instalación estándar sin necesidad de instalar paquetes externos.

Las dos bibliotecas esenciales

smtplib se encarga de la conexión con el servidor de correo. email construye el mensaje: asunto, cuerpo y archivos adjuntos.

Juntas forman el núcleo de cualquier sistema de notificaciones automáticas. Puedes enviar desde reportes de ventas hasta alertas de error en producción.


Estructura básica de un correo automático

Todo script de envío sigue este esquema:

  1. Construir el mensaje con email.mime
  2. Conectarte al servidor SMTP con smtplib.SMTP
  3. Autenticarte con tu usuario y contraseña
  4. Enviar y cerrar la conexión

Esta secuencia se repite sin importar si el correo es simple o lleva adjuntos.


Ejemplo 1 — Correo de texto simple

Este script envía una notificación básica. Úsalo para alertas rápidas o confirmaciones de proceso.

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

remitente = "reportes@miempresa.com.mx"
destinatario = "gerente@miempresa.com.mx"
asunto = "Proceso completado"
cuerpo = "El proceso de carga de inventario terminó sin errores."

mensaje = MIMEMultipart()
mensaje["From"] = remitente
mensaje["To"] = destinatario
mensaje["Subject"] = asunto
mensaje.attach(MIMEText(cuerpo, "plain"))

with smtplib.SMTP("smtp.gmail.com", 587) as servidor:
    servidor.starttls()
    servidor.login(remitente, "tu_contraseña_app")
    servidor.sendmail(remitente, destinatario, mensaje.as_string())

print("Correo enviado correctamente.")

Nota importante: En Gmail debes usar una contraseña de aplicación, no tu contraseña normal. La generas en la configuración de seguridad de tu cuenta de Google.


Ejemplo 2 — Reporte con archivo adjunto

Supón que trabajas en FEMSA y cada lunes debes enviar un reporte de ventas en Excel. Este script adjunta el archivo automáticamente.

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
import os

remitente = "automatizacion@femsa.com.mx"
destinatario = "direccion@femsa.com.mx"
asunto = "Reporte semanal de ventas — FEMSA"
cuerpo = "Adjunto encontrarás el reporte de ventas de la semana. Generado automáticamente."
archivo_adjunto = "reporte_ventas_semana.xlsx"

mensaje = MIMEMultipart()
mensaje["From"] = remitente
mensaje["To"] = destinatario
mensaje["Subject"] = asunto
mensaje.attach(MIMEText(cuerpo, "plain"))

with open(archivo_adjunto, "rb") as archivo:
    adjunto = MIMEBase("application", "octet-stream")
    adjunto.set_payload(archivo.read())

encoders.encode_base64(adjunto)
adjunto.add_header(
    "Content-Disposition",
    f"attachment; filename={os.path.basename(archivo_adjunto)}"
)
mensaje.attach(adjunto)

with smtplib.SMTP("smtp.gmail.com", 587) as servidor:
    servidor.starttls()
    servidor.login(remitente, "tu_contraseña_app")
    servidor.sendmail(remitente, destinatario, mensaje.as_string())

print("Reporte enviado.")

El objeto MIMEBase con encoders.encode_base64 convierte el archivo binario a un formato seguro para transmisión por correo.


Ejemplo 3 — Notificación con datos variables

Este ejemplo es más cercano a un caso real. Imagina que en Liverpool se generan alertas cuando las ventas del día caen por debajo de una meta.

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

def enviar_alerta_ventas(tienda, ventas_dia, meta):
    remitente = "alertas@liverpool.com.mx"
    destinatario = "supervisor@liverpool.com.mx"
    diferencia = meta - ventas_dia

    asunto = f"Alerta: {tienda} por debajo de meta"
    cuerpo = (
        f"Tienda: {tienda}\n"
        f"Ventas del día: ${ventas_dia:,.0f}\n"
        f"Meta diaria: ${meta:,.0f}\n"
        f"Diferencia: -${diferencia:,.0f}\n"
        f"Se requiere revisión inmediata."
    )

    mensaje = MIMEMultipart()
    mensaje["From"] = remitente
    mensaje["To"] = destinatario
    mensaje["Subject"] = asunto
    mensaje.attach(MIMEText(cuerpo, "plain"))

    with smtplib.SMTP("smtp.gmail.com", 587) as servidor:
        servidor.starttls()
        servidor.login(remitente, "tu_contraseña_app")
        servidor.sendmail(remitente, destinatario, mensaje.as_string())

    print(f"Alerta enviada para {tienda}.")

enviar_alerta_ventas("Perisur", 42000, 60000)

Resultado en consola:

Alerta enviada para Perisur.

Cuerpo del correo generado:

Tienda: Perisur
Ventas del día: $42,000
Meta diaria: $60,000
Diferencia: -$18,000
Se requiere revisión inmediata.

Al envolver la lógica en una función, puedes llamarla dentro de un ciclo para revisar múltiples tiendas en segundos.


Enviar a múltiples destinatarios

Para notificar a todo un equipo, usa una lista y únela con comas.

destinatarios = [
    "gerente@bimbo.com.mx",
    "logistica@bimbo.com.mx",
    "finanzas@bimbo.com.mx"
]

mensaje["To"] = ", ".join(destinatarios)
servidor.sendmail(remitente, destinatarios, mensaje.as_string())

sendmail acepta una lista de correos como segundo argumento. El campo "To" del encabezado es solo visual; la entrega real la controla ese segundo argumento.


Tabla de referencia: componentes MIME

Clase Uso
MIMEMultipart Contenedor principal del mensaje
MIMEText Texto plano o HTML en el cuerpo
MIMEBase Archivos adjuntos genéricos
encoders.encode_base64 Codifica archivos binarios para adjuntar

Siempre usa MIMEMultipart como base. Los demás objetos se adjuntan con .attach().


Tabla de referencia: parámetros SMTP comunes

Servidor Host Puerto Cifrado
Gmail smtp.gmail.com 587 STARTTLS
Outlook / Hotmail smtp.office365.com 587 STARTTLS
Yahoo smtp.mail.yahoo.com 587 STARTTLS
Servidor propio tu_dominio.com.mx 587 / 465 STARTTLS / SSL

El puerto 587 con STARTTLS es el estándar moderno. Evita el puerto 25, que muchos proveedores bloquean.


Errores comunes

Error 1 — Usar la contraseña de cuenta en lugar de contraseña de aplicación. Gmail y Outlook bloquean el inicio de sesión si usas tu contraseña normal desde un script. Genera siempre una contraseña de aplicación específica para Python.

Error 2 — No usar starttls() antes de login(). Si omites servidor.starttls(), la conexión no está cifrada y el servidor rechaza la autenticación. Esta línea siempre va antes de login().

Error 3 — Abrir el archivo adjunto en modo texto ("r") en lugar de binario ("rb"). Los archivos Excel, PDF e imágenes deben abrirse con open(archivo, "rb"). Si usas "r" obtendrás un error de codificación.

Error 4 — Hardcodear credenciales en el código fuente. Nunca escribas tu contraseña directamente en el script si lo vas a compartir o subir a un repositorio. Usa variables de entorno con os.environ.get("CORREO_PASSWORD").

import os
password = os.environ.get("CORREO_PASSWORD")

Esto mantiene tus credenciales fuera del código y protege tu cuenta.


Automatización programada

Enviar correos con Python cobra mayor utilidad cuando el script corre solo, sin intervención manual. En Windows puedes usar el Programador de tareas. En Linux o macOS usas cron.

Ejemplo de entrada en cron para ejecutar el reporte todos los lunes a las 7:00 a.m.:

0 7 * * 1 /usr/bin/python3 /home/usuario/reporte_semanal.py

Combina este script con lo que aprendiste en la lección anterior: genera el Excel con openpyxl o pandas y luego envíalo de forma automática en el mismo flujo.


Puntos clave

  • Usa smtplib para la conexión y email.mime para construir el mensaje completo.
  • Siempre llama servidor.starttls() antes de servidor.login() para cifrar la conexión.
  • Los archivos adjuntos requieren MIMEBase + encoders.encode_base64 y abrirse en modo binario ("rb").
  • Nunca pongas contraseñas directamente en el código; usa variables de entorno con os.environ.get().
  • Combina el envío de correos con la generación de archivos Excel para crear reportes automáticos de extremo a extremo.

Puntos clave

  • Usa `smtplib` para conectarte al servidor de correo y `email.mime` para construir el mensaje, el asunto y los archivos adjuntos.
  • Siempre llama a `servidor.starttls()` antes de `servidor.login()`. Sin cifrado, el servidor rechaza la autenticación.
  • Para adjuntar archivos Excel o PDF, abre el archivo en modo binario (`"rb"`) y usa `MIMEBase` con `encoders.encode_base64`.
  • Nunca escribas contraseñas directamente en el script. Guárdalas en variables de entorno y accede con `os.environ.get()`.
  • Combina este módulo con `pandas` u `openpyxl` para generar y enviar reportes automáticos sin ninguna intervención manual.

Comparte esta lección:

¿Cómo automatizar el envío de correos electrónicos con Python? | Automatización con Python | Certmundo