Sendmail plugin: Allow to attach a file to emails (#1814)

* sendmail: allow to attach files to emails

* Fix mixup of model objects and model IDs

* Attach to order-level emails, not only position-level emails

* Give attachments a proper file type

* Add a warning note about higher spam chances

Co-authored-by: Raphael Michel <mail@raphaelmichel.de>
This commit is contained in:
Sohalt
2020-10-22 09:53:19 +02:00
committed by GitHub
parent d673a43130
commit 9e4dc344a4
5 changed files with 51 additions and 18 deletions

View File

@@ -7,6 +7,7 @@ from i18nfield.forms import I18nFormField, I18nTextarea, I18nTextInput
from pretix.base.email import get_available_placeholders
from pretix.base.forms import PlaceholderValidator
from pretix.base.models import CheckinList, Item, Order, SubEvent
from pretix.control.forms import ExtFileField
from pretix.control.forms.widgets import Select2, Select2Multiple
@@ -20,6 +21,18 @@ class MailForm(forms.Form):
sendto = forms.MultipleChoiceField() # overridden later
subject = forms.CharField(label=_("Subject"))
message = forms.CharField(label=_("Message"))
attachment = ExtFileField(
label=_("Attachment"),
required=False,
ext_whitelist=(
".png", ".jpg", ".gif", ".jpeg", ".pdf", ".txt", ".docx", ".gif", ".svg",
".pptx", ".ppt", ".doc", ".xlsx", ".xls", ".jfif", ".heic", ".heif", ".pages",
".bmp", ".tif", ".tiff"
),
help_text=_('Sending an attachment increases the chance of your email not arriving or being sorted into spam folders. We recommend only using PDFs '
'of no more than 2 MB in size.'),
max_size=10 * 1024 * 1024
) # TODO i18n
items = forms.ModelMultipleChoiceField(
widget=forms.CheckboxSelectMultiple(
attrs={'class': 'scrolling-multiple-choice'}

View File

@@ -10,7 +10,8 @@ from pretix.celery_app import app
@app.task(base=ProfiledEventTask, acks_late=True)
def send_mails(event: Event, user: int, subject: dict, message: dict, orders: list, items: list,
recipients: str, filter_checkins: bool, not_checked_in: bool, checkin_lists: list) -> None:
recipients: str, filter_checkins: bool, not_checked_in: bool, checkin_lists: list,
attachments: list = None) -> None:
failures = []
user = User.objects.get(pk=user) if user else None
orders = Order.objects.filter(pk__in=orders, event=event)
@@ -61,7 +62,8 @@ def send_mails(event: Event, user: int, subject: dict, message: dict, orders: li
event,
locale=o.locale,
order=o,
position=p
position=p,
attach_cached_files=attachments
)
o.log_action(
'pretix.plugins.sendmail.order.email.sent.attendee',
@@ -87,7 +89,8 @@ def send_mails(event: Event, user: int, subject: dict, message: dict, orders: li
email_context,
event,
locale=o.locale,
order=o
order=o,
attach_cached_files=attachments
)
o.log_action(
'pretix.plugins.sendmail.order.email.sent',

View File

@@ -5,7 +5,7 @@
{% block content %}
<h1>{% trans "Send out emails" %}</h1>
{% block inner %}
<form class="form-horizontal" method="post" action="">
<form class="form-horizontal" method="post" action="" enctype="multipart/form-data">
{% csrf_token %}
{% bootstrap_field form.recipients layout='horizontal' %}
{% bootstrap_field form.sendto layout='horizontal' %}
@@ -32,6 +32,7 @@
</div>
{% bootstrap_field form.subject layout='horizontal' %}
{% bootstrap_field form.message layout='horizontal' %}
{% bootstrap_field form.attachment layout='horizontal' %}
{% if request.method == "POST" %}
<fieldset>
<legend>{% trans "E-mail preview" %}</legend>

View File

@@ -1,4 +1,5 @@
import logging
from datetime import timedelta
import bleach
from django.contrib import messages
@@ -11,7 +12,7 @@ from django.views.generic import FormView, ListView
from pretix.base.email import get_available_placeholders
from pretix.base.i18n import LazyI18nString, language
from pretix.base.models import LogEntry, Order, OrderPosition
from pretix.base.models import CachedFile, LogEntry, Order, OrderPosition
from pretix.base.models.event import SubEvent
from pretix.base.services.mail import TolerantDict
from pretix.base.templatetags.rich_text import markdown_compile_email
@@ -136,19 +137,34 @@ class SenderView(EventPermissionRequiredMixin, FormView):
return self.get(self.request, *self.args, **self.kwargs)
attachment = None
if 'attachment' in self.request.FILES:
attachment = self.request.FILES['attachment']
cf = CachedFile.objects.create(
expires=now() + timedelta(days=1),
date=now(),
filename=attachment.name,
type=attachment.content_type,
)
cf.file.save(attachment.name, attachment.file)
cf.save()
kwargs = {
'recipients': form.cleaned_data['recipients'],
'event': self.request.event.pk,
'user': self.request.user.pk,
'subject': form.cleaned_data['subject'].data,
'message': form.cleaned_data['message'].data,
'orders': [o.pk for o in orders],
'items': [i.pk for i in form.cleaned_data.get('items')],
'not_checked_in': form.cleaned_data.get('not_checked_in'),
'checkin_lists': [i.pk for i in form.cleaned_data.get('checkin_lists')],
'filter_checkins': form.cleaned_data.get('filter_checkins'),
}
if attachment is not None:
kwargs['attachments'] = [cf.id]
send_mails.apply_async(
kwargs={
'recipients': form.cleaned_data['recipients'],
'event': self.request.event.pk,
'user': self.request.user.pk,
'subject': form.cleaned_data['subject'].data,
'message': form.cleaned_data['message'].data,
'orders': [o.pk for o in orders],
'items': [i.pk for i in form.cleaned_data.get('items')],
'not_checked_in': form.cleaned_data.get('not_checked_in'),
'checkin_lists': [i.pk for i in form.cleaned_data.get('checkin_lists')],
'filter_checkins': form.cleaned_data.get('filter_checkins'),
}
kwargs=kwargs
)
self.request.event.log_action('pretix.plugins.sendmail.sent',
user=self.request.user,