Сообщить об ошибке.

Отправка писем из приложения Flask в Python

Расширение Flask-Mail предоставляет простой интерфейс для настройки SMTP с приложением Flask и для отправки сообщений из представлений и сценариев.

Установка модуля Flask-Mail в виртуальное окружение.

# создаем виртуальное окружение, если нет
$ python3 -m venv .venv --prompt VirtualEnv
# активируем виртуальное окружение 
$ source .venv/bin/activate
# обновляем `pip`
(VirtualEnv):~$ python3 -m pip install -U pip
# ставим расширение `Flask-Mail`
(VirtualEnv):~$ python3 -m pip install -U Flask-Mail

Содержание:


Добавление модуля Flask-Mail в приложение Flask.

Электронная почта управляется через экземпляр Mail:

from flask import Flask
# импортируем класс `Mail`
# из расширения Flask-Mail
from flask_mail import Mail

app = Flask(__name__)
# создаем и настраиваем 
# экземпляр `Mail`
mail = Mail(app)

# настраиваем конфигурацию по умолчанию 
app.config['MAIL_SERVER'] = smtp.mail.ru

В этом случае все электронные письма будут отправляться с использованием значений конфигурации, которые класс Mail() будет читать из словаря app.config.

В качестве альтернативы можно настроить свой экземпляр Mail позже во время настройки, используя метод mail.init_app:

from flask import Flask
from flask_mail import Mail
# создаем экземпляр `Mail` 
mail = Mail()

app = Flask(__name__)
# настраиваем экземпляр `Mail`
mail.init_app(app)

В этом случае электронные письма будут отправляться с использованием значений конфигурации из глобального контекста текущего приложения Flask current_app. Это полезно, если Flask обслуживает фабрику веб-приложений, которые работают в одном процессе, но с разными параметрами конфигурации.

Доступные параметры конфигурации Flask-Mail.

Flask-Mail настраивается через стандартный API конфигурации Flask. Ниже приводятся доступные параметры:

  • MAIL_SERVER: по умолчанию "localhost",
  • MAIL_PORT: по умолчанию 25,
  • MAIL_USE_TLS: по умолчанию False,
  • MAIL_USE_SSL: по умолчанию False,
  • MAIL_DEBUG: по умолчанию app.debug,
  • MAIL_USERNAME: по умолчанию None,
  • MAIL_PASSWORD: по умолчанию None,
  • MAIL_DEFAULT_SENDER: по умолчанию None,
  • MAIL_MAX_EMAILS: по умолчанию None,
  • MAIL_SUPPRESS_SEND: по умолчанию app.testing,
  • MAIL_ASCII_ATTACHMENTS: по умолчанию False.

Кроме того, в модульных тестах Flask-Mail использует стандартный параметр конфигурации Flask TESTING.

Отправка письма/сообщения из приложения Flask.

Для отправки письма/сообщения, необходимо сначала создать экземпляр Message:

from flask_mail import Message

@app.route("/")
def index():
    msg = Message("Hello",
                  sender="from@example.com",
                  recipients=["to@example.com"])

Параметры письма/сообщения можно задать сразу в конструкторе Message(), так с помощью методов экземпляра Message:

msg.recipients = ["you@example.com"]
msg.add_recipient("somebodyelse@example.com")

Если при инициализации экземпляра Flask-Mail был установлен параметр конфигурации по умолчанию MAIL_DEFAULT_SENDER, то не надо явно указывать отправителя сообщения sender, так как будет использоваться значение конфигурации по умолчанию:

msg = Message("Hello",
              recipients=["to@example.com"])

Если отправитель представляет собой кортеж из двух элементов, то он будет разделен на имя и адрес:

msg = Message("Hello",
              sender=("Me", "me@example.com"))

assert msg.sender == "Me <me@example.com>"

Сообщение может содержать тело body и/или HTML html:

msg.body = "testing"
msg.html = "<b>testing</b>"

Наконец, чтобы отправить сообщение, используется экземпляр Mail, настроенный с приложением Flask:

mail.send(msg)

Массовая рассылка сообщений подписчикам при помощи Flask-Mail.

Обычно в веб-приложении необходимо отправлять одно или два электронных письма на запрос. В определенных ситуациях может потребоваться возможность отправлять десятки или сотни электронных писем (сделать рассылку подписчикам), например во внешнем процессе, при помощи командной строки или cronjob.

В этом случае необходимо делаете что-то немного по-другому:

with mail.connect() as conn:
    for user in users:
        message = '...'
        subject = f"hello, {user.name}"
        msg = Message(recipients=[user.email],
                      body=message,
                      subject=subject)

        conn.send(msg)

Соединение с почтовым хостом сохраняется и закрывается автоматически после отправки всех сообщений.

Некоторые почтовые серверы устанавливают ограничение на количество писем, отправляемых за одно соединение. Что бы установить максимальное количестве писем для отправки перед повторным подключением, необходимо указать параметр MAIL_MAX_EMAILS.

Добавление вложений attachments в письмо/сообщение.

Добавить вложения очень просто:

with app.open_resource("image.png") as fp:
    msg.attach("image.png", "image/png", fp.read())

Если для параметра конфигурации MAIL_ASCII_ATTACHMENTS установлено значение True, то имена файлов будут преобразованы в эквивалент ASCII. Это может быть полезно при использовании почтового ретранслятора, который изменяет содержимое почты и искажает спецификацию Content-Disposition, когда имена файлов имеют кодировку UTF-8. Преобразование в ASCII представляет собой базовое удаление символов, отличных от ASCII. Это должно подойти для любого символа Юникода, который может быть разложен NFKD на один или несколько символов ASCII. Если нужна транслитерация (т.е. ß → ss), то приложение Flask должно сделать это само, например при помощи модуля unidecode или transliterate и передать правильную строку ASCII.

Подавление отправки электронных писем при разработке и тестировании.

В среде разработки или при тестировании полезно иметь возможность подавлять отправку электронной почты. Если для параметра конфигурации TESTING установлено значение True, сообщения электронной почты будут подавляться. Вызов метода Mail.send() не приведет к фактической отправке каких-либо сообщений.

В качестве альтернативы, вне среды тестирования, можно установить для MAIL_SUPPRESS_SEND значение False, что будет иметь тот же эффект.

Тем не менее, по-прежнему полезно отслеживать электронные письма, которые были бы отправлены. Чтобы отслеживать отправленные электронные письма, нужно использовать метод Mail.record_messages():

with mail.record_messages() as outbox:
    mail.send_message(subject='testing',
                      body='test',
                      recipients=emails)
    assert len(outbox) == 1
    assert outbox[0].subject == "testing"

Экземпляр outbox это список отправленных сообщений. Для работы этого метода должен быть установлен сторонний модуль blinker.

Обратите внимание, что старый способ добавления исходящих сообщений к глобальному объекту Flask.g теперь устарел.

Логирование события отправки письма.

Расширение Flask-Mail поддерживает сигнал email_dispatched. Он отправляется всякий раз, когда отправляется электронное письмо (даже если электронное письмо фактически не отправляется, то есть в тестовой среде).

Функция, подключающаяся к сигналу email_dispatched, принимает экземпляр Message в качестве первого аргумента и экземпляр приложения Flask в качестве дополнительного аргумента:

from flask_mail import email_dispatched

def log_message(message, app):
    app.logger.debug(message.subject)

email_dispatched.connect(log_message)