Трансуляционные электронные письма являются важным способом сохранения пользователей, когда вы строите общественный сайт, как Фактеруид Отказ Это импорт, чтобы обратить внимание на детали, чтобы пользователи могли нажать на них и возвращаться.
К сожалению, разработка работа по электронной почте немного рутина. Вы должны либо засорять ваш почтовый ящик с помощью тестовых электронных писем для тестирования каждого небольшого изменения или в лучшем случае настроить еще одно неловкое решение, чтобы открыть их в браузере. ограничительные требования к HTML больно работать, особенно необходимость использования встроенных стилей.
Я построил какую-то простую инфраструктуру, чтобы сделать рабочий процесс разработки электронной почты намного проще. Я построил Фактеруид В Джангу, но основные идеи должны обратиться к любой платформе.
Основная настройка
Отправка отформатированной электронной почты означает генерацию трех строк: тема, тело HTML и простой текстовый корпус. Наиболее очевидный способ сделать это – выйти на каждую часть в своем собственном шаблоне (скажем, Woment_email_subject.txt, welcent_email_plain.txt, wellow_email_html.txt) и использование Render_to_String. Это может потребоваться немного раздражать для управления, потому что у вас есть три отдельных файла для редактирования и сохранения синхронизации.
Почему бы не использовать Блоки ? Django-Render-Block Пакет идеально подходит для этого. Это дает вам Render_block_to_string
Функция, которая работает так же, как Render_to_String, но дает вам содержимое определенного блока. Все, что вам нужно сделать сейчас, определяют один шаблон с отдельными блоками для трех частей.
Давайте инкапсулируем, что в классе
class Email: template = "emails/base.html" from_email = settings.DEFAULT_FROM_EMAIL def __init__(self, ctx, to_email): self.to_email = to_email self.subject = render_block_to_string(self.template, 'subject', ctx) self.plain = render_block_to_string(self.template, 'plain', ctx) self.body = render_block_to_string(self.template, 'html', ctx) def send(self): send_mail(self.subject, self.plain, self.from_email, [self.to_email], html_message=self.html)
{% block subject %}Welcome to Facteroid{% endblock %} {% block plain %}Hi, This is an example email. Thanks, - The Facteroid Team {% endblock %} {% block html %}Hi,
This is an example email.
Thanks,
The Facteroid Team
{% endblock %}
Все, что нам нужно сделать сейчас, это создать шаблон, который расширяет base.html и переопределить Шаблон
В детском классе Электронное письмо
И мы на нашем пути. Конечно, HTML и тело для этого, скорее всего, будет намного больше, чем это, с большим количеством котельной. На самом деле, стандартный способ структурирования HTML электронных писем включает в себя Две вложенные столы Со всем контентом, входящим в одну ячейку внутреннего стола. Было бы довольно расточительно, чтобы продолжать повторять это. Конечно, мы можем приятно использовать наследство шаблона, чтобы избежать этого.
{% block subject %}{% endblock %} {% block plain %}{% endblock %} {% block html %}
|
Вы все еще можете наследовать от Base.html, но вам не нужно переопределить все HTML
Большую часть времени вы можете просто переопределить html_main
Блок и напишите намного более простой документ.
Хотя мы высыхаем вещи, почему бы не генерировать простое тело от HTML-адреса? Мы всегда можем указать один вручную для самых важных электронных писем, но сгенерированное тело должно быть достаточно хорошо в большинстве случаев. HTML2Text в помощь.
class Email: template = "emails/base.html" from_email = settings.DEFAULT_FROM_EMAIL def __init__(self, ctx, to_email): self.to_email = to_email self.subject = render_block_to_string(self.template, 'subject', ctx) self.plain = render_block_to_string(self.template, 'plain', ctx) self.body = render_block_to_string(self.template, 'html', ctx) if self.plain == "": h = HTML2Text() h.ignore_images = True h.ignore_emphasis = True h.ignore_tables = True self.plain = h.handle(self.html) def send(self): send_mail(self.subject, self.plain, self.from_email, [self.to_email], html_message=self.html)
Это довольно распространено для электронного письма, чтобы взять Пользователь
Объект и представить некоторую информацию от связанных объектов. Вы также хотите облегчить пользователям отписаться от конкретных типов электронных писем. Те, кто обрабатывается с логическими полями в пользователе Профиль
Отказ Давайте инкапсулируем это.
class UserEmail(Email): unsubscribe_field = None def __init__(self, ctx, user): if self.unsubscribe_field is None: raise ProgrammingError("Derived class must set unsubscribe_field") self.user = user ctx = { 'user': user, 'unsubscribe_link': user.profile.unsubscribe_link(self.unsubscribe_field) **ctx } super().__init__(ctx, user.email) def send(self): if getattr(self.user.profile, self.unsubscribe_field): super().send() class NotificationEmail(UserEmail): template = 'emails/notification_email.html' unsubscribe_field = 'notification_emails' def __init__(self, user): ctx = { 'notifications': user.notifications.filter(seen=False) } super().__init__(ctx, user)
Просмотр писем в браузере
Теперь довольно легко написать представление для предварительного просмотра электронной почты в браузере с очень небольшими усилиями.
# user_emails/views.py @staff_member_required def preview_email(request): email_types = { 'email_confirmation': ConfirmationEmail, 'notification': NotificationEmail, 'welcome': WelcomeEmail, } email_type = request.GET.get('type') if email_type not in email_types: return HttpResponseBadRequest("Invalid email type") if 'user_id' in request.GET: user = get_object_or_404(User, request.GET['user_id']) else: user = request.user email = email_types[email_type](user) if request.GET.get('plain'): text = "Subject: %s\n\n%s" % (email.subject, email.plain) return HttpResponse(text, content_type='text/plain') else: # Insert a table with metadata like Subject, To etc. to top of body extra = render_to_string('user_email/metadata.html', {'email': email}) soup = BeautifulSoup(email.html) soup.body.insert(0, BeautifulSoup(extra)) return HttpResponse(soup.encode())
Теперь я могу легко просмотреть электронные письма в браузере. Я также использую Django-Live-Reload В разработке, поэтому я могу редактировать шаблонные файлы и код и мгновенно видеть эффект в окне браузера без необходимости перезагрузки страницы.
Держать Sane CSS
Еще одна вещь, которая делает разработку HTML Emails больно, это необходимость использования встроенных стилей. В отличие от обычных веб-страниц, вы не можете просто иметь блок стиля и полагаться на агентов пользователей, чтобы правильно сделать их. Вам действительно нужно поставить Стиль = "..."
Атрибуты на каждом элементе, который вы хотите стиль, что делает самую простой вещь, как «сделать все мои ссылки светло-синие и удалить подчеркивание» довольно болезненно.
Я сделал это легче с небольшим количеством Пользовательский шаблон тег который читает стили из внешнего файла и выплевывает Стиль
атрибут. Я мог бы просто определить стили в словаре, но с небольшим количеством помощи Cssutils Может держать его в файле .css, который делает его хорошо играть с редакторами кода поэтому я получаю правильный синтаксис, автозаполнение и т. Д.
# user_email/templatetags/email_tags.py _styles = None @register.simple_tag() def style(names): global _styles if _styles is None or settings.DEBUG: _load_styles() style = ';'.join(_styles.get(name, '') for name in names.split()) return mark_safe(% style) def _load_styles(): global _styles _styles = {} sheet = cssutils.parseFile(finders.find('user_email/email_styles.css')) for rule in sheet.cssRules: for selector in rule.selectorList: _styles[selector.selectorText] = rule.style.cssText
Теперь в моих HTML-файлах все, что мне нужно сделать, это это:
{% extends 'email/base.html' %} {% load email_tags %} {% block html_main %}Hello {{user.profile.display_name}},
Thanks for signing up! Here's an article to help you get started.
{% endblock %}
Вывод
Я выделил некоторый из этого примера, чтобы сделать его проще, но у меня есть все виды дополнительных функциональных возможностей, которые можно легко добавлять с помощью этой базы.
-
Email
Базовый класс анализирует электронную почту и автоматически добавляет базовый URL к любым относительным ссылкам. -
Отправить
Функция записывает журнал отправленных электронных писем в базе данных и звонитAfter_send
Метод, если он существует.After_send
Функция в некоторых классах электронной почты занимается домашними задачами, как запись, какие уведомления уже были отправлены пользователю. - Функция My View немного сложнее, поэтому я могу просмотреть электронные письма, которые принимают больше, чем просто пользователь (но он строит по той же идее).
Я приветствую любые комментарии, предложения или вопросы!
Оригинал: “https://dev.to/vinaypai/django-transactional-emails-made-easy-1pf1”