El Blog de Trespams

Blog personal sobre tecnologia, gestió de projectes i coses que se me passen pel cap

Mails amb Django - IV

Amb tot el que hem vist fins ara podem organitzar els nostres enviaments de correus i mantenir al seu manteniment organitzat encara que el nombre d'opcions sigui gran.

Hi ha encara un grapat d'escenaris que és interessant tractar, ja que ens els trobarem sovint. Pensem en aquests possibles escenaris:

  • Ens hem de connectar a un servidor SMTP extern i el temps de connexió és gran, la qual cosa fa que la nostra aplicació web no respongui.
  • Tenim un entorn de preproducció on els correus no s'enviïn però on volem mantenir registre del que s'hauria enviat.
  • Volem mantenir un registre dels correus que s'envien dins la nostra aplicació.

El primer escenari es pot resoldre amb un servidor de correu local y fent realy cap al servidor final, però això a vegades no és possible ja que no tenim la gestió del servidor de correu.

També ho podem resoldre amb un sistema de coes, és a dir, l'enviament de correu es posa com a tasca i és un altre programa (un worker) el que se n'encarrega de fer l'enviament. La combinació de Celery+Redis ens pot anar bé, però també estam afegint un factor gran de complexitat: hem de tenir Redis instal·lat, configurar adequadament Celery i mantenir els workers actius amb supervisor.

Encara que el sistema de coes possiblement sigui l'opció millor per sistemes amb molta càrrega, s'ha d'avaluar bé si per la nostra aplicació convé complicar-nos tant la vida. Quan més peces posem més complexitat, més punts a gestionar, i la simplicitat importa. Si la nostra aplicació creix Django té prou flexibilitat per permetre'ns anar separant capes, afegir les coes, ...

Una solució a tots aquests problemes i escenaris, que a més és prou simple és la de guardar els correus que s'han d'enviar dins una taula de la base de dades i executar un procés cron per fer els enviaments. Això allibera ràpidament a la nostra aplicació web i no té la complexitat de manteniment d'un sistema de coes dedicat.

Com que el cron ho gestionam nosaltres, en preproducció podem dir que no s'executi, i els correus queden dins la base de dades i els podem veure sense cap problema sense fer un enviament real. Si hem de mantenir registre del que s'han enviat doncs també ho tenim.

Això no vol dir que aquest sistema no tengui mancances: si generam molts correus per segon el nostre coll d'ampolla serà la base de dades, però també és veritat que si enviam tal quantitat de correus, llavors sí que potser convé complicar-nos un poc més amb l'arquitectura de l'aplicació.

Dit això uns present django-mailer2. Al link he posat el fork que fem servir a APSL ja que ens hem trobat amb alguns problemes relacionats amb l'unicode que hem resolt i també amb la necessitat de poder visualitzar els e-mails amb adjunts. Així que es va fer un fork del fork i el fem servir a l'espera que l'autor del fork original ens admeti el codi nou, i ja posats vam generar la documentació per posar-la online a readthedocs.

django-mailer2 actua com a backend de Django, per la qualcosa una vegada instal·lada l'aplicació i posada als nostres settings.py hem de configurar el backend per a que quedi com

EMAIL_BACKEND = ‘django_mailer.smtp_queue.EmailBackend’

i farem un syncdb per crear les taules que necessitam a la base de dades.

A partir d'aquest moment els correus que enviem quedaran a la base de dades de django-mailer i no sortiran fins que executem la comanda

python manage.py send_mail

que és el que normalment posarem al cron.

Podem interactuar amb la prioritat d'enviament amb la capçalera

{‘X-Mail-Queue-Priority’: ‘<value>’}

on <value> pot prender els valor:

  • now per no posar-ho a la coa i enviar-lo immediatament.
  • normal prioritat per defecte
  • low prioritat baixa. Sortiran els darrers.

Si fem servir django-mailviews fixau-vos que seria prou senzill fer una classe base que abans d'enviar el correu li posàs la prioritat desitjada, afagint aquest paràmetre als headers.

Per mi aquesta aplicació ha estat un dels factors de productivitat més grans dels darrers mesos. Potser perquè les nostres aplicacions han d'enviar avisos amb adjunts i correus formatejats en HTML, és veritat, però poder mantenir el registre del que s'ha enviat i a l'entorn de preproducció despreoucupar-nos de maldecaps de si s'enviarà el correu sense voler o no és una meravella.

Epíleg

Amb això acab aquesta sèrie d'apunts sobre l'enviament de correus electrònics i Django. Esper que us hagi agradat llegir-los tant com a mi m'ha agradat escriure'ls.

La idea, com sempre, és compartir un poc les troballes que un va fent al llarg del temps. Pensau però que no hi ha veritats absolutes, potser per la vostra aplicació el que he contat per aquí no s'aplicarà, o demà sortirà una manera millor de fer les coses. Si això passa no deixeu d'avisar!

blog comments powered by Disqus