Enviar correos electrónicos con Python

Envía correo en Python con email.message.EmailMessage y smtplib.SMTP_SSL de la biblioteca estándar, o llama a una API de correo HTTP con el paquete messagebird-sdk para los envíos en producción.

La biblioteca estándar de Python incluye smtplib para la conexión SMTP y email.message.EmailMessage para construir el mensaje, así que un envío básico por SMTP no requiere paquetes de terceros. Para los envíos en producción, una API de correo HTTP gestiona el calentamiento de IP, los reintentos y los eventos de rebote sin que tengas que mantener un servidor de correo.

¿Cómo envías correo con la biblioteca estándar?

EmailMessage construye el mensaje y establece las cabeceras por ti. smtplib.SMTP_SSL abre una conexión cifrada en el puerto 465:

import smtplib
from email.message import EmailMessage

msg = EmailMessage()
msg["From"] = "you@yourdomain.com"
msg["To"] = "recipient@example.org"
msg["Subject"] = "Your receipt"
msg.set_content("Thanks for your order. This is the plain-text version.")
msg.add_alternative("<p>Thanks for your order.</p>", subtype="html")

with smtplib.SMTP_SSL("smtp.example.com", 465) as server:
    server.login("smtp-user", "smtp-password")
    server.send_message(msg)

set_content escribe el cuerpo en texto plano y add_alternative adjunta la versión HTML, para que los clientes elijan lo que pueden renderizar. Enviar ambas partes es buena práctica y ayuda con la entregabilidad.

¿SSL o STARTTLS?

Existen dos rutas de cifrado y usan puertos distintos. SMTP_SSL en el 465 negocia TLS desde el primer byte. La alternativa es SMTP en texto plano en el 587 seguido de starttls(), que actualiza una conexión sin cifrar:

with smtplib.SMTP("smtp.example.com", 587) as server:
    server.starttls()
    server.login("smtp-user", "smtp-password")
    server.send_message(msg)

Elige según lo que admita tu servidor de correo. No envíes credenciales por una conexión sin cifrar. Guarda el nombre de usuario y la contraseña en variables de entorno, leídas con os.environ, en lugar de escribirlos en el código fuente.

¿Cómo añades un archivo adjunto?

add_attachment recibe los bytes más un tipo MIME. Lee el archivo en modo binario:

with open("invoice.pdf", "rb") as f:
    msg.add_attachment(
        f.read(),
        maintype="application",
        subtype="pdf",
        filename="invoice-1042.pdf",
    )

¿Por qué dejar SMTP directo en producción?

Los envíos en producción añaden requisitos que la biblioteca estándar no cubre. Necesitas un servidor de correo con buena reputación de IP, registros SPF, DKIM y DMARC, lógica para reintentar tras fallos transitorios y una forma de hacer seguimiento de los rebotes y las quejas. Una API HTTP se encarga de esa capa: te autenticas con una clave de API, envías JSON y lees respuestas estructuradas en lugar de analizar códigos de estado SMTP.

Envíalo con Bird

Instala el SDK de Python de Bird (pip install messagebird-sdk) para enviar por HTTPS sin gestionar una conexión SMTP:

from bird import APIError, Bird

client = Bird()

try:
    message = client.email.send(
        from_="onboarding@messagebird.dev",
        to=["delivered@messagebird.dev"],
        subject="Hello from Python",
        text="It works.",
        html="<p>It works.</p>",
    )
    print(message.id, message.status)
except APIError as err:
    print("send failed:", err)

Bird() lee BIRD_API_KEY del entorno automáticamente. Si envías desde onboarding@messagebird.dev a la dirección sandbox de delivered@messagebird.dev, compruebas tu clave y tu payload antes de configurar un dominio propio. Si la solicitud no supera la validación, APIError muestra el código de estado HTTP y el código de error.

Construye sobre la misma red.

Obtén una clave API de prueba de inmediato. El acceso a producción se desbloquea cuando añades un método de pago y verificas un remitente.

Start building with Bird in minutes.