SMTP per Python — posta dal tuo script o dalla tua app Django che arriva
Python ha SMTP integrato: con smtplib invii un messaggio in una manciata di righe, e Django lo racchiude in un proprio livello di posta con le impostazioni EMAIL. Ciò che nessuno dei due fornisce è la recapitabilità — quella dipende dal server attraverso cui invii.
Che tu abbia uno script isolato, un'app Flask o un progetto Django: le impostazioni sono gli stessi cinque dati. Li fai puntare al tuo relay e il codice che compone i messaggi resta invariato.
Perché senza relay le cose vanno storte
La posta di Python arriva spesso dal retro: un report notturno, un'attività cron che invia fatture, uno script che avvisa quando una misura esce dai margini. Nessuno ci sta guardando — e quindi nessuno si accorge che il server ricevente le rifiuta in silenzio. Con Django si aggiunge la classica sorpresa del passaggio in produzione: in sviluppo tutto va alla console, in produzione verso provider reali che controllano davvero la reputazione.
Configurare l'SMTP in Python
Recupera i dati
Accedi al tuo account 2mail e recupera lì il tuo server SMTP, il nome utente e la password.
Inserisci in Python
In un progetto Django imposti le impostazioni EMAIL nei settings: il backend SMTP come backend di posta, l'host del relay, la porta 587, l'opzione STARTTLS attiva, nome utente e password e un indirizzo mittente predefinito sul tuo dominio. Se lavori direttamente con smtplib, ti connetti all'host sulla porta 587, chiami starttls, effettui l'accesso con nome utente e password e invii poi il messaggio. In entrambi i casi leggi i dati da variabili d'ambiente, non dal codice.
Autentica il dominio
Assicurati che SPF, DKIM e DMARC siano configurati correttamente per il tuo dominio, così i destinatari possono verificare che il messaggio provenga da te.
Prova
Invia dalla tua piattaforma un messaggio di prova a un indirizzo presso un grande provider e verifica che arrivi nella posta in arrivo e non nella cartella spam.
I campi richiesti da Python
Ogni piattaforma li chiama in modo leggermente diverso, ma si tratta sempre degli stessi cinque. I valori concreti sono legati al tuo account e li trovi nel tuo account 2mail — recuperali da lì, così sei certo di usare quelli giusti.
| Campo | Che cosa inserire |
|---|---|
| Server SMTP (host) | Il nome del server dal tuo account 2mail. |
| Porta | La porta corrispondente alla cifratura scelta; il tuo account indica quale. |
| Cifratura | TLS. Non inviare mai in chiaro — altrimenti le tue credenziali viaggiano leggibili sulla rete. |
| Nome utente | Il login SMTP del tuo account 2mail. |
| Password | La password corrispondente. Non usare mai la password della casella di posta di un collaboratore. |
Configurazione SMTP per Python nel codice
Esempi funzionanti per la porta 587 con STARTTLS, pronti da copiare. Sostituisci l'indirizzo mittente con un indirizzo del tuo dominio e verifica nome del server e login nel tuo account 2mail. La password va in una variabile d'ambiente — mai nel codice e mai nel controllo di versione.
smtplib: connettersi sulla 587 con starttls()
La libreria standard è sufficiente. L'ordine conta: prima starttls(), e solo dopo login() — altrimenti la tua password passa in chiaro sulla linea, oppure il relay rifiuta l'autenticazione. Usa smtplib.SMTP e non SMTP_SSL: quest'ultimo va con la porta 465. Nome utente e password arrivano da variabili d'ambiente.
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: le impostazioni EMAIL_*
Django non ha bisogno di alcun pacchetto aggiuntivo. Imposta il backend SMTP in modo esplicito: in sviluppo è spesso impostato sul backend console, e allora la produzione non invia nulla mentre tutto sembra funzionare. sendtestemail è un comando di gestione integrato con cui controlli le impostazioni senza dover richiamare una view o un task.
# 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: gli stessi cinque dati
Se lavori con Flask, Flask-Mail chiede gli stessi dati con altri nomi. Anche qui vale la stessa regola: MAIL_USE_TLS per la porta 587, e MAIL_USE_SSL resta disattivato.
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) Quali e-mail invia Python
Una volta configurato il relay, tutte queste passano tramite 2mail — non devi configurarle una per una.
Insidie con Python
Opzione TLS e porta devono coincidere
Django prevede due impostazioni TLS separate: una per STARTTLS e una per TLS fin dall'inizio. Attiva solo l'impostazione STARTTLS; è quella corrispondente alla porta 587. Attivarle entrambe genera un errore di configurazione; non attivarne nessuna invia le tue credenziali in chiaro, e un relay giustamente lo rifiuta.
Una connessione per serie, non per messaggio
Uno script che apre una nuova connessione SMTP per ciascuno di mille messaggi si comporta come un aggressore. Apri una connessione, invia la serie, chiudi. Django dispone di una funzione per inviare più messaggi su una sola connessione.
Errori silenziosi nelle attività in background
Un'eccezione in un'attività cron sparisce in un file di log che nessuno legge. Intercetta gli errori di invio e segnalali dove si notano — e collega i webhook di 2mail per recapito e bounce, così vedi anche ciò che va storto <em>dopo</em> la consegna.
Messaggi di errore frequenti con Python
I messaggi che compaiono quando host, porta, cifratura o login non sono corretti — riportati alla lettera, così li riconosci nel tuo log, con accanto la causa e la soluzione.
| Messaggio | Causa | Soluzione |
|---|---|---|
smtplib.SMTPAuthenticationError: (535, b'5.7.8 Error: authentication failed: …') | Il relay rifiuta le credenziali: nome utente o password errati, oppure una variabile d'ambiente che nel contesto di cron o del servizio ha un valore diverso rispetto alla tua shell. | Stampa ciò che il processo legge effettivamente (il nome utente, mai la password) e usa il login SMTP del tuo account 2mail — non la password di una casella di posta. |
smtplib.SMTPNotSupportedError: SMTP AUTH extension not supported by server. | login() viene chiamato prima di starttls(). Un relay offre l'autenticazione solo quando la connessione è cifrata; sulla connessione ancora in chiaro AUTH quindi non esiste. | Chiama prima server.starttls(context=context) e solo dopo server.login(…). In Django: imposta EMAIL_USE_TLS = True. |
ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:…) | Il codice usa smtplib.SMTP_SSL (oppure, in Django, EMAIL_USE_SSL) sulla porta 587. Python inizia allora subito con un handshake TLS, mentre su quella porta il relay si aspetta prima SMTP semplice e passa a TLS solo dopo STARTTLS. La classica confusione tra 465 e 587. | Usa smtplib.SMTP(…, 587) seguito da starttls(), oppure in Django EMAIL_USE_TLS = True con la porta 587. |
smtplib.SMTPServerDisconnected: Connection unexpectedly closed | La connessione è caduta prima o durante il dialogo. Di solito si tratta di uno script che tiene aperta una connessione e la riutilizza dopo una lunga pausa, mentre nel frattempo il server l'ha chiusa per inattività — oppure di una normale connessione SMTP verso una porta che si aspetta TLS dal primo byte. | Apri una connessione per ogni serie di messaggi e chiudila al termine; intercetta l'eccezione e riconnettiti. Verifica di usare la porta 587 con starttls(). |
ValueError: EMAIL_USE_TLS/EMAIL_USE_SSL are mutually exclusive, so only set one of those settings to True. | Nei settings di Django sono attive entrambe le opzioni TLS — spesso perché una arriva da un file di base condiviso e l'altra dai settings di produzione. | Lascia soltanto EMAIL_USE_TLS = True e imposta EMAIL_USE_SSL = False. |
Un'altra piattaforma?
L'SMTP è un protocollo standard: ogni sistema che parla SMTP — un CRM, un ERP, un'applicazione proprietaria o un server — può inviare tramite 2mail con gli stessi cinque campi.