mirror of
https://github.com/pretix/pretix.git
synced 2026-08-28 13:34:40 +00:00
Add option to attach calendar files to emails (#1457)
This commit is contained in:
@@ -723,7 +723,8 @@ class Order(LockModel, LoggedModel):
|
|||||||
def send_mail(self, subject: str, template: Union[str, LazyI18nString],
|
def send_mail(self, subject: str, template: Union[str, LazyI18nString],
|
||||||
context: Dict[str, Any]=None, log_entry_type: str='pretix.event.order.email.sent',
|
context: Dict[str, Any]=None, log_entry_type: str='pretix.event.order.email.sent',
|
||||||
user: User=None, headers: dict=None, sender: str=None, invoices: list=None,
|
user: User=None, headers: dict=None, sender: str=None, invoices: list=None,
|
||||||
auth=None, attach_tickets=False, position: 'OrderPosition'=None, auto_email=True):
|
auth=None, attach_tickets=False, position: 'OrderPosition'=None, auto_email=True,
|
||||||
|
attach_ical=False):
|
||||||
"""
|
"""
|
||||||
Sends an email to the user that placed this order. Basically, this method does two things:
|
Sends an email to the user that placed this order. Basically, this method does two things:
|
||||||
|
|
||||||
@@ -740,6 +741,7 @@ class Order(LockModel, LoggedModel):
|
|||||||
:param headers: Dictionary with additional mail headers
|
:param headers: Dictionary with additional mail headers
|
||||||
:param sender: Custom email sender.
|
:param sender: Custom email sender.
|
||||||
:param attach_tickets: Attach tickets of this order, if they are existing and ready to download
|
:param attach_tickets: Attach tickets of this order, if they are existing and ready to download
|
||||||
|
:param attach_ical: Attach relevant ICS files
|
||||||
:param position: An order position this refers to. If given, no invoices will be attached, the tickets will
|
:param position: An order position this refers to. If given, no invoices will be attached, the tickets will
|
||||||
only be attached for this position and child positions, the link will only point to the
|
only be attached for this position and child positions, the link will only point to the
|
||||||
position and the attendee email will be used if available.
|
position and the attendee email will be used if available.
|
||||||
@@ -763,7 +765,7 @@ class Order(LockModel, LoggedModel):
|
|||||||
recipient, subject, template, context,
|
recipient, subject, template, context,
|
||||||
self.event, self.locale, self, headers=headers, sender=sender,
|
self.event, self.locale, self, headers=headers, sender=sender,
|
||||||
invoices=invoices, attach_tickets=attach_tickets,
|
invoices=invoices, attach_tickets=attach_tickets,
|
||||||
position=position, auto_email=auto_email
|
position=position, auto_email=auto_email, attach_ical=attach_ical
|
||||||
)
|
)
|
||||||
except SendMailException:
|
except SendMailException:
|
||||||
raise
|
raise
|
||||||
@@ -779,6 +781,7 @@ class Order(LockModel, LoggedModel):
|
|||||||
'recipient': recipient,
|
'recipient': recipient,
|
||||||
'invoices': [i.pk for i in invoices] if invoices else [],
|
'invoices': [i.pk for i in invoices] if invoices else [],
|
||||||
'attach_tickets': attach_tickets,
|
'attach_tickets': attach_tickets,
|
||||||
|
'attach_ical': attach_ical,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -790,7 +793,7 @@ class Order(LockModel, LoggedModel):
|
|||||||
self.send_mail(
|
self.send_mail(
|
||||||
email_subject, email_template, email_context,
|
email_subject, email_template, email_context,
|
||||||
'pretix.event.order.email.resend', user=user, auth=auth,
|
'pretix.event.order.email.resend', user=user, auth=auth,
|
||||||
attach_tickets=True
|
attach_tickets=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -1334,7 +1337,7 @@ class OrderPayment(models.Model):
|
|||||||
email_subject, email_template, email_context,
|
email_subject, email_template, email_context,
|
||||||
'pretix.event.order.email.order_paid', user,
|
'pretix.event.order.email.order_paid', user,
|
||||||
invoices=[], position=position,
|
invoices=[], position=position,
|
||||||
attach_tickets=True
|
attach_tickets=True, attach_ical=True
|
||||||
)
|
)
|
||||||
except SendMailException:
|
except SendMailException:
|
||||||
logger.exception('Order paid email could not be sent')
|
logger.exception('Order paid email could not be sent')
|
||||||
@@ -1351,7 +1354,7 @@ class OrderPayment(models.Model):
|
|||||||
email_subject, email_template, email_context,
|
email_subject, email_template, email_context,
|
||||||
'pretix.event.order.email.order_paid', user,
|
'pretix.event.order.email.order_paid', user,
|
||||||
invoices=[invoice] if invoice and self.order.event.settings.invoice_email_attachment else [],
|
invoices=[invoice] if invoice and self.order.event.settings.invoice_email_attachment else [],
|
||||||
attach_tickets=True
|
attach_tickets=True, attach_ical=True
|
||||||
)
|
)
|
||||||
except SendMailException:
|
except SendMailException:
|
||||||
logger.exception('Order paid email could not be sent')
|
logger.exception('Order paid email could not be sent')
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ from pretix.base.services.tickets import get_tickets_for_order
|
|||||||
from pretix.base.signals import email_filter, global_email_filter
|
from pretix.base.signals import email_filter, global_email_filter
|
||||||
from pretix.celery_app import app
|
from pretix.celery_app import app
|
||||||
from pretix.multidomain.urlreverse import build_absolute_uri
|
from pretix.multidomain.urlreverse import build_absolute_uri
|
||||||
|
from pretix.presale.ical import get_ical
|
||||||
|
|
||||||
logger = logging.getLogger('pretix.base.mail')
|
logger = logging.getLogger('pretix.base.mail')
|
||||||
INVALID_ADDRESS = 'invalid-pretix-mail-address'
|
INVALID_ADDRESS = 'invalid-pretix-mail-address'
|
||||||
@@ -50,7 +51,7 @@ class SendMailException(Exception):
|
|||||||
def mail(email: str, subject: str, template: Union[str, LazyI18nString],
|
def mail(email: str, subject: str, template: Union[str, LazyI18nString],
|
||||||
context: Dict[str, Any]=None, event: Event=None, locale: str=None,
|
context: Dict[str, Any]=None, event: Event=None, locale: str=None,
|
||||||
order: Order=None, position: OrderPosition=None, headers: dict=None, sender: str=None,
|
order: Order=None, position: OrderPosition=None, headers: dict=None, sender: str=None,
|
||||||
invoices: list=None, attach_tickets=False, auto_email=True, user=None):
|
invoices: list=None, attach_tickets=False, auto_email=True, user=None, attach_ical=False):
|
||||||
"""
|
"""
|
||||||
Sends out an email to a user. The mail will be sent synchronously or asynchronously depending on the installation.
|
Sends out an email to a user. The mail will be sent synchronously or asynchronously depending on the installation.
|
||||||
|
|
||||||
@@ -85,6 +86,8 @@ def mail(email: str, subject: str, template: Union[str, LazyI18nString],
|
|||||||
|
|
||||||
:param attach_tickets: Whether to attach tickets to this email, if they are available to download.
|
:param attach_tickets: Whether to attach tickets to this email, if they are available to download.
|
||||||
|
|
||||||
|
:param attach_ical: Whether to attach relevant ``.ics`` files to this email
|
||||||
|
|
||||||
:param auto_email: Whether this email is auto-generated
|
:param auto_email: Whether this email is auto-generated
|
||||||
|
|
||||||
:param user: The user this email is sent to
|
:param user: The user this email is sent to
|
||||||
@@ -216,6 +219,7 @@ def mail(email: str, subject: str, template: Union[str, LazyI18nString],
|
|||||||
order=order.pk if order else None,
|
order=order.pk if order else None,
|
||||||
position=position.pk if position else None,
|
position=position.pk if position else None,
|
||||||
attach_tickets=attach_tickets,
|
attach_tickets=attach_tickets,
|
||||||
|
attach_ical=attach_ical,
|
||||||
user=user.pk if user else None
|
user=user.pk if user else None
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -231,7 +235,8 @@ def mail(email: str, subject: str, template: Union[str, LazyI18nString],
|
|||||||
@app.task(base=TransactionAwareTask, bind=True)
|
@app.task(base=TransactionAwareTask, bind=True)
|
||||||
def mail_send_task(self, *args, to: List[str], subject: str, body: str, html: str, sender: str,
|
def mail_send_task(self, *args, to: List[str], subject: str, body: str, html: str, sender: str,
|
||||||
event: int=None, position: int=None, headers: dict=None, bcc: List[str]=None,
|
event: int=None, position: int=None, headers: dict=None, bcc: List[str]=None,
|
||||||
invoices: List[int]=None, order: int=None, attach_tickets=False, user=None) -> bool:
|
invoices: List[int]=None, order: int=None, attach_tickets=False, user=None,
|
||||||
|
attach_ical=False) -> bool:
|
||||||
email = EmailMultiAlternatives(subject, body, sender, to=to, bcc=bcc, headers=headers)
|
email = EmailMultiAlternatives(subject, body, sender, to=to, bcc=bcc, headers=headers)
|
||||||
if html is not None:
|
if html is not None:
|
||||||
html_with_cid, cid_images = replace_images_with_cid_paths(html)
|
html_with_cid, cid_images = replace_images_with_cid_paths(html)
|
||||||
@@ -301,6 +306,20 @@ def mail_send_task(self, *args, to: List[str], subject: str, body: str, html: st
|
|||||||
'invoices': [],
|
'invoices': [],
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
if attach_ical:
|
||||||
|
ical_events = set()
|
||||||
|
if event.has_subevents:
|
||||||
|
if position:
|
||||||
|
ical_events.add(position.subevent)
|
||||||
|
else:
|
||||||
|
for p in order.positions.all():
|
||||||
|
ical_events.add(p.subevent)
|
||||||
|
else:
|
||||||
|
ical_events.add(order.event)
|
||||||
|
|
||||||
|
for i, e in enumerate(ical_events):
|
||||||
|
cal = get_ical([e])
|
||||||
|
email.attach('event-{}.ics'.format(i), cal.serialize(), 'text/calendar')
|
||||||
|
|
||||||
email = email_filter.send_chained(event, 'message', message=email, order=order, user=user)
|
email = email_filter.send_chained(event, 'message', message=email, order=order, user=user)
|
||||||
|
|
||||||
|
|||||||
@@ -707,7 +707,8 @@ def _order_placed_email(event: Event, order: Order, pprov: BasePaymentProvider,
|
|||||||
email_subject, email_template, email_context,
|
email_subject, email_template, email_context,
|
||||||
log_entry,
|
log_entry,
|
||||||
invoices=[invoice] if invoice and event.settings.invoice_email_attachment else [],
|
invoices=[invoice] if invoice and event.settings.invoice_email_attachment else [],
|
||||||
attach_tickets=True
|
attach_tickets=True,
|
||||||
|
attach_ical=event.settings.mail_attach_ical
|
||||||
)
|
)
|
||||||
except SendMailException:
|
except SendMailException:
|
||||||
logger.exception('Order received email could not be sent')
|
logger.exception('Order received email could not be sent')
|
||||||
@@ -723,7 +724,8 @@ def _order_placed_email_attendee(event: Event, order: Order, position: OrderPosi
|
|||||||
log_entry,
|
log_entry,
|
||||||
invoices=[],
|
invoices=[],
|
||||||
attach_tickets=True,
|
attach_tickets=True,
|
||||||
position=position
|
position=position,
|
||||||
|
attach_ical=event.settings.mail_attach_ical
|
||||||
)
|
)
|
||||||
except SendMailException:
|
except SendMailException:
|
||||||
logger.exception('Order received email could not be sent to attendee')
|
logger.exception('Order received email could not be sent to attendee')
|
||||||
|
|||||||
@@ -297,6 +297,10 @@ DEFAULTS = {
|
|||||||
'default': 'classic',
|
'default': 'classic',
|
||||||
'type': str
|
'type': str
|
||||||
},
|
},
|
||||||
|
'mail_attach_ical': {
|
||||||
|
'default': 'False',
|
||||||
|
'type': bool
|
||||||
|
},
|
||||||
'mail_prefix': {
|
'mail_prefix': {
|
||||||
'default': None,
|
'default': None,
|
||||||
'type': str
|
'type': str
|
||||||
|
|||||||
@@ -976,6 +976,11 @@ class MailSettingsForm(SettingsForm):
|
|||||||
required=False,
|
required=False,
|
||||||
max_length=255
|
max_length=255
|
||||||
)
|
)
|
||||||
|
mail_attach_ical = forms.BooleanField(
|
||||||
|
label=_("Attach calendar files"),
|
||||||
|
help_text=_("If enabled, we will attach an .ics calendar file to order confirmation emails."),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
|
||||||
mail_text_signature = I18nFormField(
|
mail_text_signature = I18nFormField(
|
||||||
label=_("Signature"),
|
label=_("Signature"),
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
{% bootstrap_field form.mail_from_name layout="control" %}
|
{% bootstrap_field form.mail_from_name layout="control" %}
|
||||||
{% bootstrap_field form.mail_text_signature layout="control" %}
|
{% bootstrap_field form.mail_text_signature layout="control" %}
|
||||||
{% bootstrap_field form.mail_bcc layout="control" %}
|
{% bootstrap_field form.mail_bcc layout="control" %}
|
||||||
|
{% bootstrap_field form.mail_attach_ical layout="control" %}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{% trans "E-mail design" %}</legend>
|
<legend>{% trans "E-mail design" %}</legend>
|
||||||
|
|||||||
Reference in New Issue
Block a user