mirror of
https://github.com/pretix/pretix.git
synced 2026-05-04 15:04:03 +00:00
* Custom HTML email renderers * Move inline_css call * Small fixes * New HTML mail style for pretix * Thumbs * Inlinestyle for notifications * Documentation * Set line-height
138 lines
4.6 KiB
Python
138 lines
4.6 KiB
Python
import logging
|
|
from smtplib import SMTPRecipientsRefused, SMTPSenderRefused
|
|
|
|
import bleach
|
|
import markdown
|
|
from django.conf import settings
|
|
from django.core.mail.backends.smtp import EmailBackend
|
|
from django.dispatch import receiver
|
|
from django.template.loader import get_template
|
|
from django.utils.translation import ugettext_lazy as _
|
|
from inlinestyler.utils import inline_css
|
|
|
|
from pretix.base.models import Event, Order
|
|
from pretix.base.signals import register_html_mail_renderers
|
|
from pretix.base.templatetags.rich_text import markdown_compile
|
|
|
|
logger = logging.getLogger('pretix.base.email')
|
|
|
|
|
|
class CustomSMTPBackend(EmailBackend):
|
|
|
|
def test(self, from_addr):
|
|
try:
|
|
self.open()
|
|
self.connection.ehlo_or_helo_if_needed()
|
|
self.connection.rcpt("test@example.org")
|
|
(code, resp) = self.connection.mail(from_addr, [])
|
|
if code != 250:
|
|
logger.warn('Error testing mail settings, code %d, resp: %s' % (code, resp))
|
|
raise SMTPSenderRefused(code, resp, from_addr)
|
|
senderrs = {}
|
|
(code, resp) = self.connection.rcpt('test@example.com')
|
|
if (code != 250) and (code != 251):
|
|
logger.warn('Error testing mail settings, code %d, resp: %s' % (code, resp))
|
|
raise SMTPRecipientsRefused(senderrs)
|
|
finally:
|
|
self.close()
|
|
|
|
|
|
class BaseHTMLMailRenderer:
|
|
"""
|
|
This is the base class for all HTML e-mail renderers.
|
|
"""
|
|
|
|
def __init__(self, event: Event):
|
|
self.event = event
|
|
|
|
def __str__(self):
|
|
return self.identifier
|
|
|
|
def render(self, plain_body: str, plain_signature: str, subject: str, order: Order=None) -> str:
|
|
"""
|
|
This method should generate the HTML part of the email.
|
|
|
|
:param plain_body: The body of the email in plain text.
|
|
:param plain_signature: The signature with event organizer contact details in plain text.
|
|
:param subject: The email subject.
|
|
:param order: The order if this email is connected to one, otherwise ``None``.
|
|
:return: An HTML string
|
|
"""
|
|
raise NotImplementedError()
|
|
|
|
@property
|
|
def verbose_name(self) -> str:
|
|
"""
|
|
A human-readable name for this renderer. This should be short but self-explanatory.
|
|
"""
|
|
raise NotImplementedError() # NOQA
|
|
|
|
@property
|
|
def identifier(self) -> str:
|
|
"""
|
|
A short and unique identifier for this renderer.
|
|
This should only contain lowercase letters and in most cases will be the same as your package name or prefixed
|
|
with your package name.
|
|
"""
|
|
raise NotImplementedError() # NOQA
|
|
|
|
@property
|
|
def thumbnail_filename(self) -> str:
|
|
"""
|
|
A file name discoverable in the static file storage that contains a preview of your renderer. This should
|
|
be with aspect resolution 4:3.
|
|
"""
|
|
raise NotImplementedError() # NOQA
|
|
|
|
@property
|
|
def is_available(self) -> bool:
|
|
"""
|
|
This renderer will only be available if this returns ``True``. You can use this to limit this renderer
|
|
to certain events. Defaults to ``True``.
|
|
"""
|
|
return True
|
|
|
|
|
|
class TemplateBasedMailRenderer(BaseHTMLMailRenderer):
|
|
|
|
@property
|
|
def template_name(self):
|
|
raise NotImplemented
|
|
|
|
def render(self, plain_body: str, plain_signature: str, subject: str, order: Order) -> str:
|
|
body_md = bleach.linkify(markdown_compile(plain_body))
|
|
htmlctx = {
|
|
'site': settings.PRETIX_INSTANCE_NAME,
|
|
'site_url': settings.SITE_URL,
|
|
'body': body_md,
|
|
'subject': str(subject),
|
|
'color': '#8E44B3'
|
|
}
|
|
if self.event:
|
|
htmlctx['event'] = self.event
|
|
htmlctx['color'] = self.event.settings.primary_color
|
|
|
|
if plain_signature:
|
|
signature_md = plain_signature.replace('\n', '<br>\n')
|
|
signature_md = bleach.linkify(bleach.clean(markdown.markdown(signature_md), tags=bleach.ALLOWED_TAGS + ['p', 'br']))
|
|
htmlctx['signature'] = signature_md
|
|
|
|
if order:
|
|
htmlctx['order'] = order
|
|
|
|
tpl = get_template(self.template_name)
|
|
body_html = inline_css(tpl.render(htmlctx))
|
|
return body_html
|
|
|
|
|
|
class ClassicMailRenderer(TemplateBasedMailRenderer):
|
|
verbose_name = _('pretix default')
|
|
identifier = 'classic'
|
|
thumbnail_filename = 'pretixbase/email/thumb.png'
|
|
template_name = 'pretixbase/email/plainwrapper.html'
|
|
|
|
|
|
@receiver(register_html_mail_renderers, dispatch_uid="pretixbase_email_renderers")
|
|
def base_renderers(sender, **kwargs):
|
|
return [ClassicMailRenderer]
|