From 764e5e5df7471bd19795edcd5aa85b6500bd3be5 Mon Sep 17 00:00:00 2001 From: Phin Wolkwitz Date: Thu, 6 Aug 2026 17:20:34 +0200 Subject: [PATCH] Fix and improve sendmail logic --- src/pretix/plugins/sendmail/models.py | 13 ++--- src/pretix/plugins/sendmail/tasks.py | 79 +++++++++++++++++---------- 2 files changed, 56 insertions(+), 36 deletions(-) diff --git a/src/pretix/plugins/sendmail/models.py b/src/pretix/plugins/sendmail/models.py index 8950e7fde6..7300928fa0 100644 --- a/src/pretix/plugins/sendmail/models.py +++ b/src/pretix/plugins/sendmail/models.py @@ -191,15 +191,13 @@ class ScheduledMail(models.Model): positions = [p for p in positions if p.subevent_id == self.subevent_id] parent_op = None - sent_to_parent_positions = set() + sent_to_positions = set() for p in positions: if p.addon_to_id is None: parent_op = p if not self.rule.all_products and p.item_id not in position_ids: continue - else: - sent_to_parent_positions.add(p.id) if p.id in position_ids: mail_to_parent = False @@ -208,13 +206,12 @@ class ScheduledMail(models.Model): if p.addon_to_id is not None: # without attendee-email if not p.attendee_email: - if p.addon_to_id in sent_to_parent_positions: + if p.addon_to_id in sent_to_positions: continue elif parent_op.attendee_email: - sent_to_parent_positions.add(parent_op.id) mail_to_parent = True # with attendee-email but same as parent's and sent to parent - elif parent_op.attendee_email and p.attendee_email == parent_op.attendee_email and parent_op in sent_to_parent_positions: + elif parent_op.attendee_email and p.attendee_email == parent_op.attendee_email and parent_op in sent_to_positions: continue if p.attendee_email and (p.attendee_email != o.email or not o_sent): @@ -228,6 +225,7 @@ class ScheduledMail(models.Model): p.send_mail(self.rule.subject, self.rule.template, email_ctx, attach_ical=self.rule.attach_ical, log_entry_type='pretix.plugins.sendmail.rule.order.position.email.sent') + sent_to_positions.add(p.id) elif mail_to_parent and (parent_op.attendee_email != o.email or not o_sent): email_ctx = get_email_context( event=e, @@ -239,6 +237,7 @@ class ScheduledMail(models.Model): parent_op.send_mail(self.rule.subject, self.rule.template, email_ctx, attach_ical=self.rule.attach_ical, log_entry_type='pretix.plugins.sendmail.rule.order.position.email.sent') + sent_to_positions.add(parent_op.id) elif not o_sent and o.email: email_ctx = get_email_context( event=e, @@ -262,7 +261,7 @@ class Rule(models.Model, LoggingMixin): SEND_TO_CHOICES = [ (CUSTOMERS, _("Everyone who created a ticket order")), (ATTENDEES, - _("Every attendee (falling back to the order contact when no attendee email address is given or the ticket's contact in the case of add-ons)")), + _("Every attendee (falling back to the order contact when no attendee email address is given)")), (BOTH, _('Both (all order contact addresses and all attendee email addresses)')) ] diff --git a/src/pretix/plugins/sendmail/tasks.py b/src/pretix/plugins/sendmail/tasks.py index 60c873af07..57204085e5 100644 --- a/src/pretix/plugins/sendmail/tasks.py +++ b/src/pretix/plugins/sendmail/tasks.py @@ -71,7 +71,7 @@ def send_mails_to_orders(event: Event, user: int, subject: dict, message: dict, ia = InvoiceAddress(order=o) parent_op = None - sent_to_parent_positions = set() + sent_to_positions = set() if recipients in ('both', 'attendees'): for p in o.positions.annotate( any_checkins=Exists( @@ -105,27 +105,25 @@ def send_mails_to_orders(event: Event, user: int, subject: dict, message: dict, if not allowed: continue - send_to_email = '' - + send_to_parent = False if not p.attendee_email: if recipients == 'attendees': if is_addon: - if p.addon_to_id in sent_to_parent_positions: + if p.addon_to_id in sent_to_positions: continue elif parent_op and parent_op.id == p.addon_to_id and parent_op.attendee_email: - send_to_email = parent_op.attendee_email + send_to_parent = True else: send_to_order = True continue else: send_to_order = True continue - elif is_addon and p.addon_to_id in sent_to_parent_positions and p.attendee_email == parent_op.attendee_email: + # add-on's attendee-email is the same as parent's and sent to parent + elif is_addon and p.addon_to_id in sent_to_positions and p.attendee_email == parent_op.attendee_email: continue - else: - send_to_email = p.attendee_email - if send_to_email == o.email and send_to_order: + if p.attendee_email and p.attendee_email == o.email and send_to_order: continue if subevent and p.subevent_id != subevent: @@ -138,27 +136,50 @@ def send_mails_to_orders(event: Event, user: int, subject: dict, message: dict, continue with language(o.locale, event.settings.region): - email_context = get_email_context(event=event, order=o, invoice_address=ia, position=p) - outgoing_mail = mail( - send_to_email, - subject, - message, - email_context, - event, - locale=o.locale, - order=o, - position=p, - attach_tickets=attach_tickets, - attach_ical=attach_ical, - attach_cached_files=attachments - ) - if outgoing_mail: - o.log_action( - 'pretix.plugins.sendmail.order.email.sent.attendee', - user=user, - data=outgoing_mail.log_data(), + if send_to_parent: + email_context = get_email_context(event=event, order=o, invoice_address=ia, position=parent_op) + outgoing_mail = mail( + parent_op.attendee_email, + subject, + message, + email_context, + event, + locale=o.locale, + order=o, + position=parent_op, + attach_tickets=attach_tickets, + attach_ical=attach_ical, + attach_cached_files=attachments ) - sent_to_parent_positions.add(p.id) + if outgoing_mail: + o.log_action( + 'pretix.plugins.sendmail.order.email.sent.attendee', + user=user, + data=outgoing_mail.log_data(), + ) + sent_to_positions.add(parent_op.id) + else: + email_context = get_email_context(event=event, order=o, invoice_address=ia, position=p) + outgoing_mail = mail( + p.attendee_email, + subject, + message, + email_context, + event, + locale=o.locale, + order=o, + position=p, + attach_tickets=attach_tickets, + attach_ical=attach_ical, + attach_cached_files=attachments + ) + if outgoing_mail: + o.log_action( + 'pretix.plugins.sendmail.order.email.sent.attendee', + user=user, + data=outgoing_mail.log_data(), + ) + sent_to_positions.add(p.id) if send_to_order and o.email: with language(o.locale, event.settings.region):