forked from CGM_Public/pretix_original
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:
@@ -231,7 +231,7 @@ def mail(email: Union[str, Sequence[str]], subject: str, template: Union[str, La
|
|||||||
attach_tickets=attach_tickets,
|
attach_tickets=attach_tickets,
|
||||||
attach_ical=attach_ical,
|
attach_ical=attach_ical,
|
||||||
user=user.pk if user else None,
|
user=user.pk if user else None,
|
||||||
attach_cached_files=[cf.id for cf in attach_cached_files] if attach_cached_files else [],
|
attach_cached_files=[(cf.id if isinstance(cf, CachedFile) else cf) for cf in attach_cached_files] if attach_cached_files else [],
|
||||||
)
|
)
|
||||||
|
|
||||||
if invoices:
|
if invoices:
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from i18nfield.forms import I18nFormField, I18nTextarea, I18nTextInput
|
|||||||
from pretix.base.email import get_available_placeholders
|
from pretix.base.email import get_available_placeholders
|
||||||
from pretix.base.forms import PlaceholderValidator
|
from pretix.base.forms import PlaceholderValidator
|
||||||
from pretix.base.models import CheckinList, Item, Order, SubEvent
|
from pretix.base.models import CheckinList, Item, Order, SubEvent
|
||||||
|
from pretix.control.forms import ExtFileField
|
||||||
from pretix.control.forms.widgets import Select2, Select2Multiple
|
from pretix.control.forms.widgets import Select2, Select2Multiple
|
||||||
|
|
||||||
|
|
||||||
@@ -20,6 +21,18 @@ class MailForm(forms.Form):
|
|||||||
sendto = forms.MultipleChoiceField() # overridden later
|
sendto = forms.MultipleChoiceField() # overridden later
|
||||||
subject = forms.CharField(label=_("Subject"))
|
subject = forms.CharField(label=_("Subject"))
|
||||||
message = forms.CharField(label=_("Message"))
|
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(
|
items = forms.ModelMultipleChoiceField(
|
||||||
widget=forms.CheckboxSelectMultiple(
|
widget=forms.CheckboxSelectMultiple(
|
||||||
attrs={'class': 'scrolling-multiple-choice'}
|
attrs={'class': 'scrolling-multiple-choice'}
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ from pretix.celery_app import app
|
|||||||
|
|
||||||
@app.task(base=ProfiledEventTask, acks_late=True)
|
@app.task(base=ProfiledEventTask, acks_late=True)
|
||||||
def send_mails(event: Event, user: int, subject: dict, message: dict, orders: list, items: list,
|
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 = []
|
failures = []
|
||||||
user = User.objects.get(pk=user) if user else None
|
user = User.objects.get(pk=user) if user else None
|
||||||
orders = Order.objects.filter(pk__in=orders, event=event)
|
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,
|
event,
|
||||||
locale=o.locale,
|
locale=o.locale,
|
||||||
order=o,
|
order=o,
|
||||||
position=p
|
position=p,
|
||||||
|
attach_cached_files=attachments
|
||||||
)
|
)
|
||||||
o.log_action(
|
o.log_action(
|
||||||
'pretix.plugins.sendmail.order.email.sent.attendee',
|
'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,
|
email_context,
|
||||||
event,
|
event,
|
||||||
locale=o.locale,
|
locale=o.locale,
|
||||||
order=o
|
order=o,
|
||||||
|
attach_cached_files=attachments
|
||||||
)
|
)
|
||||||
o.log_action(
|
o.log_action(
|
||||||
'pretix.plugins.sendmail.order.email.sent',
|
'pretix.plugins.sendmail.order.email.sent',
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>{% trans "Send out emails" %}</h1>
|
<h1>{% trans "Send out emails" %}</h1>
|
||||||
{% block inner %}
|
{% block inner %}
|
||||||
<form class="form-horizontal" method="post" action="">
|
<form class="form-horizontal" method="post" action="" enctype="multipart/form-data">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% bootstrap_field form.recipients layout='horizontal' %}
|
{% bootstrap_field form.recipients layout='horizontal' %}
|
||||||
{% bootstrap_field form.sendto layout='horizontal' %}
|
{% bootstrap_field form.sendto layout='horizontal' %}
|
||||||
@@ -32,6 +32,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% bootstrap_field form.subject layout='horizontal' %}
|
{% bootstrap_field form.subject layout='horizontal' %}
|
||||||
{% bootstrap_field form.message layout='horizontal' %}
|
{% bootstrap_field form.message layout='horizontal' %}
|
||||||
|
{% bootstrap_field form.attachment layout='horizontal' %}
|
||||||
{% if request.method == "POST" %}
|
{% if request.method == "POST" %}
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{% trans "E-mail preview" %}</legend>
|
<legend>{% trans "E-mail preview" %}</legend>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import logging
|
import logging
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
import bleach
|
import bleach
|
||||||
from django.contrib import messages
|
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.email import get_available_placeholders
|
||||||
from pretix.base.i18n import LazyI18nString, language
|
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.models.event import SubEvent
|
||||||
from pretix.base.services.mail import TolerantDict
|
from pretix.base.services.mail import TolerantDict
|
||||||
from pretix.base.templatetags.rich_text import markdown_compile_email
|
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)
|
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(
|
send_mails.apply_async(
|
||||||
kwargs={
|
kwargs=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'),
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
self.request.event.log_action('pretix.plugins.sendmail.sent',
|
self.request.event.log_action('pretix.plugins.sendmail.sent',
|
||||||
user=self.request.user,
|
user=self.request.user,
|
||||||
|
|||||||
Reference in New Issue
Block a user