(
    campaign_key: str,
    to: List[Dict[str, str]],
    subject: str,
    headers: Dict,
    txt_body: str = "",
    html_body: str = "",
    reply_to: Optional[str] = None,
)
Sends built email message asynchronously.
Sends built email message asynchronously.
Sends built email message asynchronously .
def _send_email(
    campaign_key: str,
    to: List[Dict[str, str]],
    subject: str,
    headers: Dict,
    txt_body: str = "",
    html_body: str = "",
    reply_to: Optional[str] = None,
) -> None:
    """
    Sends built email message asynchronously.
    """

    messages: List = []
    records: List = []

    with transaction.atomic():

        for dest in to:
            record, _ = MessagingRecord.objects.get_or_create(raw_email=dest["raw_email"], campaign_key=campaign_key)

            # Lock object (database-level) while the message is sent
            record = MessagingRecord.objects.select_for_update().get(pk=record.pk)
            # If an email for this campaign was already sent to this user, skip recipient
            if record.sent_at:
                record.save()  # release DB lock
                continue

            records.append(record)
            reply_to = reply_to or settings.EMAIL_REPLY_TO

            email_message = mail.EmailMultiAlternatives(
                subject=subject,
                body=txt_body,
                to=[dest["recipient"]],
                headers=headers,
                reply_to=[reply_to] if reply_to else None,
            )

            email_message.attach_alternative(html_body, "text/html")
            messages.append(email_message)

        connection = None
        try:
            connection = mail.get_connection()
            connection.open()
            connection.send_messages(messages)

            for record in records:
                record.sent_at = timezone.now()
                record.save()

        except Exception as err:
            # Handle exceptions gracefully to avoid breaking the entire task for all teams
            # but make sure they're tracked on Sentry.
            print("Could not send email:", err, file=sys.stderr)
            capture_exception(err)
        finally:
            # Ensure that connection has been closed
            try:
                connection.close()  # type: ignore
            except Exception as err:
                print("Could not close email connection (this can be ignored):", err, file=sys.stderr)
def _send_email ( campaign_key : str , to : List [ Dict [ str , str ] ] , subject : str , headers : Dict , txt_body : str = "" , html_body : str = "" , reply_to : Optional [ str ] = None , ) -> None : messages : List = [ ] records : List = [ ] with transaction . atomic ( ) : for dest in to : record , _ = MessagingRecord . objects . get_or_create ( raw_email = dest [ "raw_email" ] , campaign_key = campaign_key ) # Lock object (database-level) while the message is sent record = MessagingRecord . objects . select_for_update ( ) . get ( pk = record . pk ) # If an email for this campaign was already sent to this user, skip recipient if record . sent_at : record . save ( ) # release DB lock continue records . append ( record ) reply_to = reply_to or settings . EMAIL_REPLY_TO email_message = mail . EmailMultiAlternatives ( subject = subject , body = txt_body , to = [ dest [ "recipient" ] ] , headers = headers , reply_to = [ reply_to ] if reply_to else None , ) email_message . attach_alternative ( html_body , "text/html" ) messages . append ( email_message ) connection = None try : connection = mail . get_connection ( ) connection . open ( ) connection . send_messages ( messages ) for record in records : record . sent_at = timezone . now ( ) record . save ( ) except Exception as err : # Handle exceptions gracefully to avoid breaking the entire task for all teams # but make sure they're tracked on Sentry. print ( "Could not send email:" , err , file = sys . stderr ) capture_exception ( err ) finally : # Ensure that connection has been closed try : connection . close ( ) # type: ignore except Exception as err : print ( "Could not close email connection (this can be ignored):" , err , file = sys . stderr )