Beispiel #1
0
    def test_dont_base64_encode_message_rfc822(self):
        # Ticket #18967
        # Shouldn't use base64 encoding for a child EmailMessage attachment.
        # Create a child message first
        child_msg = EmailMessage('Child Subject', 'Some body of child message', '*****@*****.**', ['*****@*****.**'], headers={'From': '*****@*****.**'})
        child_s = child_msg.message().as_string()

        # Now create a parent
        parent_msg = EmailMessage('Parent Subject', 'Some parent body', '*****@*****.**', ['*****@*****.**'], headers={'From': '*****@*****.**'})

        # Attach to parent as a string
        parent_msg.attach(content=child_s, mimetype='message/rfc822')
        parent_s = parent_msg.message().as_string()

        # Verify that the child message header is not base64 encoded
        self.assertTrue(str('Child Subject') in parent_s)

        # Feature test: try attaching email.Message object directly to the mail.
        parent_msg = EmailMessage('Parent Subject', 'Some parent body', '*****@*****.**', ['*****@*****.**'], headers={'From': '*****@*****.**'})
        parent_msg.attach(content=child_msg.message(), mimetype='message/rfc822')
        parent_s = parent_msg.message().as_string()

        # Verify that the child message header is not base64 encoded
        self.assertTrue(str('Child Subject') in parent_s)

        # Feature test: try attaching Django's EmailMessage object directly to the mail.
        parent_msg = EmailMessage('Parent Subject', 'Some parent body', '*****@*****.**', ['*****@*****.**'], headers={'From': '*****@*****.**'})
        parent_msg.attach(content=child_msg, mimetype='message/rfc822')
        parent_s = parent_msg.message().as_string()

        # Verify that the child message header is not base64 encoded
        self.assertTrue(str('Child Subject') in parent_s)
Beispiel #2
0
 def test_multiple_message_call(self):
     """
     Regression for #13259 - Make sure that headers are not changed when
     calling EmailMessage.message()
     """
     email = EmailMessage('Subject', 'Content', '*****@*****.**', ['*****@*****.**'], headers={'From': '*****@*****.**'})
     message = email.message()
     self.assertEqual(message['From'], '*****@*****.**')
     message = email.message()
     self.assertEqual(message['From'], '*****@*****.**')
Beispiel #3
0
 def test_unicode_address_header(self):
     """
     Regression for #11144 - When a to/from/cc header contains unicode,
     make sure the email addresses are parsed correctly (especially with
     regards to commas)
     """
     email = EmailMessage('Subject', 'Content', '*****@*****.**', ['"Firstname Sürname" <*****@*****.**>', '*****@*****.**'])
     self.assertEqual(email.message()['To'], '=?utf-8?q?Firstname_S=C3=BCrname?= <*****@*****.**>, [email protected]')
     email = EmailMessage('Subject', 'Content', '*****@*****.**', ['"Sürname, Firstname" <*****@*****.**>', '*****@*****.**'])
     self.assertEqual(email.message()['To'], '=?utf-8?q?S=C3=BCrname=2C_Firstname?= <*****@*****.**>, [email protected]')
Beispiel #4
0
    def test_reply_to(self):
        email = EmailMessage(
            'Subject', 'Content', '*****@*****.**', ['*****@*****.**'],
            reply_to=['*****@*****.**'],
        )
        message = email.message()
        self.assertEqual(message['Reply-To'], '*****@*****.**')

        email = EmailMessage(
            'Subject', 'Content', '*****@*****.**', ['*****@*****.**'],
            reply_to=['*****@*****.**', '*****@*****.**']
        )
        message = email.message()
        self.assertEqual(message['Reply-To'], '[email protected], [email protected]')
Beispiel #5
0
    def test_encoding(self):
        """
        Regression for #12791 - Encode body correctly with other encodings
        than utf-8
        """
        email = EmailMessage('Subject', 'Firstname Sürname is a great guy.', '*****@*****.**', ['*****@*****.**'])
        email.encoding = 'iso-8859-1'
        message = email.message()
        self.assertMessageHasHeaders(message, {
            ('MIME-Version', '1.0'),
            ('Content-Type', 'text/plain; charset="iso-8859-1"'),
            ('Content-Transfer-Encoding', 'quoted-printable'),
            ('Subject', 'Subject'),
            ('From', '*****@*****.**'),
            ('To', '*****@*****.**')})
        self.assertEqual(message.get_payload(), 'Firstname S=FCrname is a great guy.')

        # Make sure MIME attachments also works correctly with other encodings than utf-8
        text_content = 'Firstname Sürname is a great guy.'
        html_content = '<p>Firstname Sürname is a <strong>great</strong> guy.</p>'
        msg = EmailMultiAlternatives('Subject', text_content, '*****@*****.**', ['*****@*****.**'])
        msg.encoding = 'iso-8859-1'
        msg.attach_alternative(html_content, "text/html")
        payload0 = msg.message().get_payload(0)
        self.assertMessageHasHeaders(payload0, {
            ('MIME-Version', '1.0'),
            ('Content-Type', 'text/plain; charset="iso-8859-1"'),
            ('Content-Transfer-Encoding', 'quoted-printable')})
        self.assertTrue(payload0.as_bytes().endswith(b'\n\nFirstname S=FCrname is a great guy.'))
        payload1 = msg.message().get_payload(1)
        self.assertMessageHasHeaders(payload1, {
            ('MIME-Version', '1.0'),
            ('Content-Type', 'text/html; charset="iso-8859-1"'),
            ('Content-Transfer-Encoding', 'quoted-printable')})
        self.assertTrue(payload1.as_bytes().endswith(b'\n\n<p>Firstname S=FCrname is a <strong>great</strong> guy.</p>'))
Beispiel #6
0
 def test_ascii(self):
     email = EmailMessage('Subject', 'Content', '*****@*****.**', ['*****@*****.**'])
     message = email.message()
     self.assertEqual(message['Subject'], 'Subject')
     self.assertEqual(message.get_payload(), 'Content')
     self.assertEqual(message['From'], '*****@*****.**')
     self.assertEqual(message['To'], '*****@*****.**')
    def send(self):
        subject = ("Contact ~ %s") % settings.PROJECT_DOMAIN
        html_content = render_to_response(
            "emails/web_contact.html",
            {
                "fullname": self.fullname,
                "email": self.email,
                "contact_number": self.contact_number,
                "comment": self.comment,
                "project": settings.PROJECT_DOMAIN,
            },
        ).content

        msg = EmailMessage(subject, html_content, settings.EMAIL_SYSTEM_SENDER, settings.WEBCONTACT_RECIPIENTS)
        msg.content_subtype = "html"

        try:
            if not settings.EMAIL_TEST_MODE:
                msg.send(fail_silently=False)

            else:  # save the email to disk for manual inspection
                filename = os.path.join(
                    settings.TEST_EMAIL_DIR, "%s_WebContactEmail.eml" % time.time().__int__().__str__()
                )
                if not os.path.isdir(settings.TEST_EMAIL_DIR):
                    os.mkdir(settings.TEST_EMAIL_DIR)
                f = open(filename, "w")
                f.write(msg.message().as_string())
                f.close()

        except Exception, e:
            print "Exception: %s" % e
            raise SendEmailError
Beispiel #8
0
 def test_multiple_recipients(self):
     email = EmailMessage('Subject', 'Content', '*****@*****.**', ['*****@*****.**', '*****@*****.**'])
     message = email.message()
     self.assertEqual(message['Subject'], 'Subject')
     self.assertEqual(message.get_payload(), 'Content')
     self.assertEqual(message['From'], '*****@*****.**')
     self.assertEqual(message['To'], '[email protected], [email protected]')
Beispiel #9
0
 def test_from_header(self):
     """
     Make sure we can manually set the From header (#9214)
     """
     email = EmailMessage('Subject', 'Content', '*****@*****.**', ['*****@*****.**'], headers={'From': '*****@*****.**'})
     message = email.message()
     self.assertEqual(message['From'], '*****@*****.**')
Beispiel #10
0
    def __send_to_user(cls, user, template, subject_params, body_params, cc):
        if not user.email:
            logger.warning("{} has no email address defined. Could not send email.".format(user.username))
            return

        if cc:
            cc_users = set(user.delegates.all() | user.cc_users.all())
            cc_addresses = [p.email for p in cc_users if p.email]
        else:
            cc_addresses = []

        subject = cls.__render_string(template.subject, subject_params)
        body = cls.__render_string(template.body, body_params)

        mail = EmailMessage(
            subject=subject,
            body=body,
            to=[user.email],
            cc=cc_addresses,
            bcc=[a[1] for a in settings.MANAGERS],
            headers={"Reply-To": settings.REPLY_TO_EMAIL},
        )

        try:
            mail.send(False)
            logger.info(('Sent email "{}" to {}.').format(subject, user.username))
        except Exception:
            logger.exception(
                'An exception occurred when sending the following email to user "{}":\n{}\n'.format(
                    user.username, mail.message()
                )
            )
    def test_message_reply(self):
        email_object = EmailMessage('Test subject',  # subject
            'Test body',  # body
            '*****@*****.**',  # from
            ['*****@*****.**'],  # to
        )
        msg = self.mailbox.record_outgoing_message(email_object.message())

        self.assertTrue(msg.outgoing)

        actual_from = '*****@*****.**'
        reply_email_object = EmailMessage(
            'Test subject',  # subject
            'Test body',  # body
            actual_from,  # from
            ['*****@*****.**'],  # to
        )

        with mock.patch.object(reply_email_object, 'send'):
            reply_msg = msg.reply(reply_email_object)

        self.assertEqual(reply_msg.in_reply_to, msg)

        self.assertEqual(actual_from, msg.from_header)

        reply_email_object.from_email = None

        second_reply_msg = msg.reply(reply_email_object)

        self.assertEqual(self.mailbox.from_email, second_reply_msg.from_header)
Beispiel #12
0
    def test_dont_base64_encode(self):
        # Ticket #3472
        # Shouldn't use Base64 encoding at all
        msg = EmailMessage(
            "Subject",
            "UTF-8 encoded body",
            "*****@*****.**",
            ["*****@*****.**"],
            headers={"From": "*****@*****.**"},
        )
        self.assertFalse("Content-Transfer-Encoding: base64" in msg.message().as_string())

        # Ticket #11212
        # Shouldn't use quoted printable, should detect it can represent content with 7 bit data
        msg = EmailMessage(
            "Subject",
            "Body with only ASCII characters.",
            "*****@*****.**",
            ["*****@*****.**"],
            headers={"From": "*****@*****.**"},
        )
        s = msg.message().as_string()
        self.assertFalse("Content-Transfer-Encoding: quoted-printable" in s)
        self.assertTrue("Content-Transfer-Encoding: 7bit" in s)

        # Shouldn't use quoted printable, should detect it can represent content with 8 bit data
        msg = EmailMessage(
            "Subject",
            "Body with latin characters: àáä.",
            "*****@*****.**",
            ["*****@*****.**"],
            headers={"From": "*****@*****.**"},
        )
        s = msg.message().as_string()
        self.assertFalse("Content-Transfer-Encoding: quoted-printable" in s)
        self.assertTrue("Content-Transfer-Encoding: 8bit" in s)

        msg = EmailMessage(
            "Subject",
            u"Body with non latin characters: А Б В Г Д Е Ж Ѕ З И І К Л М Н О П.",
            "*****@*****.**",
            ["*****@*****.**"],
            headers={"From": "*****@*****.**"},
        )
        s = msg.message().as_string()
        self.assertFalse("Content-Transfer-Encoding: quoted-printable" in s)
        self.assertTrue("Content-Transfer-Encoding: 8bit" in s)
Beispiel #13
0
    def test_to_header(self):
        """
        Make sure we can manually set the To header (#17444)
        """
        email = EmailMessage('Subject', 'Content', '*****@*****.**',
                             ['*****@*****.**', '*****@*****.**'],
                             headers={'To': '*****@*****.**'})
        message = email.message()
        self.assertEqual(message['To'], '*****@*****.**')
        self.assertEqual(email.to, ['*****@*****.**', '*****@*****.**'])

        # If we don't set the To header manually, it should default to the `to` argument to the constructor
        email = EmailMessage('Subject', 'Content', '*****@*****.**',
                             ['*****@*****.**', '*****@*****.**'])
        message = email.message()
        self.assertEqual(message['To'], '[email protected], [email protected]')
        self.assertEqual(email.to, ['*****@*****.**', '*****@*****.**'])
Beispiel #14
0
 def test_space_continuation(self):
     """
     Test for space continuation character in long (ASCII) subject headers (#7747)
     """
     email = EmailMessage('Long subject lines that get wrapped should contain a space continuation character to get expected behavior in Outlook and Thunderbird', 'Content', '*****@*****.**', ['*****@*****.**'])
     message = email.message()
     # Note that in Python 3, maximum line length has increased from 76 to 78
     self.assertEqual(message['Subject'].encode(), b'Long subject lines that get wrapped should contain a space continuation\n character to get expected behavior in Outlook and Thunderbird')
Beispiel #15
0
 def test_unicode_headers(self):
     email = EmailMessage("Gżegżółka", "Content", "*****@*****.**", ["*****@*****.**"],
                          headers={"Sender": '"Firstname Sürname" <*****@*****.**>',
                                   "Comments": 'My Sürname is non-ASCII'})
     message = email.message()
     self.assertEqual(message['Subject'], '=?utf-8?b?R8W8ZWfFvMOzxYJrYQ==?=')
     self.assertEqual(message['Sender'], '=?utf-8?q?Firstname_S=C3=BCrname?= <*****@*****.**>')
     self.assertEqual(message['Comments'], '=?utf-8?q?My_S=C3=BCrname_is_non-ASCII?=')
Beispiel #16
0
    def test_cc(self):
        """Regression test for #7722"""
        email = EmailMessage('Subject', 'Content', '*****@*****.**', ['*****@*****.**'], cc=['*****@*****.**'])
        message = email.message()
        self.assertEqual(message['Cc'], '*****@*****.**')
        self.assertEqual(email.recipients(), ['*****@*****.**', '*****@*****.**'])

        # Test multiple CC with multiple To
        email = EmailMessage('Subject', 'Content', '*****@*****.**', ['*****@*****.**', '*****@*****.**'], cc=['*****@*****.**', '*****@*****.**'])
        message = email.message()
        self.assertEqual(message['Cc'], '[email protected], [email protected]')
        self.assertEqual(email.recipients(), ['*****@*****.**', '*****@*****.**', '*****@*****.**', '*****@*****.**'])

        # Testing with Bcc
        email = EmailMessage('Subject', 'Content', '*****@*****.**', ['*****@*****.**', '*****@*****.**'], cc=['*****@*****.**', '*****@*****.**'], bcc=['*****@*****.**'])
        message = email.message()
        self.assertEqual(message['Cc'], '[email protected], [email protected]')
        self.assertEqual(email.recipients(), ['*****@*****.**', '*****@*****.**', '*****@*****.**', '*****@*****.**', '*****@*****.**'])
Beispiel #17
0
 def test_reply_to_header(self):
     """
     Specifying 'Reply-To' in headers should override reply_to.
     """
     email = EmailMessage(
         'Subject', 'Content', '*****@*****.**', ['*****@*****.**'],
         reply_to=['*****@*****.**'], headers={'Reply-To': '*****@*****.**'},
     )
     message = email.message()
     self.assertEqual(message['Reply-To'], '*****@*****.**')
 def message(self):
     """
     Returns the underlying :class:`email.message.Message` object.
     In case the user did not set a :attr:`msg` attribute for this instance
     the parent :meth:`EmailMessage.message
     <django.core.mail.EmailMessage.message>` method is used.
     """
     if self.msg:
         msg = self._attach_all()
         return msg
     else:
         return EmailMessage.message(self)
Beispiel #19
0
 def test_non_ascii_attachment_filename(self):
     """Regression test for #14964"""
     headers = {"Date": "Fri, 09 Nov 2001 01:08:47 -0000", "Message-ID": "foo"}
     subject, from_email, to = 'hello', '*****@*****.**', '*****@*****.**'
     content = 'This is the message.'
     msg = EmailMessage(subject, content, from_email, [to], headers=headers)
     # Unicode in file name
     msg.attach("une pièce jointe.pdf", b"%PDF-1.4.%...", mimetype="application/pdf")
     msg_bytes = msg.message().as_bytes()
     message = message_from_bytes(msg_bytes)
     payload = message.get_payload()
     self.assertEqual(payload[1].get_filename(), 'une pièce jointe.pdf')
Beispiel #20
0
    def test_dont_base64_encode(self):
        # Ticket #3472
        # Shouldn't use Base64 encoding at all
        msg = EmailMessage('Subject', 'UTF-8 encoded body', '*****@*****.**', ['*****@*****.**'], headers={'From': '*****@*****.**'})
        self.assertFalse(b'Content-Transfer-Encoding: base64' in msg.message().as_bytes())

        # Ticket #11212
        # Shouldn't use quoted printable, should detect it can represent content with 7 bit data
        msg = EmailMessage('Subject', 'Body with only ASCII characters.', '*****@*****.**', ['*****@*****.**'], headers={'From': '*****@*****.**'})
        s = msg.message().as_bytes()
        self.assertFalse(b'Content-Transfer-Encoding: quoted-printable' in s)
        self.assertTrue(b'Content-Transfer-Encoding: 7bit' in s)

        # Shouldn't use quoted printable, should detect it can represent content with 8 bit data
        msg = EmailMessage('Subject', 'Body with latin characters: àáä.', '*****@*****.**', ['*****@*****.**'], headers={'From': '*****@*****.**'})
        s = msg.message().as_bytes()
        self.assertFalse(b'Content-Transfer-Encoding: quoted-printable' in s)
        self.assertTrue(b'Content-Transfer-Encoding: 8bit' in s)

        msg = EmailMessage('Subject', 'Body with non latin characters: А Б В Г Д Е Ж Ѕ З И І К Л М Н О П.', '*****@*****.**', ['*****@*****.**'], headers={'From': '*****@*****.**'})
        s = msg.message().as_bytes()
        self.assertFalse(b'Content-Transfer-Encoding: quoted-printable' in s)
        self.assertTrue(b'Content-Transfer-Encoding: 8bit' in s)
Beispiel #21
0
def feedback_send(request):
    sender_email = request.user.email
    message = request.POST.get("message")
    subject = "Feedback from {}".format(sender_email)

    if message:
        mail = EmailMessage(
            subject=subject,
            body=message,
            to=[settings.FEEDBACK_EMAIL])

        try:
            mail.send()
            logger.info('Sent feedback email: \n{}\n'.format(mail.message()))
        except Exception:
            logger.exception('An exception occurred when sending the following feedback email:\n{}\n'.format(mail.message()))

    return HttpResponse()
Beispiel #22
0
    def test_message_header_overrides(self):
        """
        Specifying dates or message-ids in the extra headers overrides the
        default values (#9233)
        """
        headers = {"date": "Fri, 09 Nov 2001 01:08:47 -0000", "Message-ID": "foo"}
        email = EmailMessage('subject', 'content', '*****@*****.**', ['*****@*****.**'], headers=headers)

        self.assertMessageHasHeaders(email.message(), {
            ('Content-Transfer-Encoding', '7bit'),
            ('Content-Type', 'text/plain; charset="utf-8"'),
            ('From', '*****@*****.**'),
            ('MIME-Version', '1.0'),
            ('Message-ID', 'foo'),
            ('Subject', 'subject'),
            ('To', '*****@*****.**'),
            ('date', 'Fri, 09 Nov 2001 01:08:47 -0000'),
        })
Beispiel #23
0
 def send_mail(self, request):
     token = request.auth
     app = token.application
     app_admin = token.application.user
     user = self.get_queryset().first()
     mail = SendMailSerializer(data=request.data)
     if mail.is_valid():
         subject = '[SSO] [%s] %s' % (app.name, mail.validated_data.get('subject'))
         body = ('%s\n\n\n'
                 'Sent via SSO by %s\n\n'
                 'You received this message because you\'ve provided the email sending'
                 ' permission to the application')
         body = body % (mail.validated_data.get('message'), app.name)
         from_email = '%s <%s>' % (app_admin.first_name, app_admin.email)
         email_message = EmailMessage(
             subject=subject,
             body=body,
             from_email=from_email,
             to=[user.email],
             reply_to=mail.validated_data.get('reply_to'),
         )
         message = email_message.message()
         sent_message = SentMessage(
             message_id=message['Message-ID'],
             sender=app,
             user=user,
         )
         response_data = {
             'Message-ID': message['Message-ID'],
             'status': True,
         }
         try:
             email_message.send()
             sent_message.status = True
             response_data['status'] = True
         except SMTPException as err:
             sent_message.status = False,
             sent_message.error_message = err.message
             logger.error(err)
             response_data['status'] = False
         sent_message.save()
         return Response(response_data)
     else:
         return Response(mail.errors, status=HTTP_400_BAD_REQUEST)
Beispiel #24
0
def contact(request):
    message = request.POST.get("message")
    title = request.POST.get("title")
    subject = "[EvaP] Message from {}".format(request.user.username)

    if message:
        mail = EmailMessage(
            subject=subject,
            body="{}\n{} ({})\n\n{}".format(title, request.user.username, request.user.email, message),
            to=[settings.CONTACT_EMAIL])
        try:
            mail.send()
            logger.info('Sent contact email: \n{}\n'.format(mail.message()))
            return HttpResponse()
        except Exception:
            logger.exception('An exception occurred when sending the following contact email:\n{}\n'.format(mail.message()))
            raise

    return HttpResponseBadRequest()
Beispiel #25
0
    def test_encoding(self):
        """
        Regression for #12791 - Encode body correctly with other encodings
        than utf-8
        """
        email = EmailMessage('Subject', 'Firstname Sürname is a great guy.',
                             '*****@*****.**', ['*****@*****.**'])
        email.encoding = 'iso-8859-1'
        message = email.message()
        self.assertMessageHasHeaders(
            message, {('MIME-Version', '1.0'),
                      ('Content-Type', 'text/plain; charset="iso-8859-1"'),
                      ('Content-Transfer-Encoding', 'quoted-printable'),
                      ('Subject', 'Subject'), ('From', '*****@*****.**'),
                      ('To', '*****@*****.**')})
        self.assertEqual(message.get_payload(),
                         'Firstname S=FCrname is a great guy.')

        # Make sure MIME attachments also works correctly with other encodings than utf-8
        text_content = 'Firstname Sürname is a great guy.'
        html_content = '<p>Firstname Sürname is a <strong>great</strong> guy.</p>'
        msg = EmailMultiAlternatives('Subject', text_content,
                                     '*****@*****.**', ['*****@*****.**'])
        msg.encoding = 'iso-8859-1'
        msg.attach_alternative(html_content, "text/html")
        payload0 = msg.message().get_payload(0)
        self.assertMessageHasHeaders(
            payload0, {('MIME-Version', '1.0'),
                       ('Content-Type', 'text/plain; charset="iso-8859-1"'),
                       ('Content-Transfer-Encoding', 'quoted-printable')})
        self.assertTrue(payload0.as_bytes().endswith(
            b'\n\nFirstname S=FCrname is a great guy.'))
        payload1 = msg.message().get_payload(1)
        self.assertMessageHasHeaders(
            payload1, {('MIME-Version', '1.0'),
                       ('Content-Type', 'text/html; charset="iso-8859-1"'),
                       ('Content-Transfer-Encoding', 'quoted-printable')})
        self.assertTrue(payload1.as_bytes().endswith(
            b'\n\n<p>Firstname S=FCrname is a <strong>great</strong> guy.</p>')
                        )
Beispiel #26
0
 def send(self):
     subject = "A Reyoozer is interested in \"%s\"" % self.message.item.title
     html_content = render_to_response('emails/item_message_html.html', {
         'message': self.message,
         'base_url': settings.BASE_URL
     }).content
     
     msg = EmailMessage(subject, html_content, settings.EMAIL_SYSTEM_SENDER, [self.message.item.user.email])
     msg.content_subtype = "html"
     
     try:
         if not settings.EMAIL_TEST_MODE: msg.send(fail_silently = False)
         
         else: # save the email to disk for manual inspection
             filename = os.path.join( settings.TEST_EMAIL_DIR, "%s_ItemMessageEmail.eml" % time.time().__int__().__str__() )
             if not os.path.isdir(settings.TEST_EMAIL_DIR): os.mkdir(settings.TEST_EMAIL_DIR)
             f = open(filename, 'w')
             f.write(msg.message().as_string())
             f.close()
     except Exception, e:
         print "Exception: %s" % e
         raise SendEmailError
Beispiel #27
0
 def send_mail(self, request):
     token = request.auth
     app = token.application
     app_admin = token.application.user
     user = self.get_queryset().first()
     mail = SendMailSerializer(data=request.data)
     if mail.is_valid():
         subject = "[SSO] [%s] %s" % (app.name, mail.validated_data.get("subject"))
         body = (
             "%s\n\n"
             "Sent via SSO by %s\n\n"
             "You received this message because you've provided the email sending"
             " permission to the application"
         )
         body = body % (mail.validated_data.get("message"), app.name)
         from_email = "%s <%s>" % (app_admin.first_name, app_admin.email)
         email_message = EmailMessage(
             subject=subject,
             body=body,
             from_email=from_email,
             to=[user.email],
             reply_to=mail.validated_data.get("reply_to"),
         )
         message = email_message.message()
         sent_message = SentMessage(message_id=message["Message-ID"], sender=app, user=user)
         response_data = {}
         try:
             email_message.send()
             sent_message.status = True
             response_data["status"] = True
         except SMTPException as e:
             sent_message.status = (False,)
             sent_message.error_message = e.message
             logger.error(e)
             response_data["status"] = False
         sent_message.save()
         return Response(response_data)
     else:
         return Response(mail.errors, status=HTTP_400_BAD_REQUEST)
Beispiel #28
0
 def send(self):
     subject = "Please complete your Reyooz sign-up"
     html_content = render_to_response('emails/verification_html.html', {
         'user': self.user,
         'base_url': settings.BASE_URL
     }).content
     
     msg = EmailMessage(subject, html_content, settings.EMAIL_SYSTEM_SENDER, [self.user.email])
     msg.content_subtype = "html"
     
     try:
         if not settings.EMAIL_TEST_MODE: msg.send(fail_silently = False)
         
         else: # save the email to disk for manual inspection
             filename = os.path.join( settings.TEST_EMAIL_DIR, "%s_VerificationEmail.eml" % time.time().__int__().__str__() )
             if not os.path.isdir(settings.TEST_EMAIL_DIR): os.mkdir(settings.TEST_EMAIL_DIR)
             f = open(filename, 'w')
             f.write(msg.message().as_string())
             f.close()
     except Exception, e:
         print "Exception: %s" % e
         raise SendEmailError
Beispiel #29
0
def contact(request):
    message = request.POST.get("message")
    title = request.POST.get("title")
    email = request.user.email or f"User {request.user.id}"
    subject = f"[EvaP] Message from {email}"

    if message:
        mail = EmailMessage(
            subject=subject,
            body="{}\n{}\n\n{}".format(title, request.user.email, message),
            to=[settings.CONTACT_EMAIL],
            reply_to=[request.user.email],
        )
        try:
            mail.send()
            logger.info("Sent contact email: \n{}\n".format(mail.message()))
            return HttpResponse()
        except Exception:
            logger.exception(
                "An exception occurred when sending the following contact email:\n{}\n".format(mail.message())
            )
            raise

    return HttpResponseBadRequest()
Beispiel #30
0
    def test_message_header_overrides(self):
        """
        Specifying dates or message-ids in the extra headers overrides the
        default values (#9233)
        """
        headers = {
            "date": "Fri, 09 Nov 2001 01:08:47 -0000",
            "Message-ID": "foo"
        }
        email = EmailMessage('subject',
                             'content',
                             '*****@*****.**', ['*****@*****.**'],
                             headers=headers)

        self.assertEqual(sorted(email.message().items()), [
            ('Content-Transfer-Encoding', '7bit'),
            ('Content-Type', 'text/plain; charset="utf-8"'),
            ('From', '*****@*****.**'),
            ('MIME-Version', '1.0'),
            ('Message-ID', 'foo'),
            ('Subject', 'subject'),
            ('To', '*****@*****.**'),
            ('date', 'Fri, 09 Nov 2001 01:08:47 -0000'),
        ])
Beispiel #31
0
 def test_dont_mangle_from_in_body(self):
     # Regression for #13433 - Make sure that EmailMessage doesn't mangle
     # 'From ' in message body.
     email = EmailMessage('Subject', 'From the future', '*****@*****.**', ['*****@*****.**'], headers={'From': '*****@*****.**'})
     self.assertFalse(b'>From the future' in email.message().as_bytes())
Beispiel #32
0
def email_comment(gitlab, forge_id, author, comment, merge_id=None) -> None:
    """Email a comment made on Gitlab"""
    try:
        git_forge = GitForge.objects.get(host=urllib.parse.urlsplit(
            gitlab.url).hostname,
                                         forge_id=forge_id)
    except GitForge.DoesNotExist:
        _log.error(
            "Got comment event for project id %d, which isn't in the database",
            forge_id)
        return

    commit = comment.get("commit_id")
    try:
        bridged_submission = BridgedSubmission.objects.filter(
            git_forge=git_forge).order_by("-series_version")
        if merge_id:
            bridged_submission = bridged_submission.filter(
                merge_request=merge_id)
        if commit:
            bridged_submission = bridged_submission.filter(commit=commit)
        bridged_submission = bridged_submission[0]
    except IndexError:
        _log.info(
            "Unable to find a bridged submission for comment on MR %d, commit %s, forge %r",
            merge_id,
            commit,
            git_forge,
        )
        return

    from_email = settings.PATCHLAB_FROM_EMAIL.format(forge_user=author["name"])
    # From the bridged_submission, find the in-reply-to, create email.
    headers = {
        "Date": email_utils.formatdate(localtime=settings.EMAIL_USE_LOCALTIME),
        "Message-ID": email_utils.make_msgid(domain=DNS_NAME),
        "In-Reply-To": bridged_submission.submission.msgid,
        "X-Patchlab-Comment": comment["url"],
    }
    subject = "Re: " + " ".join(
        message_from_string(
            bridged_submission.submission.headers)["Subject"].splitlines())
    wrapped_description = "\n".join([
        textwrap.fill(line, width=72, replace_whitespace=False)
        for line in comment["note"].splitlines()
    ])
    body = (
        f"From: {author['name']} on {git_forge.host}\n{comment['url']}\n\n{wrapped_description}\n"
        f"")
    comment = EmailMessage(
        subject=subject,
        body=body,
        from_email=from_email,
        to=[git_forge.project.listemail],
        headers=headers,
        reply_to=[git_forge.project.listemail],
    )
    with get_connection(fail_silently=False) as conn:
        patchwork_parser.parse_mail(comment.message(),
                                    list_id=git_forge.project.listid)
        comment.connection = conn
        comment.send(fail_silently=False)
Beispiel #33
0
 def populate(self, email_message: EmailMessage, *args, **kwargs):
     self.subject = email_message.subject
     self.email_content = email_message.message().as_bytes()
     return super().populate(*args, **kwargs)
Beispiel #34
0
	def handle(self, *args, **options):
		check_date = datetime.date.today() - datetime.timedelta(days=settings.MINUTES_PUBLISH_REMINDER_DAYS)
		due_unpublished_minutes_documents = MinutesDocument.objects.filter(state=MinutesDocument.UNPUBLISHED, date=check_date)
		for minutes_document in due_unpublished_minutes_documents:
			if minutes_document.moderator and minutes_document.moderator.email:
				to_email = [minutes_document.moderator.email]
				cc_email = [minutes_document.author.email]
			else:
				to_email = [minutes_document.author.email]
				cc_email = []
			mail = EmailMessage(
				subject=_("Minutes publish reminder"),
				body=_('Please remember to publish the minutes document "{}" from {} ({}).'.format(
					minutes_document.title,
					minutes_document.date.strftime("%d.%m.%Y"),
					settings.PAGE_URL + minutes_document.get_view_url()
				)),
				to=to_email,
				cc=cc_email,
				bcc=[a[1] for a in settings.ADMINS]
			)
			try:
				mail.send(False)
			except Exception:
				logger.exception('An exception occurred when sending the following email to user "{}":\n{}\n'.format(minutes_document.author.username, mail.message()))
Beispiel #35
0
def sendHtmlEmail(to,
                  subject,
                  context,
                  template,
                  cc,
                  bcc,
                  from_email,
                  attachment1=None):

    email_delivery = env('EMAIL_DELIVERY', 'off')
    override_email = env('OVERRIDE_EMAIL', None)
    email_instance = env('EMAIL_INSTANCE', 'DEV')

    context['default_url'] = env('DEFAULT_URL', '')
    context['default_url_internal'] = env('DEFAULT_URL_INTERNAL', '')
    log_hash = int(
        hashlib.sha1(str(datetime.datetime.now()).encode('utf-8')).hexdigest(),
        16) % (10**8)
    if email_delivery != 'on':
        print("EMAIL DELIVERY IS OFF NO EMAIL SENT -- applications/email.py ")
        return False

    if template is None:
        raise ValidationError('Invalid Template')
    if to is None:
        raise ValidationError('Invalid Email')
    if subject is None:
        raise ValidationError('Invalid Subject')

    if from_email is None:
        if settings.DEFAULT_FROM_EMAIL:
            from_email = settings.DEFAULT_FROM_EMAIL
        else:
            from_email = '*****@*****.**'

    context['version'] = settings.APPLICATION_VERSION_NO
    # Custom Email Body Template
    context['body'] = get_template(template).render(context)
    # Main Email Template Style ( body template is populated in the center
    main_template = get_template('email-dpaw-template.html').render(context)

    if override_email is not None:
        to = override_email.split(",")
        if cc:
            cc = override_email.split(",")
        if bcc:
            bcc = override_email.split(",")

    if len(to) > 1:
        for to_email in to:
            msg = EmailMessage(subject,
                               main_template,
                               to=[to_email],
                               cc=cc,
                               from_email=from_email,
                               headers={'System-Environment': email_instance})
            msg.content_subtype = 'html'
            if attachment1:
                msg.attach_file(attachment1)

            #msg.send()

            try:
                email_log(str(log_hash) + ' ' + subject)
                msg.send()
                email_log(str(log_hash) + ' Successfully sent to mail gateway')
            except Exception as e:
                email_log(str(log_hash) + ' Error Sending - ' + str(e))

            #print ("MESSGE")
            #print (str(msg.message()))
    else:
        msg = EmailMessage(subject,
                           main_template,
                           to=to,
                           cc=cc,
                           from_email=from_email,
                           headers={'System-Environment': email_instance})
        msg.content_subtype = 'html'
        if attachment1:
            msg.attach_file(attachment1)
        #msg.send()
        #print ("MESSGE")
        #print (str(msg.message()))

        try:
            email_log(str(log_hash) + ' ' + subject)
            msg.send()
            email_log(str(log_hash) + ' Successfully sent to mail gateway')
        except Exception as e:
            email_log(str(log_hash) + ' Error Sending - ' + str(e))

    if 'app' in context:
        eml_content = msg.message().as_bytes()
        #file_name = settings.BASE_DIR+"/private-media/tmp/"+str(log_hash)+".msg"
        #with open(file_name, "wb") as outfile:
        #   outfile.write(eml_content)

        #f = open(file_name, "r")
        #       print(f.read())
        print("CLASS")
        print(":" + context['app'].__class__.__name__ + ":")
        if context['app'].__class__.__name__ == 'Compliance':
            print("LOADING")
            doc = models.Record()
            doc.upload.save(str(log_hash) + '.eml',
                            ContentFile(eml_content),
                            save=False)
            doc.name = str(log_hash) + '.eml'
            doc.file_group = 2007
            doc.file_group_ref_id = context['app'].id
            doc.extension = '.eml'
            doc.save()

            approval = approval_models.Approval.objects.get(
                id=context['app'].approval_id)
            comms = approval_models.CommunicationApproval.objects.create(
                approval=approval,
                comms_type=2,
                comms_to=str(to),
                comms_from=from_email,
                subject=subject,
                details='see attachment')
            comms.records.add(doc)
            comms.save()
        elif context['app'].__class__.__name__ == 'Approval':
            doc = models.Record()
            doc.upload.save(str(log_hash) + '.eml',
                            ContentFile(eml_content),
                            save=False)
            doc.name = str(log_hash) + '.eml'
            doc.file_group = 2007
            doc.file_group_ref_id = context['app'].id
            doc.extension = '.eml'
            doc.save()

            comms = approval_models.CommunicationApproval.objects.create(
                approval=context['app'],
                comms_type=2,
                comms_to=str(to),
                comms_from=from_email,
                subject=subject,
                details='see attachment')
            comms.records.add(doc)
            comms.save()
        else:
            doc = models.Record()
            doc.upload.save(str(log_hash) + '.eml',
                            ContentFile(eml_content),
                            save=False)
            doc.name = str(log_hash) + '.eml'
            doc.file_group = 2003
            doc.file_group_ref_id = context['app'].id
            doc.extension = '.eml'
            doc.save()

            comms = models.Communication.objects.create(
                application=context['app'],
                comms_type=2,
                comms_to=str(to),
                comms_from=from_email,
                subject=subject,
                details='see attachment')
            comms.records.add(doc)
            comms.save()
    return True
Beispiel #36
0
    def post(self, request):
        logger.debug('Send Email post call')
        csvfile = request.FILES.get('file', None)
        email_data = request.data.get('email_data', None)

        #TODO: do we have to validate email data here?
        if not email_data:
            logger.error('Email data is null')
            return Response({"response": "Invalid Email Data"},
                            status=status.HTTP_400_BAD_REQUEST)

        #validating csvfile
        if csvfile:
            if not csvfile.name.endswith('.csv'):
                logger.error('Uploaded file is not CSV:' + csvfile.name)
                return Response({"response": "Uploaded file is not CSV"},
                                status=status.HTTP_400_BAD_REQUEST)
            if csvfile.size > 1048576:
                logger.error('Uploaded file is more than 1MB:' + csvfile.size)
                return Response({"response": "Uploaded file is more than 1MB"},
                                status=status.HTTP_400_BAD_REQUEST)

        #converting json string to json object
        email_data = json.loads(email_data)

        #splitting comma separated values & stripping whitespaces from the list of strings
        to_list = split_and_strip(email_data.get('to', ''))
        bcc_list = split_and_strip(email_data.get('bcc', ''))
        cc_list = split_and_strip(email_data.get('cc', ''))
        subject = email_data.get('subject', '')
        body = email_data.get('body', '')

        #parsing csvfile
        if csvfile:
            file_reader = csv.reader(csvfile,
                                     delimiter=str(u',').encode('utf-8'))
            for row in file_reader:
                to_list.append(row[0])

        if not (is_valid_email(to_list) and is_valid_email(cc_list)
                and is_valid_email(bcc_list)):
            logger.error('Invalid Email Address')
            return Response({"response": "Invalid Email Address"},
                            status=status.HTTP_400_BAD_REQUEST)

        try:
            email = EmailMessage(subject, body, settings.EMAIL_HOST_USER,
                                 to_list)
            if cc_list:
                email.cc = cc_list

            if bcc_list:
                email.bcc = bcc_list

            logger.info("Email sent successfully:" + str(email.message()))

            is_success = email.send(fail_silently=False)
            if not is_success:
                logger.error('Error occured while sending emails')
                return Response(
                    {"response": "Error occured while sending emails"},
                    status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            #if successful, store the emails in DB
            store_email_data(to_list, 1, subject)
            store_email_data(cc_list, 2, subject)
            store_email_data(bcc_list, 3, subject)

        except Exception as e:
            logger.error('Exception while sending emails: ' + str(e))
            return Response({"response": "Error occured while sending emails"},
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        return Response({"response": "Sent successfully"},
                        status=status.HTTP_200_OK)
Beispiel #37
0
    def send_to_user(cls, user, template, subject_params, body_params, use_cc, request=None):
        if not user.email:
            warning_message = "{} has no email address defined. Could not send email.".format(user.username)
            # If this method is triggered by a cronjob changing course states, the request is None.
            # In this case warnings should be sent to the admins via email (configured in the settings for logger.error).
            # If a request exists, the page is displayed in the browser and the message can be shown on the page (messages.warning).
            if request is not None:
                logger.warning(warning_message)
                messages.warning(request, _(warning_message))
            else:
                logger.error(warning_message)
            return

        if use_cc:
            cc_users = set(user.delegates.all() | user.cc_users.all())
            cc_addresses = [p.email for p in cc_users if p.email]
        else:
            cc_addresses = []

        send_separate_login_url = False
        body_params['login_url'] = ""
        if user.needs_login_key:
            user.generate_login_key()
            if not cc_addresses:
                body_params['login_url'] = user.login_url
            else:
                send_separate_login_url = True

        subject = cls.__render_string(template.subject, subject_params)
        body = cls.__render_string(template.body, body_params)

        mail = EmailMessage(
            subject=subject,
            body=body,
            to=[user.email],
            cc=cc_addresses,
            bcc=[a[1] for a in settings.MANAGERS],
            headers={'Reply-To': settings.REPLY_TO_EMAIL})

        try:
            mail.send(False)
            logger.info(('Sent email "{}" to {}.').format(subject, user.username))
            if send_separate_login_url:
                cls.send_login_url_to_user(user)
        except Exception:
            logger.exception('An exception occurred when sending the following email to user "{}":\n{}\n'.format(user.username, mail.message()))
Beispiel #38
0
    def __send_to_user(cls, user, template, subject_params, body_params, cc):
        if not user.email:
            logger.warning("{} has no email address defined. Could not send email.".format(user.username))
            return

        if cc:
            cc_users = set(user.delegates.all() | user.cc_users.all())
            cc_addresses = [p.email for p in cc_users if p.email]
        else:
            cc_addresses = []

        subject = cls.__render_string(template.subject, subject_params)
        body = cls.__render_string(template.body, body_params)

        mail = EmailMessage(
            subject = subject,
            body = body,
            to = [user.email],
            cc = cc_addresses,
            bcc = [a[1] for a in settings.MANAGERS],
            headers = {'Reply-To': settings.REPLY_TO_EMAIL})

        try:
            mail.send(False)
            logger.info(('Sent email "{}" to {}.').format(subject, user.username))
        except Exception:
            logger.exception('An exception occurred when sending the following email to user "{}":\n{}\n'.format(user.username, mail.message()))
                template=config['template'], user=repr(user)))
            ctx = dict(global_context)
            ctx.update(
                dict(user=user,
                     site=Site.objects.get_current(),
                     datetime=datetime.datetime.utcnow()))
            email = EmailMessage(
                subject='%s %s' %
                (settings.EMAIL_SUBJECT_PREFIX, config['subject']),
                body=template.render(Context(ctx)),
                from_email=settings.DEFAULT_FROM_EMAIL,
                to=(user.email, ),
                headers={'Reply-To': settings.DEFAULT_SUPPORT_EMAIL})
            try:
                if args.simulate:
                    print email.message()
                else:
                    email.send()
            except Exception as error:
                log.exception('There was error while sending email to %r' %
                              user)
                continue
            cache[user.pk] = dict(pk=user.pk,
                                  email=user.email,
                                  timestamp=datetime.datetime.utcnow())
    finally:
        if not args.simulate:
            log.debug('saving cache')
            open(cache_path,
                 'w').write(yaml.dump(cache, default_flow_style=False))
else:
Beispiel #40
0
    def __send_to_user(cls, user, template, subject_params, body_params, use_cc, request=None):
        if not user.email:
            warning_message = "{} has no email address defined. Could not send email.".format(user.username)
            logger.warning(warning_message)
            if request is not None:
                messages.warning(request, _(warning_message))
            return

        if use_cc:
            cc_users = set(user.delegates.all() | user.cc_users.all())
            cc_addresses = [p.email for p in cc_users if p.email]
        else:
            cc_addresses = []

        send_separate_login_url = False
        body_params['login_url'] = ""
        if user.needs_login_key:
            user.generate_login_key()
            if not cc_addresses:
                body_params['login_url'] = user.login_url
            else:
                send_separate_login_url = True

        subject = cls.__render_string(template.subject, subject_params)
        body = cls.__render_string(template.body, body_params)

        mail = EmailMessage(
            subject=subject,
            body=body,
            to=[user.email],
            cc=cc_addresses,
            bcc=[a[1] for a in settings.MANAGERS],
            headers={'Reply-To': settings.REPLY_TO_EMAIL})

        try:
            mail.send(False)
            logger.info(('Sent email "{}" to {}.').format(subject, user.username))
            if send_separate_login_url:
                cls.send_login_url_to_user(user)
        except Exception:
            logger.exception('An exception occurred when sending the following email to user "{}":\n{}\n'.format(user.username, mail.message()))
Beispiel #41
0
 def test_recipients_as_tuple(self):
     email = EmailMessage('Subject', 'Content', '*****@*****.**', ('*****@*****.**', '*****@*****.**'), cc=('*****@*****.**', '*****@*****.**'), bcc=('*****@*****.**',))
     message = email.message()
     self.assertEqual(message['Cc'], '[email protected], [email protected]')
     self.assertEqual(email.recipients(), ['*****@*****.**', '*****@*****.**', '*****@*****.**', '*****@*****.**', '*****@*****.**'])
Beispiel #42
0
 def test_dont_mangle_from_in_body(self):
     # Regression for #13433 - Make sure that EmailMessage doesn't mangle
     # 'From ' in message body.
     email = EmailMessage('Subject', 'From the future', '*****@*****.**', ['*****@*****.**'], headers={'From': '*****@*****.**'})
     self.assertFalse(b'>From the future' in email.message().as_bytes())
Beispiel #43
0
    def send_to_user(cls, user, template, subject_params, body_params, use_cc, request=None):
        if not user.email:
            warning_message = "{} has no email address defined. Could not send email.".format(user.username)
            # If this method is triggered by a cronjob changing course states, the request is None.
            # In this case warnings should be sent to the admins via email (configured in the settings for logger.error).
            # If a request exists, the page is displayed in the browser and the message can be shown on the page (messages.warning).
            if request is not None:
                logger.warning(warning_message)
                messages.warning(request, _(warning_message))
            else:
                logger.error(warning_message)
            return

        if use_cc:
            cc_users = set(user.delegates.all() | user.cc_users.all())
            cc_addresses = [p.email for p in cc_users if p.email]
        else:
            cc_addresses = []

        send_separate_login_url = False
        body_params['login_url'] = ""
        if user.needs_login_key:
            user.ensure_valid_login_key()
            if not cc_addresses:
                body_params['login_url'] = user.login_url
            else:
                send_separate_login_url = True

        subject = cls.render_string(template.subject, subject_params)
        body = cls.render_string(template.body, body_params)

        mail = EmailMessage(
            subject=subject,
            body=body,
            to=[user.email],
            cc=cc_addresses,
            bcc=[a[1] for a in settings.MANAGERS],
            headers={'Reply-To': settings.REPLY_TO_EMAIL})

        try:
            mail.send(False)
            logger.info(('Sent email "{}" to {}.').format(subject, user.username))
            if send_separate_login_url:
                cls.send_login_url_to_user(user)
        except Exception:
            logger.exception('An exception occurred when sending the following email to user "{}":\n{}\n'.format(user.username, mail.message()))
Beispiel #44
0
 def test_recipients_as_tuple(self):
     email = EmailMessage('Subject', 'Content', '*****@*****.**', ('*****@*****.**', '*****@*****.**'), cc=('*****@*****.**', '*****@*****.**'), bcc=('*****@*****.**',))
     message = email.message()
     self.assertEqual(message['Cc'], '[email protected], [email protected]')
     self.assertEqual(email.recipients(), ['*****@*****.**', '*****@*****.**', '*****@*****.**', '*****@*****.**', '*****@*****.**'])
def notify_users(subject_text=None,
                 body_text=None,
                 all_users=False,
                 admins=False,
                 managers=False,
                 superusers=False,
                 staff=False,
                 bcc=False,
                 subject_template=None,
                 body_template=None,
                 dry_run=False,
                 request=None,
                 **kwargs):
    """
    Send an email notification to selected site users.
    """
    # Determine which user types should be notified.
    admins = admins or all_users
    managers = managers or all_users
    if auth_is_installed():
        superusers = superusers or all_users
        staff = staff or all_users
        user_model = get_user_model()
    else:
        superusers = False
        staff = False
        user_model = None
    if not (admins or managers or superusers or staff):
        default_recipients = set(
            get_site_utils_setting('SITE_NOTIFY_DEFAULT_RECIPIENTS'))
        admins = 'admins' in default_recipients
        managers = 'managers' in default_recipients
        if auth_is_installed():
            superusers = 'superusers' in default_recipients
            staff = 'staff' in default_recipients

    # Build full list of recipients.
    recipients = collections.OrderedDict()
    if admins:
        for name, email in settings.ADMINS:
            recipients.setdefault(email, name)
    if managers:
        for name, email in settings.MANAGERS:
            recipients.setdefault(email, name)
    if superusers and user_model:
        for user in user_model.objects.exclude(email='').filter(
                is_active=True, is_superuser=True):
            recipients.setdefault(user.email,
                                  user.get_full_name() or user.email)
    if staff and user_model:
        for user in user_model.objects.exclude(email='').filter(is_active=True,
                                                                is_staff=True):
            recipients.setdefault(user.email,
                                  user.get_full_name() or user.email)

    # Render subject and body of notification.
    # TODO: Future feature: render subject/body per recipient.
    subject_template = subject_template or get_site_utils_setting(
        'SITE_NOTIFY_SUBJECT_TEMPLATE')
    body_template = body_template or get_site_utils_setting(
        'SITE_NOTIFY_BODY_TEMPLATE')
    subject_text = subject_text if subject_text is not None else 'Site Notification'
    if isinstance(body_text, (list, tuple)):
        body_text = '\n\n'.join(body_text)
    context = dict(subject=subject_text, body=body_text)
    request = request or RequestFactory().get('/')
    subject = render_to_string(subject_template, context, request)
    subject = ' '.join(
        filter(None, map(lambda x: x.strip(), subject.splitlines())))
    subject = settings.EMAIL_SUBJECT_PREFIX + subject
    body = render_to_string(body_template, context, request)

    # Create and send the email.
    email_kwargs = dict(subject=subject, body=body)
    # FIXME: Sanitize user full name and email?
    email_recipients = [
        '"{}" <{}>'.format(v, k) for k, v in recipients.items()
    ]
    email_kwargs['bcc' if bcc else 'to'] = email_recipients
    email_message = EmailMessage(**email_kwargs)
    if dry_run:
        print(force_text(email_message.message()))
    else:
        email_message.send()