django

Django DB Mailer — простая и удобная батарейка, для отправки почтовых сообщений в вашем проекте

  • четверг, 19 марта 2015 г. в 02:10:52
http://habrahabr.ru/post/253445/

В подавляющем большинстве проектов используется отправка сообщений на почтовые адреса клиентов/админов/отделов. На сколько утомительно каждый раз создавать шаблоны на файловой системе, задавать сигналы, использовать часто дублирующийся код для рендеринга и отправки.

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

В больших проектах часто необходимо визуально разделять шаблоны на категории, для фильтрации, дабы не тратить время на редактирование менее важных шаблонов при рефакторинге, и во избежание путаницы с новым контентом, или при работе со старым.

Для подобных решений существует простая батарейка, призванная решить большинство подобных проблем, и избавить Вас от лишнего кода, сопровождения и нервотрепки.



django-db-mailer — открытая и простая в использовании батарейка, для отправки почтовых сообщений, рассылок и отложенных уведомлений. Не требует особых знаний или нестандартных настроек. Вам всего лишь необходимо установить пакет, настроить систему очередей Celery в связке с Redis, и можно начинать заниматься творческой работой.

Что же умеет батарейка из коробки?


1. Простой и удобный функциональный интерфейс, для отправки писем.
2. Работа в указанной очереди (необходимо когда в проекте все разбито на разные сервера и воркеры).
3. Возможность переотправки сообщения в случае неудачи (есть возможность задать кол-во попыток в БД и в коде).
4. Таймауты
5. Логирование (вы всегда можете посмотреть какие сообщение были отправлены удачно/неудачно. полезно при расследовании жалоб от пользователей).
6. Категории (быстрая фильтрация разнородных шаблонов. каталогизация по аппам и тд и тп).
7. Группы получателей (удобно для разделения на отделы внутри компании и задание адресов получателей в админке).
8. Сигналы (отправка сообщений по событию post_save/pre_save & etc. настраивается прямо в админке).
9. Отложенная отправка сообщений (хорошо для всяких промо, а так же при использовании транзакций во вьюхах).
10. Встроенный браузер полей в моделях (не нужно лезть в код, что бы просмотреть доступные для использования поля. не дрегают вас, и вы сами не лезите в код).
11. Система приоритизации (возможность задать приоритет сообщению в БД/Коде).
12. Редактирование шаблонов прямо в админке (для саппорта, менеджеров — самое оно. не отнимает время программиста).
13. Шаблоны кешируются — при каждой отправке сообщения нет обращений к БД (шаблоны и настройки читаются из кеша, что снижает нагрузку на БД. Бекенд на Ваш вкус).
14. Визуальный редактор TinyMCE (по желанию).
15. Версионирование изменений в шаблонах. Всегда можно откатиться (бывают случаи, когда без этого никак не обойтись).
16. Локализация батарейки Русский/English.
17. Тестирование сообщений прямо из админки (возможно создать шаблон и сразу же получить пример на почтовый ящик текущего пользователя).
18. Из коробки поддерживается популярная тема django-grappelli.
19. Типы письма html и text (возможность указания типа шаблона).
20. Возможность использовать все встроенные возможности мейлера джанги.
21. Bcc — можно дублировать все письма на указанные адреса (бывает полезно для логирования с текстом. по умолчанию тело письма не логируется в БД из соображений безопасности).
22. API — для совместной работы с приложениями на других языках/платформах.
23. Возможность задавать каждому шаблону поле «От» (полезно когда у Вас несколько отделов. особенно удобно при передаче обязанностей в другой отдел).
24. SMTP настройки для адресатов (можно настраивать различные smtp сервера для отправки писем).
25. Прикрепление стандартных файлов (различные вкладыши, документы, инструкции прямо в админке).
26. Мультиязычность шаблонов для локализированных сайтов (один шаблон для мультиязычных сайтов. в зависимости от локали, выбирается язык сообщения).
27. Отключение/Включение оповещений (удобно для дебага, или для временного отключения каких-то промо акций компании).
28. Простая интеграция с такими популярными сервисами как postmark (всего лишь нужно установить python-postmark).
29. Отлов и сортировка по исключениям Python (в случае использовании постмарка, или чего-нибудь еще — удобно отфильтровать и оперативно решить проблему).
30. Просмотр различий между версиями (всегда необходимо видеть кто и что менял в шаблонах, и какова причина ошибки).
31. Отчетность по прочитанным пользователями письмам (включая информацию о geo. но здесь нет никаких гарантий).

Возможности батарейки тесно связаны с Celery и Redis. Точнее — это фоновая отправка, очередь, приоритеты и отложенная отправка.

Хотя большая часть функционала работает и без них. То есть можно пользоваться батарейкой и без каких-либо внешних зависимостей.

Это уже на усмотрение программиста. Сложностей в настройке тех, или иных частей — не составляет проблем. Есть подробная документация.

Вместо Redis можно использовать RabbitMQ, MongoDB и все поддерживаемые Celery бекенды.
К сожалению, в Сelery приоритеты реализованы лишь для Redis. В основе quasi-priorities (не на стороне сервера).

Давайте рассмотрим простой пример для отправки сообщения:

    from dbmail import send_db_mail

    # данные контекста
    settings = Settings.objects.get(user_id=1)
    user = User.objects.get(pk=1)
    data = {'path': request.path}

    # отправка простого сообщения
    send_db_mail('welcome-notification', user.email, settings, user, data)

    # отправка сообщения с вложенным файлом
    send_db_mail('daily-report', user.email, user, data, files=[report_file])

В данном случае мы задаем идентификатор сообщения, указываем получателя, и передаем в контекст 2 модели, которые автоматически распаковываются в шаблоне + словарь.

Мы можем обратиться к полям модели User в шаблоне как к username или email. Но так же остается возможность обратиться к ним в общепринятом виде: user.username.

Более развернутый пример:

    send_db_mail(
        # идентификатор шаблона в БД
        slug='welcome',

        # получатели могут быть списком или строкой. Например:
        # 'user1@example.com' или 'user1@example.com, user2@example.com', или
        # ['user1@example.com', 'user2@example.com'], или же идентификатор
        # модели группы MailGroup. Например: developers, support, admins
        recipient='user1@example.com',

        # Все параметры *args доступны в качестве контекста в шаблоне
        {
            'username': request.user.username,
            'full_name': request.user.get_full_name(),
            'signup_date': request.user.date_joined
        },

        # Если передается модель в контекст, вы получаете доступ ко всем
        # распакованным полям.
        # Для m2m и fk, необходимо обращаться по module_name (mymodel.user.email).
        MyModel.objects.get(pk=1),

        # Необязательные дополнительные параметры **kwargs:
        # from_email='from@example.com' # от кого
        # cc=['cc@example.com'],        # копия (надстройки те же, что и для recipient)
        # bcc=['bcc@example.com'],      # скрытая копия (надстройки те же, что и для recipient)
        # user=User.objects.get(pk=1),  # пользователь, для логирования в БД
        #
        # Описание данных опций доступны в официальной доке к Django
        # attachments=[(filename, content, mimetype)],
        # files=['hello.jpg', 'world.png'],
        # headers={'Custom-Header':'Some value'},
        #
        # queue='default',              # очередь
        # retry_delay=300,              # время до повторной отправки в случае неудачи
        # max_retries=3,                # максимальное кол-во попыток для переотправки
        # retry=True,                   # разрешить попытку для переотправки
        # time_limit=30,                # максимальное кол-во времени для отправки
        # send_after=60,                # отправить письмо через N секунд
        #
        # use_celery=True,              # использовать Celery
        #
        # Здесь могут быть любые дополнительные опции доступные в django.core.mail.message
    )

Установка Демо проекта:


    $ sudo apt-get install -y virtualenvwrapper redis-server || brew install pyenv-virtualenvwrapper redis
    $ source /usr/share/virtualenvwrapper/virtualenvwrapper.sh || source /usr/local/bin/virtualenvwrapper.sh
    $ mkvirtualenv db-mailer
    $ workon db-mailer
    $ git clone --depth 1 https://github.com/LPgenerator/django-db-mailer.git db-mailer
    $ cd db-mailer
    $ python setup.py develop
    $ cd demo
    $ pip install -r requirements.txt
    $ python manage.py syncdb --noinput
    $ python manage.py migrate --noinput
    $ python manage.py createsuperuser --username admin --email admin@local.host
    $ python manage.py runserver >& /dev/null &
    $ python manage.py celeryd -Q default >& /dev/null &

Запустим shell:

    $ python manage.py shell_plus --print-sql

Создадим наш первый шаблон:

>>> from dbmail.models import MailTemplate
>>> from dbmail import send_db_mail
>>>
>>> MailTemplate.objects.create(
...     name="Site welcome template",
...     subject="Welcome",
...     message="Welcome to our site. We are glad to see you.",
...     slug="welcome",
...     is_html=False,
... )

Отправим письмо:

>>> send_db_mail('welcome', 'user@example.com', use_celery=False)

В первый раз в консоль будут выведены все запросы к БД, а так же само письмо. Во второй раз запросы к БД будут отсутствовать. Только запросы на запись в лог.

Проверим что у нас в логах:

>>> from pprint import pprint
>>> from django.forms.models import model_to_dict
>>> from dbmail.models import MailLog
>>>
>>> pprint([model_to_dict(obj) for obj in MailLog.objects.all()])

Теперь можно заглянуть в админку:

    $ xdg-open http://127.0.0.1:8000/admin/dbmail/ >& /dev/null || open http://127.0.0.1:8000/admin/dbmail/ >& /dev/null

Дополнительные возможности:


История
Для сохранения истории изменений/отката, можно установить батарейку django-reversion.

Редактор
Для того что бы редактировать шаблоны в визуальном редакторе, можно поставить батарейку django-tinymce.

Темы
django-db-mailer — поддерживает как нативную тему, так и django-grappelli.

Очереди
Для отправки сообщений в фоне с поддержкой приоритетов, необходима батарейка django-celery.

Мультиязычность
Мультиязычность возможна в связке с django-modeltranslation.

Преобразование CSS
Для преобразования и использования строчного CSS, можно доустановить пакет premailer. Маленький, но полезный помощник для создания кросс-клиентских сообщений.

Отчеты
Отчеты о прочтении и информацию о данных пользователя можно получить установив 2 простые батарейки httpagentparser и django-ipware.

Примечания
Для того что бы работала приоритезация, необходима связка django-celery с брокером Redis.

Старые версии
Если Вам не нужен весь функционал, Вы можете использовать более простую версию батарейки.
Так же можно воспользоваться переменной DB_MAILER_ALLOWED_MODELS_ON_ADMIN, для отключения ненужного функционала в панели администратора.

API
Вы так же можете использовать батарейку в связке с мобильным приложением, либо во внутренних проектах на других языках.

Простой пример:

>>> from dbmail.models import ApiKey
>>> ApiKey.objects.create(name='Test', api_key='ZzriUzE')

    $ curl -X POST http://127.0.0.1:8000/dbmail/api/ --data 'api_key=ZzriUzE&slug=welcome&recipient=root@local.host'

Поддержка Django начиная с ветки 1.4 по 1.7. Python 3 на текущий момент еще не поддерживается.

Скриншоты















Данная батарейка используется в нескольких больших проектах, и сберегла много времени и нервов.
Надеюсь она будет полезна сообществу Django.

Репозиторий проекта на GitHub.

Pull Request-ы приветствуются.