Home > flask, python > Flask (parte 7): mail

Flask (parte 7): mail

26 Agosto 2015

Per notificare un evento ad uno User, utilizzeremo il pacchetto Flask-Mail,
che integra in maniera efficiente smtplib con flask.
Per installarlo:

(venv) >pip install flask-mail

flask-mail consente di connetterci ad un SMTP server in modo da passargli
le mail e far sì che vengano spedite.
Con la configurazione di default, Flask-Mail si connette tramite la porta
25 a localhost e spedisce mail senza bisogno di autenticazione.
Le chiavi che permettono di configurare Flask-Mail sono:

MAIL_SERVER : default “localhost”
MAIL_PORT : default 25
MAIL_USE_TLS : default False
MAIL_USE_SSL : default False
MAIL_DEBUG : default app.debug
MAIL_USERNAME : default None
MAIL_PASSWORD : default None
MAIL_DEFAULT_SENDER : default None
MAIL_MAX_EMAILS : default None
MAIL_SUPPRESS_SEND : default app.testing
MAIL_ASCII_ATTACHMENTS : default False

Nel caso specifico della nostra applicazione, dovremo inizializzare Flask-Mail
in app.__init__.py, creando una istanza di Mail, che gestirà le emails:

from flask.ext.mail import Mail

...
mail = Mail()

def create_app(config_name):
    ...
    mail.init_app(app)
    ...

I valori di configurazione sono già stati settati nel file config.py e
prevedono di spedire mail tramite account di posta gmail:

...

class DevelopmentConfig(Config):
    DEBUG = True
    MAIL_SERVER = 'smtp.googlemail.com'
    MAIL_PORT = 587
    MAIL_USE_TLS = True
    MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
    MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
    ...

i valori “MAIL_USERNAME” e “MAIL_PASSWORD” vengono settati per motivi di privacy
nel seguente modo per linux:

(venv) $ export MAIL_USERNAME=<Gmail username>
(venv) $ export MAIL_PASSWORD=<Gmail password>

e nel seguente, per windows:

(venv) $ set MAIL_USERNAME=<Gmail username>
(venv) $ set MAIL_PASSWORD=<Gmail password>

In questo modo, le nostre credenziali non appariranno nel codice, ma verranno prelevate dal dizionario
os.environ direttamente:

    MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
    MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
(venv) >set [email protected]
(venv) >set MAIL_PASSWORD=pippo

(venv) >python manage.py shell

>>> import os
>>> os.environ.get("MAIL_USERNAME")
'[email protected]'
>>> os.environ.get("MAIL_PASSWORD")
'pippo'

ovviamente username e pw vanno sostituiti con qualcosa di esistente…
vediamo come mandare una mail dalla shell:

>>> import os
>>> from flask import Flask
>>> from flask_mail import Message
>>> from flask_mail import Mail
>>> app = Flask("test")
>>> mail = Mail(app)
>>> sender = os.environ.get("MAIL_USERNAME")
>>> sender
'[email protected]'
>>> recipients = [sender] # mi auto spedisco una mail!
>>> msg = Message("Test", sender=sender, recipients=recipients)
>>> msg.recipients
['[email protected]']
>>> msg.add_recipient("[email protected]") # per aggiungere destinatari...
>>> msg.recipients
['[email protected]', '[email protected]']
>>> msg.body = "text body"
>>> msg.html = "<b>HTML</b> body"
>>> with app.app_context():
...     mail.send(msg)
...

nota: il messaggio può avere un text body e/o uno html, pertanto li abbiamo aggiunti
entrambi.
Questo modo di mandare mail, non è comodissimo pertanto automatizziamo l’operazione di
spedizione mail, creando una funzione nell’apposito file app/email.py:

from threading import Thread
from flask import current_app, render_template
from flask.ext.mail import Message
from . import mail


def send_async_email(app, msg):
    with app.app_context():
        mail.send(msg)


def send_email(to, subject, template, **kwargs):
    app = current_app._get_current_object()
    msg = Message(app.config['FANTAMANAGER_MAIL_SUBJECT_PREFIX'] + ' ' + subject,
                  sender=app.config['FANTAMANAGER_MAIL_SENDER'], recipients=[to])
    msg.body = render_template(template + '.txt', **kwargs)
    msg.html = render_template(template + '.html', **kwargs)
    thr = Thread(target=send_async_email, args=[app, msg])
    thr.start()
    return thr

La funzione mail.send() blocca l’applicazione durante l’operazione di spedizione.
Per questo l’operazione stessa viene delegata ad un thread che lavora in background,
evitando che il browser e tutta l’applicazione rimangano in attesa.

La template che si occupa della mail risiede in app/auth/templates/auth/email/confirm.txt

Dear {{ user.username }},
Welcome to Fantamanager!

To confirm your account please click on the following link:
{{ url_for('auth.confirm', token=token, _external=True) }}

Sincerely,
The Fantamanager Admin
Note: replies to this email address are not monitored.

mentre il file html sarà:

<p>Dear {{ user.username }},</p>
<p>Welcome to <b>Fantamanager</b>!</p>

<p>To confirm your account please <a href=
    "{{ url_for('auth.confirm', token=token, _external=True) }}">click here</a>.</p>
<p>Alternatively, you can paste the following link in your browser's address bar:</p>
<p>{{ url_for('auth.confirm', token=token, _external=True) }}</p>

<p>Sincerely,</p>
<p>The Fantamanager Team</p>

<p><small>Note: replies to this email address are not monitored.</small></p>

articoli successivi:
Flask (parte 8): registrare un nuovo user

articoli precedenti:
Flask (parte 1): virtualenv
Flask (parte 2): struttura progetto complesso
Flask (parte 3): database
Flask (parte 4): views e templates
Flask (parte 5): password security
Flask (parte 6): authentication

link utili:
“Flask Web Development” di Miguel Grinberg, fondamentale per calarsi nel mondo di Flask.
Altri link fondamentali:
Flask sito ufficiale
il blog dell’autore (Flask mega tutorial)

Categorie:flask, python Tag: ,
I commenti sono chiusi.