def mail(email: str, subject: str, template: Union[str, LazyI18nString], context: Dict[str, Any]=None, event: Event=None, locale: str=None, order: Order=None, headers: dict=None, sender: str=None, invoices: list=None, attach_tickets=False): """ Sends out an email to a user. The mail will be sent synchronously or asynchronously depending on the installation. :param email: The email address of the recipient :param subject: The email subject. Should be localized to the recipients's locale or a lazy object that will be localized by being casted to a string. :param template: The filename of a template to be used. It will be rendered with the locale given in the locale argument and the context given in the next argument. Alternatively, you can pass a LazyI18nString and ``context`` will be used as the argument to a Python ``.format_map()`` call on the template. :param context: The context for rendering the template (see ``template`` parameter) :param event: The event this email is related to (optional). If set, this will be used to determine the sender, a possible prefix for the subject and the SMTP server that should be used to send this email. :param order: The order this email is related to (optional). If set, this will be used to include a link to the order below the email. :param headers: A dict of custom mail headers to add to the mail :param locale: The locale to be used while evaluating the subject and the template :param sender: Set the sender email address. If not set and ``event`` is set, the event's default will be used, otherwise the system default. :param invoices: A list of invoices to attach to this email. :param attach_tickets: Whether to attach tickets to this email, if they are available to download. :raises MailOrderException: on obvious, immediate failures. Not raising an exception does not necessarily mean that the email has been sent, just that it has been queued by the email backend. """ if email == INVALID_ADDRESS: return headers = headers or {} with language(locale): if isinstance(context, dict) and order: try: context.update({ 'invoice_name': order.invoice_address.name, 'invoice_company': order.invoice_address.company }) except InvoiceAddress.DoesNotExist: context.update({ 'invoice_name': '', 'invoice_company': '' }) renderer = ClassicMailRenderer(None) content_plain = body_plain = render_mail(template, context) subject = str(subject).format_map(context) sender = sender or (event.settings.get('mail_from') if event else settings.MAIL_FROM) if event: sender = formataddr((str(event.name), sender)) else: sender = formataddr((settings.PRETIX_INSTANCE_NAME, sender)) subject = str(subject) signature = "" bcc = [] if event: renderer = event.get_html_mail_renderer() if event.settings.mail_bcc: bcc.append(event.settings.mail_bcc) if event.settings.mail_from == settings.DEFAULT_FROM_EMAIL and event.settings.contact_mail and not headers.get('Reply-To'): headers['Reply-To'] = event.settings.contact_mail prefix = event.settings.get('mail_prefix') if prefix and prefix.startswith('[') and prefix.endswith(']'): prefix = prefix[1:-1] if prefix: subject = "[%s] %s" % (prefix, subject) body_plain += "\r\n\r\n-- \r\n" signature = str(event.settings.get('mail_text_signature')) if signature: signature = signature.format(event=event.name) body_plain += signature body_plain += "\r\n\r\n-- \r\n" if order: body_plain += _( "You are receiving this email because you placed an order for {event}." ).format(event=event.name) body_plain += "\r\n" body_plain += _( "You can view your order details at the following URL:\n{orderurl}." ).replace("\n", "\r\n").format( event=event.name, orderurl=build_absolute_uri( order.event, 'presale:event.order', kwargs={ 'order': order.code, 'secret': order.secret } ) ) body_plain += "\r\n" try: body_html = renderer.render(content_plain, signature, str(subject), order) except: logger.exception('Could not render HTML body') body_html = None send_task = mail_send_task.si( to=[email], bcc=bcc, subject=subject, body=body_plain, html=body_html, sender=sender, event=event.id if event else None, headers=headers, invoices=[i.pk for i in invoices] if invoices else [], order=order.pk if order else None, attach_tickets=attach_tickets ) if invoices: task_chain = [invoice_pdf_task.si(i.pk).on_error(send_task) for i in invoices if not i.file] else: task_chain = [] task_chain.append(send_task) chain(*task_chain).apply_async()
def mail(email: str, subject: str, template: Union[str, LazyI18nString], context: Dict[str, Any]=None, event: Event=None, locale: 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, attach_ical=False): """ Sends out an email to a user. The mail will be sent synchronously or asynchronously depending on the installation. :param email: The email address of the recipient :param subject: The email subject. Should be localized to the recipients's locale or a lazy object that will be localized by being casted to a string. :param template: The filename of a template to be used. It will be rendered with the locale given in the locale argument and the context given in the next argument. Alternatively, you can pass a LazyI18nString and ``context`` will be used as the argument to a Python ``.format_map()`` call on the template. :param context: The context for rendering the template (see ``template`` parameter) :param event: The event this email is related to (optional). If set, this will be used to determine the sender, a possible prefix for the subject and the SMTP server that should be used to send this email. :param order: The order this email is related to (optional). If set, this will be used to include a link to the order below the email. :param order: The order position this email is related to (optional). If set, this will be used to include a link to the order position instead of the order below the email. :param headers: A dict of custom mail headers to add to the mail :param locale: The locale to be used while evaluating the subject and the template :param sender: Set the sender email address. If not set and ``event`` is set, the event's default will be used, otherwise the system default. :param invoices: A list of invoices to attach to this email. :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 user: The user this email is sent to :raises MailOrderException: on obvious, immediate failures. Not raising an exception does not necessarily mean that the email has been sent, just that it has been queued by the email backend. """ if email == INVALID_ADDRESS: return headers = headers or {} if auto_email: headers['X-Auto-Response-Suppress'] = 'OOF, NRN, AutoReply, RN' headers['Auto-Submitted'] = 'auto-generated' with language(locale): if isinstance(context, dict) and event: for k, v in event.meta_data.items(): context['meta_' + k] = v if isinstance(context, dict) and order: try: context.update({ 'invoice_name': order.invoice_address.name, 'invoice_company': order.invoice_address.company }) except InvoiceAddress.DoesNotExist: context.update({ 'invoice_name': '', 'invoice_company': '' }) renderer = ClassicMailRenderer(None) content_plain = body_plain = render_mail(template, context) subject = str(subject).format_map(TolerantDict(context)) sender = sender or (event.settings.get('mail_from') if event else settings.MAIL_FROM) if event: sender_name = event.settings.mail_from_name or str(event.name) sender = formataddr((sender_name, sender)) else: sender = formataddr((settings.PRETIX_INSTANCE_NAME, sender)) subject = str(subject) signature = "" bcc = [] if event: renderer = event.get_html_mail_renderer() if event.settings.mail_bcc: for bcc_mail in event.settings.mail_bcc.split(','): bcc.append(bcc_mail.strip()) if event.settings.mail_from == settings.DEFAULT_FROM_EMAIL and event.settings.contact_mail and not headers.get('Reply-To'): headers['Reply-To'] = event.settings.contact_mail prefix = event.settings.get('mail_prefix') if prefix and prefix.startswith('[') and prefix.endswith(']'): prefix = prefix[1:-1] if prefix: subject = "[%s] %s" % (prefix, subject) body_plain += "\r\n\r\n-- \r\n" signature = str(event.settings.get('mail_text_signature')) if signature: signature = signature.format(event=event.name) body_plain += signature body_plain += "\r\n\r\n-- \r\n" if order and order.testmode: subject = "[TESTMODE] " + subject if order and position: body_plain += _( "You are receiving this email because someone placed an order for {event} for you." ).format(event=event.name) body_plain += "\r\n" body_plain += _( "You can view your order details at the following URL:\n{orderurl}." ).replace("\n", "\r\n").format( event=event.name, orderurl=build_absolute_uri( order.event, 'presale:event.order.position', kwargs={ 'order': order.code, 'secret': position.web_secret, 'position': position.positionid, } ) ) elif order: body_plain += _( "You are receiving this email because you placed an order for {event}." ).format(event=event.name) body_plain += "\r\n" body_plain += _( "You can view your order details at the following URL:\n{orderurl}." ).replace("\n", "\r\n").format( event=event.name, orderurl=build_absolute_uri( order.event, 'presale:event.order.open', kwargs={ 'order': order.code, 'secret': order.secret, 'hash': order.email_confirm_hash() } ) ) body_plain += "\r\n" try: if 'position' in inspect.signature(renderer.render).parameters: body_html = renderer.render(content_plain, signature, str(subject), order, position) else: # Backwards compatibility warnings.warn('E-mail renderer called without position argument because position argument is not ' 'supported.', DeprecationWarning) body_html = renderer.render(content_plain, signature, str(subject), order) except: logger.exception('Could not render HTML body') body_html = None send_task = mail_send_task.si( to=[email], bcc=bcc, subject=subject, body=body_plain, html=body_html, sender=sender, event=event.id if event else None, headers=headers, invoices=[i.pk for i in invoices] if invoices and not position else [], order=order.pk if order else None, position=position.pk if position else None, attach_tickets=attach_tickets, attach_ical=attach_ical, user=user.pk if user else None ) if invoices: task_chain = [invoice_pdf_task.si(i.pk).on_error(send_task) for i in invoices if not i.file] else: task_chain = [] task_chain.append(send_task) chain(*task_chain).apply_async()
def mail(email: str, subject: str, template: Union[str, LazyI18nString], context: Dict[str, Any]=None, event: Event=None, locale: str=None, order: Order=None, headers: dict=None, sender: str=None, invoices: list=None): """ Sends out an email to a user. The mail will be sent synchronously or asynchronously depending on the installation. :param email: The email address of the recipient :param subject: The email subject. Should be localized to the recipients's locale or a lazy object that will be localized by being casted to a string. :param template: The filename of a template to be used. It will be rendered with the locale given in the locale argument and the context given in the next argument. Alternatively, you can pass a LazyI18nString and ``context`` will be used as the argument to a Python ``.format_map()`` call on the template. :param context: The context for rendering the template (see ``template`` parameter) :param event: The event this email is related to (optional). If set, this will be used to determine the sender, a possible prefix for the subject and the SMTP server that should be used to send this email. :param order: The order this email is related to (optional). If set, this will be used to include a link to the order below the email. :param headers: A dict of custom mail headers to add to the mail :param locale: The locale to be used while evaluating the subject and the template :param sender: Set the sender email address. If not set and ``event`` is set, the event's default will be used, otherwise the system default. :param invoices: A list of invoices to attach to this email. :raises MailOrderException: on obvious, immediate failures. Not raising an exception does not necessarily mean that the email has been sent, just that it has been queued by the email backend. """ if email == INVALID_ADDRESS: return headers = headers or {} with language(locale): if isinstance(context, dict) and order: try: context.update({ 'invoice_name': order.invoice_address.name, 'invoice_company': order.invoice_address.company }) except InvoiceAddress.DoesNotExist: context.update({ 'invoice_name': '', 'invoice_company': '' }) renderer = ClassicMailRenderer(None) content_plain = body_plain = render_mail(template, context) subject = str(subject).format_map(context) sender = sender or (event.settings.get('mail_from') if event else settings.MAIL_FROM) if event: sender = formataddr((str(event.name), sender)) else: sender = formataddr((settings.PRETIX_INSTANCE_NAME, sender)) subject = str(subject) signature = "" bcc = [] if event: renderer = event.get_html_mail_renderer() if event.settings.mail_bcc: bcc.append(event.settings.mail_bcc) if event.settings.mail_from == settings.DEFAULT_FROM_EMAIL and event.settings.contact_mail and not headers.get('Reply-To'): headers['Reply-To'] = event.settings.contact_mail prefix = event.settings.get('mail_prefix') if prefix and prefix.startswith('[') and prefix.endswith(']'): prefix = prefix[1:-1] if prefix: subject = "[%s] %s" % (prefix, subject) body_plain += "\r\n\r\n-- \r\n" signature = str(event.settings.get('mail_text_signature')) if signature: signature = signature.format(event=event.name) body_plain += signature body_plain += "\r\n\r\n-- \r\n" if order: body_plain += _( "You are receiving this email because you placed an order for {event}." ).format(event=event.name) body_plain += "\r\n" body_plain += _( "You can view your order details at the following URL:\n{orderurl}." ).replace("\n", "\r\n").format( event=event.name, orderurl=build_absolute_uri( order.event, 'presale:event.order', kwargs={ 'order': order.code, 'secret': order.secret } ) ) body_plain += "\r\n" try: body_html = renderer.render(content_plain, signature, str(subject), order) except: logger.exception('Could not render HTML body') body_html = None send_task = mail_send_task.si( to=[email], bcc=bcc, subject=subject, body=body_plain, html=body_html, sender=sender, event=event.id if event else None, headers=headers, invoices=[i.pk for i in invoices] if invoices else [], order=order.pk if order else None ) if invoices: task_chain = [invoice_pdf_task.si(i.pk).on_error(send_task) for i in invoices if not i.file] else: task_chain = [] task_chain.append(send_task) chain(*task_chain).apply_async()