Automatitzar l’enviament d’alertes per email amb Python
Configurar l’enviament automàtic d’alertes per email amb Python no és especialment difícil, però fer-ho bé —de forma estable, mantenible i sense soroll innecessari— requereix més cap del que sembla. No n’hi ha prou amb escriure un script que enviï correus quan ” passa alguna cosa”. Hi ha una sèrie de decisions que, si es prenen per inèrcia, porten a alertes ignorades, servidors de correu bloquejats o manteniment innecessari.
Quin problema estàs resolent exactament
Abans d’escriure una sola línia de codi, convé fer-te aquesta pregunta: vols alertar o notificar? No és el mateix.
- Si vols alertar, significa que esperes atenció immediata o prioritària.
- Si només notifiques, és una cosa que algú veurà quan revisi la seva safata, sense urgència.
Això marca una diferència clau en com configures el sistema: freqüència, prioritat del correu, agrupament de missatges, i fins i tot el compte des del qual s’envia. Si tot ho tractes com a alerta, acabaràs en spam. Si tot ho tractes com a notificació, ningú reaccionarà quan realment alguna cosa estigui espatllada.
Enviar correus des de Python amb SMTP
Si el que necessites és control i simplicitat, evita dependre de llibreries externes per a una cosa tan bàsica com enviar un correu. El mòdul smtplib de la llibreria estàndard funciona bé i no desapareix quan actualitzes l’entorn.
Aquest és un model d’exemple:
import smtplib
from email.message import EmailMessage
def send_email(subject, body, to_addrs, from_addr, smtp_server, smtp_port, username=None, password=None, use_tls=True):
msg = EmailMessage()
msg["Subject"] = subject
msg["From"] = from_addr
msg["To"] = ", ".join(to_addrs)
msg.set_content(body)
with smtplib.SMTP(smtp_server, smtp_port, timeout=10) as server:
if use_tls:
server.starttls()
if username and password:
server.login(username, password)
server.send_message(msg)
Algunes coses a tenir en compte:
- El timeout explícit evita que l’script es quedi penjat si el servidor no respon.
- L’ús de starttls() en comptes de SSL pur permet més compatibilitat amb servidors que estan mal configurats.
- No facis retry aquí. Si l’enviament d’alertes és crític, el retry el controles fora de l’enviament, no dins. Així tens visibilitat dels errors.
Quin compte fer servir per a enviar correus
Aquest detall sovint s’gnora fins que hi ha algun problema. Si pots, fes servir un compte SMTP dedicat per a automatismes, separat de comptes d’usuaris humans o de sistemes crítics.
Raons:
- Pots limitar el seu accés només a l’enviament, sense accés a la safata.
- Pots identificar des del costat del receptor quins missatges venen de sistemes.
- Si es compromet o bloqueja, no afecta altres processos ni persones.
Si no tens un servidor de correu propi, i estàs fent servir proveïdors com Gmail o Outlook, considera fer servir App Passwords o configuracions de baix nivell amb autenticació específica per a scripts. Si fas servir una contrasenya estàndard i després hi ha un login sospitós, el proveïdor pot bloquejar l’accés, i et quedaràs sense alertes sense saber-ho.
Evitar spam i bloquejos
Encara que sigui un servidor intern, convé cuidar alguns mínims per a no ser filtrat:
- Fes servir una adreça From vàlida i coherent amb el domini del servidor SMTP.
- No enviïs correus sense assumpte ni només amb majúscules.
- Inclou almenys una signatura o peu predictible. Això ajuda a identificar els missatges, tant per a humans com per als filtres.
- Si pots configurar SPF/DKIM/DMARC, fes-ho. Especialment si fas servir el teu propi domini.
I el més important: no disparis una alerta cada segon si alguna cosa falla en bucle. Això es controla fora de l’enviament de correu, amb throttling, caché o algun sistema que marqui “ja avisat”. Més sobre això a continuació.
Controlar el soroll: agrupació i supressió
Un dels errors més comuns és disparar alertes cada vegada que una condició es compleix. Això no escala. Un exemple habitual:
if ! systemctl is-active --quiet myservice; then
python3 send_alert.py
fi
Si això va en un cron cada minut, tindràs 60 correus per hora. Ningú se´ls llegirà. Hi ha diverses formes d’evitar això:
1. Arxiu de lock o estat
Crea un arxiu que indiqui si ja has alertat per aquesta condició.
if ! systemctl is-active --quiet myservice; then
if [ ! -f /tmp/alerted-myservice ]; then
python3 send_alert.py
touch /tmp/alerted-myservice
fi
else
rm -f /tmp/alerted-myservice
fi
Aquest patró funciona bé i és més fiable del que sembla.
2. Agrupació temporal
Pots emmagatzemar els errors en un arxiu o en Redis, i enviar un resum cada cert temps, per exemple cada 10 minuts.
# Pseudocodi
if error_detectat:
guardar_a_cache(error)
if es_moment_d’_enviar:
errors = llegir_cache()
enviar_resum(errors)
netejar_cache()
Això redueix el soroll i fa que l’alerta sigui més digerible.
Fer servir HTML quan toca
Enviar correus en text pla sovint és suficient, però hi ha casos on un HTML bàsic aporta molt. No per decorar, sinó per estructurar: una taula amb els resultats d’una revisió, o enllaços directes a dashboards o logs.
msg.add_alternative("""
<html>
<body>
<h2>Error a la sincronització de la base de dades</h2>
<p>S’ha detectat un error al procés <strong>sync_db</strong>.</p>
<p><a href="https://monitor.com/informes/sync">Veure detalls</a></p>
</body>
</html>
""", subtype="html")
El truc és que l’EmailMessage de Python permet combinar text pla i HTML com a multipart/alternative. Així els clients de correu trien què renderitzar.
Logs i traçabilitat de l’ enviament
Si automatitzes l’enviament d’alertes, tard o d’hora algú et preguntarà: “Aquest correu es va arribar a enviar?”, o pitjor, “Per què no em va arribar?”. Si no tens logs, només pots suposar.
Per a això, pots fer el següent:
- Registre local (logfile o syslog) de cada intent d’enviament, amb timestamp, destinataris i subject.
- Si l’enviament falla, es deixa un rastre clar. Res d’ocultar-ho amb un try/except que ho ignora tot.
- Per a processos crítics, loggejar també el contingut del missatge (almenys el hash) ajuda a diferenciar si el que es va enviar va ser l’alerta real o un fals positiu.
Exemples al món real
- Venciment de certificats TLS: Un script que revisa cada nit tots els certificats dels hosts interns i externs que es fan servir. Si algun expira en menys de 15 dies, dispara un correu. S’ envia un cop per dia per domini afectat. Si segueix fallant, es repeteix a les 24h.
- Backup fallit en servidors heretats: On no hi ha integració amb sistemes moderns, un petit script revisa logs o resultats, i si detecta errors, envia correu amb el log adjunt. Només alerta si l’estat ha canviat (d’èxit a fallada o viceversa).
- Monitor d’espai en disc per a entorns legacy: Quan no hi ha Prometheus ni res modern, l’script envia email si una partició passa cert llindar. Només alerta una vegada cada X hores mentre segueix el problema, i deixa d’alertar si es corregeix.
Quan no fer això tu mateix
Cal dir-ho: si ja fas servir un sistema de monitorització decent (Zabbix, Icinga, Prometheus amb Alertmanager, etc.), no repliquis l’enviament d’alertes a Python. No només és redundant, és contraproduent. Acabes amb alertes duplicades, i no saps quina és la font de veritat.
Aquesta solució val quan:
- Tens scripts puntuals que fan tasques específiques.
- Estàs en entorns mixtos o molt custom on les eines generalistes no arriben.
- Vols alertar abans que el problema escali i no hi ha cap altre sistema mirant.
Autenticació moderna i problemes comuns
Enviar correus des d’un script és cada vegada més molest, especialment si depèns de proveïdors com Google, Microsoft o serveis que intenten bloquejar tot el que no sigui “usuari humà des de navegador”. Anys enrere n’hi havia prou amb configurar SMTP i llestos, però avui necessites entendre alguns detalls per a evitar que et bloquegin.
Gmail / Google Workspace
Google bloqueja intents de login “insegurs” per defecte. I si estàs fent servir SMTP amb usuari/contrasenya, això és considerat insegur.
Opcions reals:
- OAuth2: És el que Google vol. Però configurar-lo en un script que només envia correus és innecessàriament complex.
- App Passwords: Si tens 2FA activat, pots generar una contrasenya específica per a l’script. Això normalment funciona de forma estable.
- Relaying des de servidor de confiança: Si tens un servidor que ja està autenticat a Google Workspace (per IP, per SPF, etc.), pots fer-lo servir com a relay.
No intentis saltar-te aquestes restriccions “temporalment”. Si ho fas en producció, el dia que falli hauràs de descobrir-ho a les 3 de la matinada.
Microsoft (Outlook/365)
Més restrictiu encara. Microsoft està forçant l’autenticació moderna (OAuth2), i deshabilitant l’autenticació bàsica fins i tot per a SMTP. Molts scripts vells simplement van deixar de funcionar.
Solucions pràctiques:
- Fa servir un relay local que sí que tingui autenticació moderna i reenviï el correu.
- Configura un compte tècnic amb permisos molt limitats, i genera un token OAuth2 per a ell. Hi ha eines per renovar automàticament el token, però és un manteniment addicional.
- Si només treballes dins de la xarxa corporativa, considera fer servir un servidor SMTP intern que reenviï office 365 mitjançant autenticació forta.
És freqüent veure scripts que “funcionen en test” perquè el token no ha expirat encara. O que funcionaven fa setmanes però van deixar de fer-ho sense donar un error clar. Per això, prova l’enviament regularment encara que no hi hagi alertes.
Entorns cloud i restriccions de xarxa
Si estàs a AWS, GCP o Azure, hi ha regles específiques que impedeixen enviar correus directament des de servidors (per defecte):
- AWS EC2: Les instàncies en VPC per defecte no poden fer connexions sortints a ports 25. Cal fer servir SES o configurar accés explícit a un relay.
- Google Cloud: Restringeix trànsit sortint a SMTP 25 per spam. Has de fer servir el seu servei de correu o relay extern amb TLS (port 587 o 465).
- Azure: Similar. Bloqueja trànsit SMTP sortint des d’ IPs públiques.
Això ho veus quan fas telnet smtp.example.com 25 i no respon. No és un error de l’script, és la xarxa que t’ho impedeix.
La solució més neta és fer servir un relay SMTP autenticat dins del mateix núvol, amb reputació coneguda. Per exemple, configurar Postfix per a autenticar contra SendGrid o Mailgun, i enviar des d’aquí.
Integració amb serveis externs
Quan has d’escalar una mica —per exemple, enviar alertes a diverses persones, incloure adjunts, controlar la prioritat o registrar confirmacions— SMTP pur es queda curt.
En aquests casos, fes servir un d’ aquests tres:
Sendgrid
- Funciona bé com a relay SMTP o via API.
- Té quota gratuïta raonable i suport per a HTML, adjunts, etc.
- Permet configurar plantilles reutilitzables des de la interfície, la qual cosa ajuda si diversos scripts comparteixen alertes similars.
Mailgun
- Similar, amb bona integració de logs i estadístiques.
- La seva API és més estricta, però més predictible en entorns amb alta càrrega.
- Molt útil si necessites saber amb certesa si el correu es va lliurar (tracking).
Amazon SES
- Millor de preu si ja estàs a AWS.
- Molt tiquis-miquis amb les validacions de domini i límits fins que “hi confies”.
- No és tan fàcil de fer servir des d’entorns mixtos, però sòlid si el deixes ben configurat.
Quan facis un d’ aquests, millor integrar via API REST, no SMTP. Més traçabilitat, millor control d’errors, i menys problemes amb TLS i firewalls.
Escalabilitat mínima
Tot i que això no és un sistema d’alertes complex, hi ha formes de fer que escali sense tornar-se incontrolable. Alguns patrons que es poden aplicar a gairebé tots els entorns:
1. Un wrapper comú per a l’enviament
En comptes de que cada script tingui la seva pròpia lògica d’enviament, crea un petit mòdul comú (email_alerts.py) amb una interfície clara. Així, si demà canvies de SMTP a SendGrid, només toques un lloc.
# email_alerts.py
def alert(subject, body, level="info"):
# Nivell pot ser info, warning, critical
# Pots fer-lo servir per acolorir HTML o triar remitent
...
2. Script de test manual
Tenir un send_test_email.py que et permeti verificar l’enviament real en qualsevol entorn és vital. Especialment quan canvies de proveïdor o modifiques regles de xarxa.
3. No facis retry a cegues
Si fas retry sense lògica, pots acabar enviant la mateixa alerta 20 vegades i col·lapsar la bústia d’algú. Millor, guarda un estat temporal (arxiu, Redis, SQLite) i defineix un backoff clar.
4. Logging explícit de fallades d’enviament
No et conformis amb capturar excepcions. Tot el que no es va poder enviar, idealment en un arxiu separat (email_errors.log), amb timestamps i causes. Això t’estalvia hores quan algú diu “no va arribar el correu”.
Conclusió
Automatitzar l’enviament d’alertes per email amb Python no és glamurós. No fardaràs d’això a cap demo. Però quan falla, fa mal. Per això convé muntar-ho bé, des del començament, amb el cap fred i sense dreceres que després passen factura.
Els scripts que alerten han de ser avorrits, predicibles. Visibles quan fallen, i silenciosos quan no. Si després de mesos ningú s’ha queixat, és que ho has fet bé.

