2mail — SMTP relay desde infraestructura belga

SMTP para Python — correo de su script o app Django

Python trae SMTP integrado: con smtplib envía un mensaje en unas pocas líneas, y Django lo agrupa en su propia capa de correo con los ajustes EMAIL. Lo que no aporta ninguno de los dos es la entregabilidad: eso depende del servidor por el que envía.

Tanto si tiene un script suelto como una aplicación Flask o un proyecto Django, los ajustes son los mismos cinco datos. Los apunta a su relay y el código que compone los mensajes se queda igual.

Por qué falla sin relay

El correo de Python sale a menudo desde el segundo plano: un informe nocturno, una tarea programada que envía facturas, un script que avisa cuando una medición se sale del margen. Nadie está mirando, así que nadie nota que el servidor receptor los rechaza en silencio. En Django se suma la sorpresa clásica al publicar: en desarrollo todo va a la consola y en producción a proveedores reales que sí comprueban la reputación.

Configurar el SMTP en Python

1

Obtener los datos

Acceda a su cuenta de 2mail y obtenga allí su servidor SMTP, su nombre de usuario y su contraseña.

2

Introducirlos en Python

En un proyecto Django pone los ajustes EMAIL en la configuración: el backend SMTP como backend de correo, el host del relay, el puerto 587, la opción STARTTLS activada, el usuario y la contraseña, y una dirección de remitente por defecto en su propio dominio. Si trabaja directamente con smtplib, conecta con el host en el puerto 587, llama a starttls, inicia sesión con usuario y contraseña y envía después el mensaje. En ambos casos, lea los datos de variables de entorno y no del código.

3

Autenticar el dominio

Asegúrese de que SPF, DKIM y DMARC de su dominio son correctos, para que los destinatarios puedan verificar que el correo viene de usted.

4

Probar

Envíe desde su plataforma un mensaje de prueba a una dirección de un gran proveedor y compruebe que llega a la bandeja de entrada y no a la carpeta de spam.

Los campos que pide Python

Cada plataforma los llama de una manera algo distinta, pero siempre son los mismos cinco. Los valores concretos dependen de su cuenta y los encuentra en su cuenta de 2mail: cópielos de ahí para asegurarse de usar los correctos.

Campo Qué introducir
Servidor SMTP (host)El nombre del servidor de su cuenta de 2mail.
PuertoEl puerto que corresponde al cifrado elegido; su cuenta le indica cuál.
CifradoTLS. No envíe nunca sin cifrar: de lo contrario sus credenciales viajan en claro.
Nombre de usuarioEl acceso SMTP de su cuenta de 2mail.
ContraseñaLa contraseña correspondiente. No use nunca la contraseña del buzón de un empleado.

Configuración SMTP para Python en código

Ejemplos que funcionan para el puerto 587 con STARTTLS, listos para copiar. Sustituya la dirección de remitente por una dirección de su propio dominio y compruebe el nombre del servidor y el acceso en su cuenta de 2mail. La contraseña va en una variable de entorno: nunca en el código y nunca en el control de versiones.

smtplib: conectar por el 587 con starttls()

Basta con la biblioteca estándar. El orden importa: primero starttls() y solo después login(); de lo contrario su contraseña viaja sin cifrar, o el relay rechaza el inicio de sesión. Use smtplib.SMTP y no SMTP_SSL: este último corresponde al puerto 465. El acceso y la contraseña salen de variables de entorno.

import os
import smtplib
import ssl
from email.message import EmailMessage

msg = EmailMessage()
msg["From"] = "Example <noreply@example.com>"
msg["To"] = "you@example.org"
msg["Subject"] = "SMTP test"
msg.set_content("Sent through the 2mail SMTP relay.")

context = ssl.create_default_context()

with smtplib.SMTP("relay.2mail.eu", 587, timeout=10) as server:
    server.starttls(context=context)  # upgrade to TLS first, log in afterwards
    server.login(os.environ["SMTP_USERNAME"], os.environ["SMTP_PASSWORD"])
    server.send_message(msg)          # call again for the next message, same connection

Django: los ajustes EMAIL_*

Django no necesita ningún paquete adicional. Fije el backend SMTP de forma explícita: en desarrollo suele estar en el backend de consola, y entonces producción no envía nada mientras todo parece funcionar. sendtestemail es un comando de gestión integrado con el que comprueba los ajustes sin tener que llamar a una vista ni a una tarea.

# settings.py
import os

EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "relay.2mail.eu"
EMAIL_PORT = 587
EMAIL_USE_TLS = True   # STARTTLS - never together with EMAIL_USE_SSL
EMAIL_HOST_USER = os.environ["SMTP_USERNAME"]
EMAIL_HOST_PASSWORD = os.environ["SMTP_PASSWORD"]
EMAIL_TIMEOUT = 10
DEFAULT_FROM_EMAIL = "Example <noreply@example.com>"
SERVER_EMAIL = "noreply@example.com"   # sender of error reports to ADMINS

# Test from the shell:
#   python manage.py sendtestemail you@example.org

Flask-Mail: los mismos cinco datos

Si trabaja con Flask, Flask-Mail pide los mismos datos con otros nombres. Aquí vale lo mismo: MAIL_USE_TLS para el puerto 587, y MAIL_USE_SSL se queda desactivado.

import os
from flask import Flask
from flask_mail import Mail

app = Flask(__name__)
app.config.update(
    MAIL_SERVER="relay.2mail.eu",
    MAIL_PORT=587,
    MAIL_USE_TLS=True,    # STARTTLS
    MAIL_USE_SSL=False,
    MAIL_USERNAME=os.environ["SMTP_USERNAME"],
    MAIL_PASSWORD=os.environ["SMTP_PASSWORD"],
    MAIL_DEFAULT_SENDER="noreply@example.com",
)
mail = Mail(app)

Qué correos envía Python

Una vez configurado el relay, todos estos pasan por 2mail: no tiene que configurarlos uno a uno.

Recuperación de contraseña y verificación de correo desde Django
Informes y exportaciones programados desde tareas cron
Avisos de scripts de monitorización y de tratamiento de datos
Facturas y confirmaciones de una aplicación web
Informes de error a los administradores

Errores frecuentes con Python

La opción TLS y el puerto deben coincidir

Django tiene dos ajustes de TLS distintos: uno para STARTTLS y otro para TLS desde el principio. Active solo el ajuste de STARTTLS, que es el que corresponde al puerto 587. Activar los dos da un error de configuración; no activar ninguno envía su acceso sin cifrar, y un relay rechaza eso con razón.

Una conexión por serie, no por mensaje

Un script que abre una conexión SMTP nueva para cada uno de mil mensajes se comporta como un atacante. Abra una conexión, envíe la serie y ciérrela. Django tiene una función para enviar varios mensajes por una misma conexión.

Errores silenciosos en tareas de fondo

Una excepción en una tarea cron desaparece en un archivo de registro que nadie lee. Capture los errores al enviar y notifíquelos en algún sitio donde se vean, y conecte los webhooks de 2mail para la entrega y el rebote, para ver también lo que falla tras la entrega.

Mensajes de error habituales con Python

Los mensajes que recibe cuando el host, el puerto, el cifrado o el acceso no son correctos: citados literalmente, para que los reconozca en su registro, con la causa y la solución al lado.

Mensaje Causa Solución
smtplib.SMTPAuthenticationError: (535, b'5.7.8 Error: authentication failed: …') El relay rechaza el acceso: un usuario o una contraseña incorrectos, o una variable de entorno que en el contexto de cron o del servicio tiene un valor distinto al de su shell. Imprima lo que el proceso lee realmente (el usuario, nunca la contraseña) y use el acceso SMTP de su cuenta de 2mail, no la contraseña de un buzón.
smtplib.SMTPNotSupportedError: SMTP AUTH extension not supported by server. login() se llama antes que starttls(). Un relay solo ofrece la autenticación una vez cifrada la conexión; en la conexión aún sin cifrar, AUTH sencillamente no existe. Llame primero a server.starttls(context=context) y solo después a server.login(…). En Django: ponga EMAIL_USE_TLS = True.
ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:…) El código usa smtplib.SMTP_SSL (o, en Django, EMAIL_USE_SSL) en el puerto 587. Python empieza entonces directamente con una negociación TLS, mientras que el relay espera primero SMTP sin cifrar en ese puerto y solo cambia tras STARTTLS. La clásica confusión entre el 465 y el 587. Use smtplib.SMTP(…, 587) seguido de starttls(), o en Django EMAIL_USE_TLS = True con el puerto 587.
smtplib.SMTPServerDisconnected: Connection unexpectedly closed La conexión se ha cortado antes de la conversación o durante ella. Lo habitual es un script que mantiene una conexión abierta y la reutiliza tras una pausa larga, cuando el servidor ya la ha cerrado por inactividad; o bien una conexión SMTP sin cifrar a un puerto que espera TLS desde el primer byte. Abra una conexión por serie de mensajes y ciérrela después; capture la excepción y vuelva a conectar. Compruebe que usa el puerto 587 con starttls().
ValueError: EMAIL_USE_TLS/EMAIL_USE_SSL are mutually exclusive, so only set one of those settings to True. En los ajustes de Django están activadas las dos opciones de TLS, a menudo porque una viene de un archivo base compartido y la otra de los ajustes de producción. Deje solo EMAIL_USE_TLS = True y ponga EMAIL_USE_SSL = False.
SPF, DKIM y DMARC explicados Sobre la entregabilidad

¿Otra plataforma?

SMTP es un protocolo estándar: cualquier sistema que hable SMTP —un CRM, un ERP, una aplicación propia o un servidor— puede enviar a través de 2mail con esos mismos cinco campos.

Preguntas frecuentes sobre el SMTP para Python

smtplib y Django envían, pero no aportan entregabilidad: eso depende del servidor por el que envía. Una función de correo local o un servidor recién montado no tiene autenticación ni reputación. Un SMTP relay con registros SPF, DKIM y DMARC correctos lo resuelve.
El backend SMTP como backend de correo, el host del relay, el puerto 587, la opción STARTTLS activada, su usuario y su contraseña, y una dirección de remitente por defecto en su propio dominio. Guarde el acceso en variables de entorno, no en la propia configuración.
Conecte con el host en el puerto 587, llame a starttls, inicie sesión con usuario y contraseña y envíe el mensaje. Para varios mensajes, use la misma conexión en lugar de abrir una nueva por cada uno.
En su cuenta de 2mail, por aplicación. Están ligados a la cuenta, así que no los publicamos en la web. Cree preferiblemente un acceso propio por script o por aplicación, para poder revocarlo por separado y seguir ese tráfico aparte.
Trust Guard Security Scanned
Llamar ahora
Enviar un correo