Ejemplo n.º 1
0
    def test_all_options(self):
        message = AnymailMessage(
            subject="Anymail Postal all-options integration test",
            body="This is the text body",
            from_email="Test From <*****@*****.**>",
            envelope_sender="*****@*****.**",
            to=[
                "*****@*****.**", "Recipient 2 <*****@*****.**>"
            ],
            cc=["*****@*****.**", "Copy 2 <*****@*****.**>"],
            bcc=[
                "*****@*****.**",
                "Blind Copy 2 <*****@*****.**>"
            ],
            reply_to=["*****@*****.**"],
            headers={"X-Anymail-Test": "value"},
            tags=["tag 1"],  # max one tag
        )
        message.attach("attachment1.txt", "Here is some\ntext for you",
                       "text/plain")
        message.attach("attachment2.csv", "ID,Name\n1,Amy Lina", "text/csv")

        message.send()
        self.assertEqual(message.anymail_status.status, {'queued'})
        self.assertEqual(
            message.anymail_status.recipients['*****@*****.**'].status,
            'queued')
        self.assertEqual(
            message.anymail_status.recipients['*****@*****.**'].status,
            'queued')
        # distinct messages should have different message_ids:
        self.assertNotEqual(
            message.anymail_status.recipients['*****@*****.**'].
            message_id, message.anymail_status.
            recipients['*****@*****.**'].message_id)
    def test_all_options(self):
        message = AnymailMessage(
            subject="Anymail all-options integration test",
            body="This is the text body",
            from_email="Test From <*****@*****.**>",
            to=["*****@*****.**", "Recipient 2 <*****@*****.**>"],
            cc=["*****@*****.**", "Copy 2 <*****@*****.**>"],
            bcc=["*****@*****.**", "Blind Copy 2 <*****@*****.**>"],
            reply_to=["*****@*****.**", "Reply 2 <*****@*****.**>"],
            headers={"X-Anymail-Test": "value"},

            # no metadata, send_at, track_clicks support
            tags=["tag 1"],  # max one tag
            track_opens=True,
        )
        message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain")
        message.attach("attachment2.csv", "ID,Name\n1,Amy Lina", "text/csv")
        cid = message.attach_inline_image_file(sample_image_path())
        message.attach_alternative(
            "<p><b>HTML:</b> with <a href='http://example.com'>link</a>"
            "and image: <img src='cid:%s'></div>" % cid,
            "text/html")

        message.send()
        self.assertTrue(message.anymail_status.status.issubset({'queued', 'sent'}))
    def test_all_options(self):
        send_at = datetime.now().replace(microsecond=0) + timedelta(minutes=2)
        message = AnymailMessage(
            subject="Anymail all-options integration test FILES",
            body="This is the text body",
            from_email="Test From <*****@*****.**>",
            to=["*****@*****.**", "Recipient 2 <*****@*****.**>"],
            cc=["*****@*****.**", "Copy 2 <*****@*****.**>"],
            bcc=["*****@*****.**", "Blind Copy 2 <*****@*****.**>"],
            reply_to=["*****@*****.**", "Reply 2 <*****@*****.**>"],
            headers={"X-Anymail-Test": "value"},

            metadata={"meta1": "simple string", "meta2": 2},
            send_at=send_at,
            tags=["tag 1", "tag 2"],
            track_clicks=True,
            track_opens=True,
        )
        message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain")
        message.attach("attachment2.csv", "ID,Name\n1,Amy Lina", "text/csv")
        cid = message.attach_inline_image_file(sample_image_path())
        message.attach_alternative(
            "<p><b>HTML:</b> with <a href='http://example.com'>link</a>"
            "and image: <img src='cid:%s'></div>" % cid,
            "text/html")

        message.send()
        self.assertEqual(message.anymail_status.status, {'queued'})  # SendGrid always queues
Ejemplo n.º 4
0
    def email_user(self,
                   subject,
                   context,
                   text_template,
                   html_template=None,
                   tag='Default'):
        from django.template.loader import render_to_string

        context['user'] = self
        text_message = render_to_string(text_template, context)
        if html_template:
            html_message = render_to_string(html_template, context)
        else:
            html_message = None

        # send_mail(subject, text_message, settings.DEFAULT_FROM_EMAIL, [self.email], fail_silently=False,
        #           html_message=html_message)

        message = AnymailMessage(
            subject=subject,
            body=text_message,
            to=["%s <%s>" % (self.full_name or self.username, self.email)],
            tags=[tag],
        )
        if html_message:
            message.attach_alternative(html_message, 'text/html')
        message.track_clicks = True
        message.send()
    def handle_prison(self, credit_notice_email, path, date, **options):
        call_command(
            'create_prisoner_credit_notices',
            path, credit_notice_email.prison.nomis_id,
            date=date, **options
        )
        if not path.exists():
            if self.verbosity:
                self.stdout.write('Nothing to send to %s' % credit_notice_email)
            return

        template_context = prepare_context()
        text_body = template_loader.get_template('credit/prisoner-notice-email.txt').render(template_context)
        html_body = template_loader.get_template('credit/prisoner-notice-email.html').render(template_context)
        email = AnymailMessage(
            subject=str(self.subject),
            body=text_body.strip('\n'),
            from_email=self.from_address,
            to=[credit_notice_email.email],
            tags=['prisoner-notice'],
        )
        email.attach_alternative(html_body, 'text/html')
        email.attach_file(str(path), mimetype='application/pdf')

        if self.verbosity:
            self.stdout.write('Sending prisoner notice email to %s' % credit_notice_email)
        email.send()
Ejemplo n.º 6
0
 def test_stored_template(self):
     message = AnymailMessage(
         template_id=
         'test-template',  # name of a real template named in Anymail's Mailgun test account
         subject=
         'Your order %recipient.order%',  # Mailgun templates don't define subject
         from_email=
         'Test From <*****@*****.**>',  # Mailgun templates don't define sender
         to=["*****@*****.**"],
         # metadata and merge_data must not have any conflicting keys when using template_id
         metadata={
             "meta1": "simple string",
             "meta2": 2
         },
         merge_data={'*****@*****.**': {
             'name': "Test Recipient",
         }},
         merge_global_data={
             'order': '12345',
         },
     )
     message.send()
     recipient_status = message.anymail_status.recipients
     self.assertEqual(recipient_status['*****@*****.**'].status,
                      'queued')
def send_report(period_description, report_path, emails):
    email = AnymailMessage(
        subject=f'Prisoner money notifications for {period_description}',
        body=f"""
OFFICIAL SENSITIVE

Please find attached, the prisoner money notifications report for {period_description}.

There is a separate sheet for each notification rule for credits and disbursements.

The ‘Monitored by’ column that appears in some sheets is the number of users
who are monitoring that prisoner or payment source.

The ‘How many?’ column that appears in some sheets is the number that triggered
the rule in column A. For example, if the ‘How many?’ column says 4 for the rule
‘More than 2 credits from the same debit card or bank account to any prisoner in a week’,
then this means that a specific debit card or bank account sent 4 credits in a week
up to when that credit was sent.

If you have any queries, contact the team at {settings.TEAM_EMAIL}.
        """.strip(),
        from_email=default_from_address(),
        to=emails,
        tags=['notifications-report'],
    )
    email.attach_file(str(report_path), mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
    email.send()
    def test_all_options(self):
        send_at = datetime.now() + timedelta(minutes=2)
        message = AnymailMessage(
            subject="Anymail all-options integration test",
            body="This is the text body",
            from_email="Test From <*****@*****.**>",
            to=["*****@*****.**", "Recipient 2 <*****@*****.**>"],
            cc=["*****@*****.**", "Copy 2 <*****@*****.**>"],
            bcc=["*****@*****.**", "Blind Copy 2 <*****@*****.**>"],
            reply_to=["*****@*****.**", "Reply 2 <*****@*****.**>"],
            headers={"X-Anymail-Test": "value"},

            metadata={"meta1": "simple string", "meta2": 2},
            send_at=send_at,
            tags=["tag 1"],  # SparkPost only supports single tags
            track_clicks=True,
            track_opens=True,
        )
        message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain")
        message.attach("attachment2.csv", "ID,Name\n1,Amy Lina", "text/csv")
        cid = message.attach_inline_image_file(sample_image_path())
        message.attach_alternative(
            "<p><b>HTML:</b> with <a href='http://example.com'>link</a>"
            "and image: <img src='cid:%s'></div>" % cid,
            "text/html")

        message.send()
        self.assertEqual(message.anymail_status.status, {'queued'})  # SparkPost always queues
    def test_all_options(self):
        message = AnymailMessage(
            subject="Anymail all-options integration test",
            body="This is the text body",
            from_email='"Test Sender, Inc." <*****@*****.**>',
            to=['*****@*****.**', '"Recipient, 2nd" <*****@*****.**>'],
            cc=['*****@*****.**', 'Copy 2 <*****@*****.**>'],
            bcc=['*****@*****.**', 'Blind Copy 2 <*****@*****.**>'],
            reply_to=['*****@*****.**', '"Reply, 2nd" <*****@*****.**>'],
            headers={"X-Anymail-Test": "value"},

            metadata={"meta1": "simple string", "meta2": 2},
            tags=["tag 1"],  # Mailjet only allows a single tag
            track_clicks=True,
            track_opens=True,
        )
        message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain")
        message.attach("attachment2.csv", "ID,Name\n1,Amy Lina", "text/csv")
        cid = message.attach_inline_image_file(sample_image_path())
        message.attach_alternative(
            "<p><b>HTML:</b> with <a href='http://example.com'>link</a>"
            "and image: <img src='cid:%s'></div>" % cid,
            "text/html")

        message.send()
        self.assertEqual(message.anymail_status.status, {'sent'})
Ejemplo n.º 10
0
    def test_all_options(self):
        message = AnymailMessage(
            subject="Anymail all-options integration test",
            body="This is the text body",
            from_email="Test From <*****@*****.**>",
            to=["*****@*****.**", "Recipient 2 <*****@*****.**>"],
            cc=["*****@*****.**", "Copy 2 <*****@*****.**>"],
            bcc=["*****@*****.**", "Blind Copy 2 <*****@*****.**>"],
            reply_to=["*****@*****.**", "Reply 2 <*****@*****.**>"],
            headers={"X-Anymail-Test": "value"},

            # no metadata, send_at, track_clicks support
            tags=["tag 1"],  # max one tag
            track_opens=True,
        )
        message.attach("attachment1.txt", "Here is some\ntext for you",
                       "text/plain")
        message.attach("attachment2.csv", "ID,Name\n1,Amy Lina", "text/csv")
        cid = message.attach_inline_image_file(sample_image_path())
        message.attach_alternative(
            "<p><b>HTML:</b> with <a href='http://example.com'>link</a>"
            "and image: <img src='cid:%s'></div>" % cid, "text/html")

        message.send()
        self.assertTrue(
            message.anymail_status.status.issubset({'queued', 'sent'}))
Ejemplo n.º 11
0
    def test_template(self):
        message = AnymailMessage(
            template_id=
            1,  # There is a template with this id in the Anymail test account
            to=[
                "*****@*****.**"
            ],  # SendinBlue doesn't allow recipient display names with templates
            reply_to=["*****@*****.**"],
            tags=["using-template"],
            headers={"X-Anymail-Test": "group: A, variation: C"},
            merge_global_data={
                # The Anymail test template includes `%SHIP_DATE%` and `%ORDER_ID%` variables
                "SHIP_DATE": "yesterday",
                "ORDER_ID": "12345",
            },
            metadata={
                "customer-id": "ZXK9123",
                "meta2": 2
            },
        )
        message.from_email = None  # Required for SendinBlue templates

        message.attach("attachment1.txt", "Here is some\ntext for you",
                       "text/plain")

        message.send()
        self.assertEqual(message.anymail_status.status,
                         {'queued'})  # SendinBlue always queues
        self.assertRegex(message.anymail_status.message_id, r'\<.+@.+\>')
Ejemplo n.º 12
0
    def handle_prison(self, credit_notice_email, path, date, **options):
        call_command('create_prisoner_credit_notices',
                     path,
                     credit_notice_email.prison.nomis_id,
                     date=date,
                     **options)
        if not path.exists():
            if self.verbosity:
                self.stdout.write('Nothing to send to %s' %
                                  credit_notice_email)
            return

        template_context = {
            'static_url': urljoin(settings.SITE_URL, settings.STATIC_URL),
        }
        text_body = template_loader.get_template(
            'credit/prisoner-notice-email.txt').render(template_context)
        html_body = template_loader.get_template(
            'credit/prisoner-notice-email.html').render(template_context)
        email = AnymailMessage(
            subject=self.subject,
            body=text_body.strip('\n'),
            from_email=self.from_address,
            to=[credit_notice_email.email],
            tags=['prisoner-notice'],
        )
        email.attach_alternative(html_body, 'text/html')
        email.attach_file(str(path), mimetype='application/pdf')

        if self.verbosity:
            self.stdout.write('Sending prisoner notice email to %s' %
                              credit_notice_email)
        email.send()
    def test_all_options(self):
        message = AnymailMessage(
            subject="Anymail Amazon SES all-options integration test",
            body="This is the text body",
            from_email='"Test From" <*****@*****.**>',
            to=["*****@*****.**", "Recipient 2 <*****@*****.**>"],
            cc=["*****@*****.**", "Copy 2 <*****@*****.**>"],
            bcc=["*****@*****.**", "Blind Copy 2 <*****@*****.**>"],
            reply_to=["*****@*****.**", "Reply 2 <*****@*****.**>"],
            headers={"X-Anymail-Test": "value"},
            metadata={"meta1": "simple_string", "meta2": 2},
            tags=["Re-engagement", "Cohort 12/2017"],
        )
        message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain")
        message.attach("attachment2.csv", "ID,Name\n1,Amy Lina", "text/csv")
        cid = message.attach_inline_image_file(sample_image_path())
        message.attach_alternative(
            "<p><b>HTML:</b> with <a href='http://example.com'>link</a>"
            "and image: <img src='cid:%s'></div>" % cid,
            "text/html")

        message.attach_alternative(
            "Amazon SES SendRawEmail actually supports multiple alternative parts",
            "text/x-note-for-email-geeks")

        message.send()
        self.assertEqual(message.anymail_status.status, {'queued'})
 def test_merge_data(self):
     message = AnymailMessage(
         subject="Anymail merge_data test: %field%",
         body="This body includes merge data: %field%",
         from_email="Test From <*****@*****.**>",
         to=[
             "*****@*****.**", "Recipient 2 <*****@*****.**>"
         ],
         reply_to=[
             '"Merge data in reply name: %field%" <*****@*****.**>'
         ],
         merge_data={
             '*****@*****.**': {
                 'field': 'one'
             },
             '*****@*****.**': {
                 'field': 'two'
             },
         },
         esp_extra={
             'merge_field_format': '%{}%',
         },
     )
     message.send()
     recipient_status = message.anymail_status.recipients
     self.assertEqual(recipient_status['*****@*****.**'].status,
                      'queued')
     self.assertEqual(recipient_status['*****@*****.**'].status,
                      'queued')
Ejemplo n.º 15
0
    def flag_for_review(self, approval_request):
        """
        Mark this hosting provider as in need of review by admins.
        Sends an notification via email to admins.
        """

        #  notify_admin_via_email(approval_request)
        provider = approval_request.hostingprovider
        link_path = reverse(
            "greenweb_admin:accounts_hostingprovider_change", args=[provider.id]
        )
        link_url = f"{settings.SITE_URL}{link_path}"
        ctx = {
            "approval_request": approval_request,
            "provider": provider,
            "link_url": link_url,
        }
        notification_subject = (
            f"TGWF: {approval_request.hostingprovider} - "
            "has been updated and needs a review"
        )

        notification_email_copy = render_to_string("flag_for_review_text.txt", ctx)
        notification_email_html = render_to_string("flag_for_review_text.html", ctx)

        msg = AnymailMessage(
            subject=notification_subject,
            body=notification_email_copy,
            to=["*****@*****.**"],
        )

        msg.attach_alternative(notification_email_html, "text/html")
        msg.send()
 def test_stored_template(self):
     # Using a template created like this:
     # boto3.client('ses').create_template(Template={
     #     "TemplateName": "TestTemplate",
     #     "SubjectPart": "Your order {{order}} shipped",
     #     "HtmlPart": "<h1>Dear {{name}}:</h1><p>Your order {{order}} shipped {{ship_date}}.</p>",
     #     "TextPart": "Dear {{name}}:\r\nYour order {{order}} shipped {{ship_date}}."
     # })
     message = AnymailMessage(
         template_id='TestTemplate',
         from_email='"Test From" <*****@*****.**>',
         to=["First Recipient <*****@*****.**>",
             "*****@*****.**"],
         merge_data={
             '*****@*****.**': {'order': 12345, 'name': "Test Recipient"},
             '*****@*****.**': {'order': 6789},
         },
         merge_global_data={
             'name': "Customer",  # default
             'ship_date': "today"
         },
     )
     message.send()
     recipient_status = message.anymail_status.recipients
     self.assertEqual(recipient_status['*****@*****.**'].status, 'queued')
     self.assertRegex(recipient_status['*****@*****.**'].message_id, r'[0-9a-f-]+')
     self.assertEqual(recipient_status['*****@*****.**'].status, 'queued')
     self.assertRegex(recipient_status['*****@*****.**'].message_id, r'[0-9a-f-]+')
Ejemplo n.º 17
0
    def test_all_options(self):
        message = AnymailMessage(
            subject="Anymail Mailjet all-options integration test",
            body="This is the text body",
            from_email='"Test Sender, Inc." <*****@*****.**>',
            to=[
                '*****@*****.**',
                '"Recipient, 2nd" <*****@*****.**>'
            ],
            cc=['*****@*****.**', 'Copy 2 <*****@*****.**>'],
            bcc=[
                '*****@*****.**',
                'Blind Copy 2 <*****@*****.**>'
            ],
            reply_to=['"Reply, To" <*****@*****.**>'
                      ],  # Mailjet only supports single reply_to
            headers={"X-Anymail-Test": "value"},
            metadata={
                "meta1": "simple string",
                "meta2": 2
            },
            tags=["tag 1"],  # Mailjet only allows a single tag
            track_clicks=True,
            track_opens=True,
        )
        message.attach("attachment1.txt", "Here is some\ntext for you",
                       "text/plain")
        message.attach("attachment2.csv", "ID,Name\n1,Amy Lina", "text/csv")
        cid = message.attach_inline_image_file(sample_image_path())
        message.attach_alternative(
            "<p><b>HTML:</b> with <a href='http://example.com'>link</a>"
            "and image: <img src='cid:%s'></div>" % cid, "text/html")

        message.send()
        self.assertEqual(message.anymail_status.status, {'sent'})
 def test_merge_data(self):
     message = AnymailMessage(
         subject="Anymail merge_data test: {{ value }}",
         body="This body includes merge data: {{ value }}\n"
         "And global merge data: {{ global }}",
         from_email="Test From <*****@*****.**>",
         to=[
             "*****@*****.**",
             "Recipient 2 <*****@*****.**>"
         ],
         merge_data={
             '*****@*****.**': {
                 'value': 'one'
             },
             '*****@*****.**': {
                 'value': 'two'
             },
         },
         merge_global_data={'global': 'global_value'},
     )
     message.send()
     recipient_status = message.anymail_status.recipients
     self.assertEqual(
         recipient_status['*****@*****.**'].status,
         'queued')
     self.assertEqual(
         recipient_status['*****@*****.**'].status,
         'queued')
Ejemplo n.º 19
0
    def test_all_options(self):
        send_at = datetime.now().replace(microsecond=0) + timedelta(minutes=2)
        message = AnymailMessage(
            subject="Anymail all-options integration test",
            body="This is the text body",
            from_email='"Test From, with comma" <*****@*****.**>',
            to=["*****@*****.**", '"Recipient 2, OK?" <*****@*****.**>'],
            cc=["*****@*****.**", "Copy 2 <*****@*****.**>"],
            bcc=["*****@*****.**", "Blind Copy 2 <*****@*****.**>"],
            reply_to=['"Reply, with comma" <*****@*****.**>'],  # v3 only supports single reply-to
            headers={"X-Anymail-Test": "value", "X-Anymail-Count": 3},

            metadata={"meta1": "simple string", "meta2": 2},
            send_at=send_at,
            tags=["tag 1", "tag 2"],
            track_clicks=True,
            track_opens=True,
            # esp_extra={'asm': {'group_id': 1}},  # this breaks activity feed if you don't have an asm group
        )
        message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain")
        message.attach("attachment2.csv", "ID,Name\n1,Amy Lina", "text/csv")
        cid = message.attach_inline_image_file(sample_image_path())
        message.attach_alternative(
            "<p><b>HTML:</b> with <a href='http://example.com'>link</a>"
            "and image: <img src='cid:%s'></div>" % cid,
            "text/html")

        message.send()
        self.assertEqual(message.anymail_status.status, {'queued'})  # SendGrid always queues
    def test_template(self):
        message = AnymailMessage(
            template_id=5,  # There is a *new-style* template with this id in the Anymail test account
            from_email='Sender <*****@*****.**>',  # Override template sender
            to=["Recipient <*****@*****.**>"],  # No batch send (so max one recipient suggested)
            reply_to=["Do not reply <*****@*****.**>"],
            tags=["using-template"],
            headers={"X-Anymail-Test": "group: A, variation: C"},
            merge_global_data={
                # The Anymail test template includes `{{ params.SHIP_DATE }}`
                # and `{{ params.ORDER_ID }}` substitutions
                "SHIP_DATE": "yesterday",
                "ORDER_ID": "12345",
            },
            metadata={"customer-id": "ZXK9123", "meta2": 2},
        )

        # Normal attachments don't work with Sendinblue templates:
        #   message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain")
        # If you can host the attachment content on some publicly-accessible URL,
        # this *non-portable* alternative allows sending attachments with templates:
        message.esp_extra = {
            'attachment': [{
                'name': 'attachment1.txt',
                # URL where Sendinblue can download the attachment content while sending:
                'url': 'https://raw.githubusercontent.com/anymail/django-anymail/master/AUTHORS.txt',
            }]
        }

        message.send()
        self.assertEqual(message.anymail_status.status, {'queued'})  # SendinBlue always queues
        self.assertRegex(message.anymail_status.message_id, r'\<.+@.+\>')
    def test_all_options(self):
        message = AnymailMessage(
            subject="Anymail Postmark all-options integration test",
            body="This is the text body",
            # Postmark accepts multiple from_email addresses, but truncates to the first on their end
            from_email="Test From <*****@*****.**>, [email protected]",
            to=["*****@*****.**", "Recipient 2 <*****@*****.**>"],
            cc=["*****@*****.**", "Copy 2 <*****@*****.**>"],
            bcc=["*****@*****.**", "Blind Copy 2 <*****@*****.**>"],
            reply_to=["*****@*****.**", "Reply 2 <*****@*****.**>"],
            headers={"X-Anymail-Test": "value"},

            # no metadata, send_at, track_clicks support
            tags=["tag 1"],  # max one tag
            track_opens=True,
            track_clicks=True,
        )
        message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain")
        message.attach("attachment2.csv", "ID,Name\n1,Amy Lina", "text/csv")
        cid = message.attach_inline_image_file(sample_image_path())
        message.attach_alternative(
            "<p><b>HTML:</b> with <a href='http://example.com'>link</a>"
            "and image: <img src='cid:%s'></div>" % cid,
            "text/html")

        message.send()
        self.assertEqual(message.anymail_status.status, {'sent'})
Ejemplo n.º 22
0
 def test_merge_data(self):
     message = AnymailMessage(
         subject=
         "Anymail Mailjet merge_data test",  # Mailjet doesn't support merge fields in the subject
         body="This body includes merge data: [[var:value]]\n"
         "And global merge data: [[var:global]]",
         from_email="Test From <*****@*****.**>",
         to=[
             "*****@*****.**", "Recipient 2 <*****@*****.**>"
         ],
         merge_data={
             '*****@*****.**': {
                 'value': 'one'
             },
             '*****@*****.**': {
                 'value': 'two'
             },
         },
         merge_global_data={'global': 'global_value'},
     )
     message.send()
     recipient_status = message.anymail_status.recipients
     self.assertEqual(recipient_status['*****@*****.**'].status,
                      'sent')
     self.assertEqual(recipient_status['*****@*****.**'].status,
                      'sent')
    def test_all_options(self):
        send_at = datetime.now().replace(microsecond=0) + timedelta(minutes=2)
        message = AnymailMessage(
            subject="Anymail all-options integration test",
            body="This is the text body",
            from_email='"Test From, with comma" <*****@*****.**>',
            to=["*****@*****.**", '"Recipient 2, OK?" <*****@*****.**>'],
            cc=["*****@*****.**", "Copy 2 <*****@*****.**>"],
            bcc=["*****@*****.**", "Blind Copy 2 <*****@*****.**>"],
            reply_to=['"Reply, with comma" <*****@*****.**>'],  # v3 only supports single reply-to
            headers={"X-Anymail-Test": "value", "X-Anymail-Count": 3},

            metadata={"meta1": "simple string", "meta2": 2},
            send_at=send_at,
            tags=["tag 1", "tag 2"],
            track_clicks=True,
            track_opens=True,
            # esp_extra={'asm': {'group_id': 1}},  # this breaks activity feed if you don't have an asm group
        )
        message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain")
        message.attach("attachment2.csv", "ID,Name\n1,Amy Lina", "text/csv")
        cid = message.attach_inline_image_file(sample_image_path())
        message.attach_alternative(
            "<p><b>HTML:</b> with <a href='http://example.com'>link</a>"
            "and image: <img src='cid:%s'></div>" % cid,
            "text/html")

        message.send()
        self.assertEqual(message.anymail_status.status, {'queued'})  # SendGrid always queues
    def test_merge_data(self):
        self.set_mock_response(raw=self._mock_batch_response)
        message = AnymailMessage(
            from_email='*****@*****.**',
            template_id=
            1234567,  # Postmark only supports merge_data content in a template
            to=['*****@*****.**', 'Bob <*****@*****.**>'],
            merge_data={
                '*****@*****.**': {
                    'name': "Alice",
                    'group': "Developers"
                },
                '*****@*****.**': {
                    'name': "Bob"
                },  # and leave group undefined
                '*****@*****.**': {
                    'name': "Not a recipient for this message"
                },
            },
            merge_global_data={
                'group': "Users",
                'site': "ExampleCo"
            })
        message.send()

        self.assert_esp_called('/email/batchWithTemplates')
        data = self.get_api_call_json()
        messages = data["Messages"]
        self.assertEqual(len(messages), 2)
        self.assertEqual(
            messages[0], {
                "From": "*****@*****.**",
                "To": "*****@*****.**",
                "TemplateId": 1234567,
                "TemplateModel": {
                    "name": "Alice",
                    "group": "Developers",
                    "site": "ExampleCo"
                },
            })
        self.assertEqual(
            messages[1], {
                "From": "*****@*****.**",
                "To": "Bob <*****@*****.**>",
                "TemplateId": 1234567,
                "TemplateModel": {
                    "name": "Bob",
                    "group": "Users",
                    "site": "ExampleCo"
                },
            })

        recipients = message.anymail_status.recipients
        self.assertEqual(recipients['*****@*****.**'].status, 'sent')
        self.assertEqual(recipients['*****@*****.**'].message_id,
                         'b7bc2f4a-e38e-4336-af7d-e6c392c2f817')
        self.assertEqual(recipients['*****@*****.**'].status, 'sent')
        self.assertEqual(recipients['*****@*****.**'].message_id,
                         'e2ecbbfc-fe12-463d-b933-9fe22915106d')
def email_export_xlsx(*, object_type, user, session, endpoint_path, filters,
                      export_description, attachment_name):
    if not get_language():
        language = getattr(settings, 'LANGUAGE_CODE', 'en')
        activate(language)

    if object_type == 'credits':
        export_message = gettext(
            'Attached are the credits you exported from ‘%(service_name)s’.')
    elif object_type == 'disbursements':
        export_message = (gettext(
            'Attached are the bank transfer and cheque disbursements you exported from ‘%(service_name)s’.'
        ) + ' ' + gettext('You can’t see cash or postal orders here.'))
    elif object_type == 'senders':
        export_message = gettext(
            'Attached is a list of payment sources you exported from ‘%(service_name)s’.'
        )
    elif object_type == 'prisoners':
        export_message = gettext(
            'Attached is a list of prisoners you exported from ‘%(service_name)s’.'
        )
    else:
        raise NotImplementedError(f'Cannot export {object_type}')

    api_session = get_api_session_with_session(user, session)
    generated_at = timezone.now()
    object_list = convert_date_fields(
        retrieve_all_pages_for_path(api_session, endpoint_path, **filters))

    serialiser = ObjectListSerialiser.serialiser_for(object_type)
    workbook = serialiser.make_workbook(object_list)
    output = save_virtual_workbook(workbook)

    attachment_type = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'

    template_context = prepare_context({
        'export_description': export_description,
        'generated_at': generated_at,
        'export_message': export_message % {
            'service_name': gettext('Prisoner money intelligence')
        }
    })

    subject = '%s - %s' % (gettext('Prisoner money intelligence'),
                           gettext('Exported data'))
    text_body = template_loader.get_template(
        'security/email/export.txt').render(template_context)
    html_body = template_loader.get_template(
        'security/email/export.html').render(template_context)
    email = AnymailMessage(
        subject=subject,
        body=text_body.strip('\n'),
        from_email=default_from_address(),
        to=[user.email],
        tags=['export'],
    )
    email.attach_alternative(html_body, mimetype='text/html')
    email.attach(attachment_name, output, mimetype=attachment_type)
    email.send()
Ejemplo n.º 26
0
def send_reset_password(email, token):
    message = AnymailMessage(to=[email], )
    # Anymail extra attributes:
    message.template_id = 1  # use this Sendinblue template
    message.from_email = None  # to use the template's default sender
    message.merge_global_data = {
        'token': str(token),
    }
    message.send()
Ejemplo n.º 27
0
 def test_send_anymail_message_without_template(self):
     # Make sure SendRawEmail is used for non-template_id messages
     message = AnymailMessage(from_email="*****@*****.**",
                              to=["*****@*****.**"],
                              subject="subject")
     message.send()
     self.assert_esp_not_called(operation_name="send_bulk_templated_email")
     self.get_send_params(operation_name="send_raw_email"
                          )  # fails if send_raw_email not called
    def test_all_options(self):
        send_at = datetime.now().replace(microsecond=0) + timedelta(minutes=2)
        send_at_timestamp = mktime(send_at.timetuple())  # python3: send_at.timestamp()
        message = AnymailMessage(
            subject="Anymail all-options integration test",
            body="This is the text body",
            from_email="Test From <*****@*****.**>",
            to=["*****@*****.**", "Recipient 2 <*****@*****.**>"],
            cc=["*****@*****.**", "Copy 2 <*****@*****.**>"],
            bcc=["*****@*****.**", "Blind Copy 2 <*****@*****.**>"],
            reply_to=["*****@*****.**", "Reply 2 <*****@*****.**>"],
            headers={"X-Anymail-Test": "value"},

            metadata={"meta1": "simple string", "meta2": 2},
            send_at=send_at,
            tags=["tag 1", "tag 2"],
            track_clicks=False,
            track_opens=True,
        )
        message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain")
        message.attach("attachment2.csv", "ID,Name\n1,3", "text/csv")
        cid = message.attach_inline_image_file(sample_image_path(), domain=MAILGUN_TEST_DOMAIN)
        message.attach_alternative(
            "<div>This is the <i>html</i> body <img src='cid:%s'></div>" % cid,
            "text/html")

        message.send()
        self.assertEqual(message.anymail_status.status, {'queued'})  # Mailgun always queues
        message_id = message.anymail_status.message_id

        events = self.fetch_mailgun_events(message_id, event="accepted")
        if events is None:
            self.skipTest("No Mailgun 'accepted' event after 30sec -- can't complete this test")
            return

        event = events.pop()
        self.assertCountEqual(event["tags"], ["tag 1", "tag 2"])  # don't care about order
        self.assertEqual(event["user-variables"],
                         {"meta1": "simple string", "meta2": "2"})  # all metadata values become strings

        self.assertEqual(event["message"]["scheduled-for"], send_at_timestamp)
        self.assertCountEqual(event["message"]["recipients"],
                              ['*****@*****.**', '*****@*****.**', '*****@*****.**', '*****@*****.**',
                               '*****@*****.**', '*****@*****.**'])  # don't care about order

        headers = event["message"]["headers"]
        self.assertEqual(headers["from"], "Test From <*****@*****.**>")
        self.assertEqual(headers["to"], "[email protected], Recipient 2 <*****@*****.**>")
        self.assertEqual(headers["subject"], "Anymail all-options integration test")

        attachments = event["message"]["attachments"]
        self.assertEqual(len(attachments), 2)  # because inline image shouldn't be an attachment
        self.assertEqual(attachments[0]["filename"], "attachment1.txt")
        self.assertEqual(attachments[0]["content-type"], "text/plain")
        self.assertEqual(attachments[1]["filename"], "attachment2.csv")
        self.assertEqual(attachments[1]["content-type"], "text/csv")
Ejemplo n.º 29
0
    def test_all_options(self):
        send_at = datetime.now().replace(microsecond=0) + timedelta(minutes=2)
        send_at_timestamp = mktime(send_at.timetuple())  # python3: send_at.timestamp()
        message = AnymailMessage(
            subject="Anymail all-options integration test",
            body="This is the text body",
            from_email="Test From <*****@*****.**>",
            to=["*****@*****.**", "Recipient 2 <*****@*****.**>"],
            cc=["*****@*****.**", "Copy 2 <*****@*****.**>"],
            bcc=["*****@*****.**", "Blind Copy 2 <*****@*****.**>"],
            reply_to=["*****@*****.**", "Reply 2 <*****@*****.**>"],
            headers={"X-Anymail-Test": "value"},

            metadata={"meta1": "simple string", "meta2": 2},
            send_at=send_at,
            tags=["tag 1", "tag 2"],
            track_clicks=False,
            track_opens=True,
        )
        message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain")
        message.attach("attachment2.csv", "ID,Name\n1,3", "text/csv")
        cid = message.attach_inline_image_file(sample_image_path(), domain=MAILGUN_TEST_DOMAIN)
        message.attach_alternative(
            "<div>This is the <i>html</i> body <img src='cid:%s'></div>" % cid,
            "text/html")

        message.send()
        self.assertEqual(message.anymail_status.status, {'queued'})  # Mailgun always queues
        message_id = message.anymail_status.message_id

        events = self.fetch_mailgun_events(message_id, event="accepted")
        if events is None:
            self.skipTest("No Mailgun 'accepted' event after 30sec -- can't complete this test")
            return

        event = events.pop()
        self.assertCountEqual(event["tags"], ["tag 1", "tag 2"])  # don't care about order
        self.assertEqual(event["user-variables"],
                         {"meta1": "simple string", "meta2": "2"})  # all metadata values become strings

        self.assertEqual(event["message"]["scheduled-for"], send_at_timestamp)
        self.assertCountEqual(event["message"]["recipients"],
                              ['*****@*****.**', '*****@*****.**', '*****@*****.**', '*****@*****.**',
                               '*****@*****.**', '*****@*****.**'])  # don't care about order

        headers = event["message"]["headers"]
        self.assertEqual(headers["from"], "Test From <*****@*****.**>")
        self.assertEqual(headers["to"], "[email protected], Recipient 2 <*****@*****.**>")
        self.assertEqual(headers["subject"], "Anymail all-options integration test")

        attachments = event["message"]["attachments"]
        self.assertEqual(len(attachments), 2)  # because inline image shouldn't be an attachment
        self.assertEqual(attachments[0]["filename"], "attachment1.txt")
        self.assertEqual(attachments[0]["content-type"], "text/plain")
        self.assertEqual(attachments[1]["filename"], "attachment2.csv")
        self.assertEqual(attachments[1]["content-type"], "text/csv")
Ejemplo n.º 30
0
def send_email(identifier, to, subject, template_data):
    logger.info("Sending receipt email id:%s to:%s subject:%s", identifier, to,
                subject)
    message = AnymailMessage()
    message.template_id = identifier
    message.to = [
        to,
    ]
    message.subject = subject
    message.merge_global_data = template_data
    message.send()
 def test_template_alias(self):
     # Anymail template_id can be either Postmark TemplateId or TemplateAlias
     message = AnymailMessage(
         from_email='*****@*****.**',
         to=['*****@*****.**'],
         template_id='welcome-message',
     )
     message.send()
     self.assert_esp_called('/email/withTemplate/')
     data = self.get_api_call_json()
     self.assertEqual(data['TemplateAlias'], 'welcome-message')
Ejemplo n.º 32
0
 def test_no_debug_logging(self):
     # Make sure it doesn't output anything when DEBUG_API_REQUESTS is not set
     message = AnymailMessage('Subject', 'Text Body', '*****@*****.**', ['*****@*****.**'])
     message._payload_init = dict(
         data="Request body",
         headers={
             "Content-Type": "text/plain",
             "Accept": "application/json",
         },
     )
     with self.assertPrints("", match="equal"):
         message.send()
 def test_template(self):
     message = AnymailMessage(
         from_email="*****@*****.**",
         to=["*****@*****.**", "Second Recipient <*****@*****.**>"],
         template_id=POSTMARK_TEST_TEMPLATE_ID,
         merge_data={
             "*****@*****.**": {"name": "Recipient 1", "order_no": "12345"},
             "*****@*****.**": {"order_no": "6789"},
         },
         merge_global_data={"name": "Valued Customer"},
     )
     message.send()
     self.assertEqual(message.anymail_status.status, {'sent'})
Ejemplo n.º 34
0
    def test_merge_data_no_template(self):
        # merge_data={} can be used to force batch sending without a template
        self.set_mock_response(raw=json.dumps(
            [{
                "ErrorCode": 0,
                "Message": "OK",
                "To": "*****@*****.**",
                "SubmittedAt": "2016-03-12T15:27:50.4468803-05:00",
                "MessageID": "b7bc2f4a-e38e-4336-af7d-e6c392c2f817",
            }, {
                "ErrorCode": 0,
                "Message": "OK",
                "To": "*****@*****.**",
                "SubmittedAt": "2016-03-12T15:27:50.4468803-05:00",
                "MessageID": "e2ecbbfc-fe12-463d-b933-9fe22915106d",
            }]).encode('utf-8'))

        message = AnymailMessage(
            from_email='*****@*****.**',
            to=['*****@*****.**', 'Bob <*****@*****.**>'],
            merge_data={},
            subject="Test batch send",
            body="Test body",
        )
        message.send()

        self.assert_esp_called('/email/batch')
        data = self.get_api_call_json()
        self.assertEqual(len(data), 2)
        self.assertEqual(
            data[0], {
                "From": "*****@*****.**",
                "To": "*****@*****.**",
                "Subject": "Test batch send",
                "TextBody": "Test body",
            })
        self.assertEqual(
            data[1], {
                "From": "*****@*****.**",
                "To": "Bob <*****@*****.**>",
                "Subject": "Test batch send",
                "TextBody": "Test body",
            })

        recipients = message.anymail_status.recipients
        self.assertEqual(recipients['*****@*****.**'].status, 'sent')
        self.assertEqual(recipients['*****@*****.**'].message_id,
                         'b7bc2f4a-e38e-4336-af7d-e6c392c2f817')
        self.assertEqual(recipients['*****@*****.**'].status, 'sent')
        self.assertEqual(recipients['*****@*****.**'].message_id,
                         'e2ecbbfc-fe12-463d-b933-9fe22915106d')
Ejemplo n.º 35
0
    def send_email(self, subject, body, tag='Default'):
        try:
            validate_email(self.email)
        except:
            print('Invalid email: %s' % self.email)
            return

        message = AnymailMessage(
            subject=subject,
            body=body,
            to=["%s <%s>" % (self.full_name or self.username, self.email)],
            tags=[tag],
        )
        message.send()
Ejemplo n.º 36
0
    def send_email(self, subject, body, tag='Default'):
        try:
            validate_email(self.email)
        except:
            print('Invalid email: %s' % self.email)
            return

        message = AnymailMessage(
            subject=subject,
            body=body,
            to=["%s <%s>" % (self.full_name or self.username, self.email)],
            tags=[tag],
        )
        message.send()
Ejemplo n.º 37
0
def password_reset_prelim(request):
    if request.method == 'POST':
        _password_reset_prelim_form = PasswordResetPrelimForm(request.POST)

        if _password_reset_prelim_form.is_valid():
            _email = _password_reset_prelim_form.cleaned_data.get('email')

            _user = get_user_model()

            if _user.objects.user_exists(_email):
                _timedSigner = TimestampSigner()
                _signed_email = _timedSigner.sign(_email)

                _message = AnymailMessage(to=[_email], tags=['Account'])
                _message.template_id = 'a4753e4f-f898-4a97-8ca1-a52ef8cc7aeb'
                _message.merge_global_data = {
                    'signed_email': _signed_email,
                }
                _message.metadata = {'signed-email': _signed_email}
                _message.track_clicks = True

                _message.send()

                return redirect('accounts:password-reset-prelim-success')

            else:
                _password_reset_prelim_form.add_error(
                    None,
                    mark_safe(
                        'This email is not registered with us. Do you want to <a href="'
                        + reverse('accounts:signup-prelim') +
                        '">signup</a> instead?'))
                return render(request, 'accounts/password_reset_prelim.html', {
                    'password_reset_prelim_form':
                    _password_reset_prelim_form,
                })

        else:
            return render(
                request, 'accounts/password_reset_prelim.html', {
                    'password_reset_prelim_form': _password_reset_prelim_form,
                })

    else:
        auth.logout(request)
        _password_reset_prelim_form = PasswordResetPrelimForm()
        return render(
            request, 'accounts/password_reset_prelim.html', {
                'password_reset_prelim_form': _password_reset_prelim_form,
            })
 def test_stored_template(self):
     message = AnymailMessage(
         from_email="Test From <*****@*****.**>",
         to=["*****@*****.**"],
         template_id=SENDGRID_TEST_TEMPLATE_ID,
         # The test template in the Anymail Test account has a substitution "-field-":
         merge_global_data={
             'field': 'value from merge_global_data',
         },
         esp_extra={
             'merge_field_format': '-{}-',
         },
     )
     message.send()
     self.assertEqual(message.anymail_status.status, {'queued'})
 def test_stored_template(self):
     message = AnymailMessage(
         template_id='test-template',  # a real template in our SparkPost test account
         to=["*****@*****.**"],
         merge_data={
             '*****@*****.**': {
                 'name': "Test Recipient",
             }
         },
         merge_global_data={
             'order': '12345',
         },
     )
     message.send()
     recipient_status = message.anymail_status.recipients
     self.assertEqual(recipient_status['*****@*****.**'].status, 'queued')
 def test_stored_template(self):
     message = AnymailMessage(
         template_id='176375',  # ID of the real template named 'test-template' in our Mailjet test account
         to=["*****@*****.**"],
         merge_data={
             '*****@*****.**': {
                 'name': "Test Recipient",
             }
         },
         merge_global_data={
             'order': '12345',
         },
     )
     message.from_email = None  # use the template's sender email/name
     message.send()
     recipient_status = message.anymail_status.recipients
     self.assertEqual(recipient_status['*****@*****.**'].status, 'sent')
 def test_merge_data(self):
     message = AnymailMessage(
         subject="Anymail merge_data test: %value%",
         body="This body includes merge data: %value%",
         from_email="Test From <*****@*****.**>",
         to=["*****@*****.**", "Recipient 2 <*****@*****.**>"],
         merge_data={
             '*****@*****.**': {'value': 'one'},
             '*****@*****.**': {'value': 'two'},
         },
         esp_extra={
             'merge_field_format': '%{}%',
         },
     )
     message.send()
     recipient_status = message.anymail_status.recipients
     self.assertEqual(recipient_status['*****@*****.**'].status, 'queued')
     self.assertEqual(recipient_status['*****@*****.**'].status, 'queued')
 def test_merge_data(self):
     message = AnymailMessage(
         subject="Anymail merge_data test",  # Mailjet doesn't support merge fields in the subject
         body="This body includes merge data: [[var:value]]\n"
              "And global merge data: [[var:global]]",
         from_email="Test From <*****@*****.**>",
         to=["*****@*****.**", "Recipient 2 <*****@*****.**>"],
         merge_data={
             '*****@*****.**': {'value': 'one'},
             '*****@*****.**': {'value': 'two'},
         },
         merge_global_data={
             'global': 'global_value'
         },
     )
     message.send()
     recipient_status = message.anymail_status.recipients
     self.assertEqual(recipient_status['*****@*****.**'].status, 'sent')
     self.assertEqual(recipient_status['*****@*****.**'].status, 'sent')
 def test_merge_data(self):
     message = AnymailMessage(
         subject="Anymail merge_data test: {{ value }}",
         body="This body includes merge data: {{ value }}\n"
              "And global merge data: {{ global }}",
         from_email="Test From <*****@*****.**>",
         to=["*****@*****.**", "Recipient 2 <*****@*****.**>"],
         merge_data={
             '*****@*****.**': {'value': 'one'},
             '*****@*****.**': {'value': 'two'},
         },
         merge_global_data={
             'global': 'global_value'
         },
     )
     message.send()
     recipient_status = message.anymail_status.recipients
     self.assertEqual(recipient_status['*****@*****.**'].status, 'queued')
     self.assertEqual(recipient_status['*****@*****.**'].status, 'queued')
class SendGridBackendIntegrationTests(SimpleTestCase, AnymailTestMixin):
    """SendGrid API integration tests

    These tests run against the **live** SendGrid API, using the
    environment variable `SENDGRID_TEST_API_KEY` as the API key
    If those variables are not set, these tests won't run.

    SendGrid doesn't offer a test mode -- it tries to send everything
    you ask. To avoid stacking up a pile of undeliverable @example.com
    emails, the tests use SendGrid's "sink domain" @sink.sendgrid.net.
    https://support.sendgrid.com/hc/en-us/articles/201995663-Safely-Test-Your-Sending-Speed

    """

    def setUp(self):
        super(SendGridBackendIntegrationTests, self).setUp()
        self.message = AnymailMessage('Anymail SendGrid integration test', 'Text content',
                                      '*****@*****.**', ['*****@*****.**'])
        self.message.attach_alternative('<p>HTML content</p>', "text/html")

    def test_simple_send(self):
        # Example of getting the SendGrid send status and message id from the message
        sent_count = self.message.send()
        self.assertEqual(sent_count, 1)

        anymail_status = self.message.anymail_status
        sent_status = anymail_status.recipients['*****@*****.**'].status
        message_id = anymail_status.recipients['*****@*****.**'].message_id

        self.assertEqual(sent_status, 'queued')  # SendGrid always queues
        self.assertRegex(message_id, r'\<.+@example\.com\>')  # should use from_email's domain
        self.assertEqual(anymail_status.status, {sent_status})  # set of all recipient statuses
        self.assertEqual(anymail_status.message_id, message_id)

    def test_all_options(self):
        send_at = datetime.now().replace(microsecond=0) + timedelta(minutes=2)
        message = AnymailMessage(
            subject="Anymail all-options integration test FILES",
            body="This is the text body",
            from_email="Test From <*****@*****.**>",
            to=["*****@*****.**", "Recipient 2 <*****@*****.**>"],
            cc=["*****@*****.**", "Copy 2 <*****@*****.**>"],
            bcc=["*****@*****.**", "Blind Copy 2 <*****@*****.**>"],
            reply_to=["*****@*****.**", "Reply 2 <*****@*****.**>"],
            headers={"X-Anymail-Test": "value"},

            metadata={"meta1": "simple string", "meta2": 2},
            send_at=send_at,
            tags=["tag 1", "tag 2"],
            track_clicks=True,
            track_opens=True,
        )
        message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain")
        message.attach("attachment2.csv", "ID,Name\n1,Amy Lina", "text/csv")
        cid = message.attach_inline_image_file(sample_image_path())
        message.attach_alternative(
            "<p><b>HTML:</b> with <a href='http://example.com'>link</a>"
            "and image: <img src='cid:%s'></div>" % cid,
            "text/html")

        message.send()
        self.assertEqual(message.anymail_status.status, {'queued'})  # SendGrid always queues

    def test_merge_data(self):
        message = AnymailMessage(
            subject="Anymail merge_data test: %value%",
            body="This body includes merge data: %value%",
            from_email="Test From <*****@*****.**>",
            to=["*****@*****.**", "Recipient 2 <*****@*****.**>"],
            merge_data={
                '*****@*****.**': {'value': 'one'},
                '*****@*****.**': {'value': 'two'},
            },
            esp_extra={
                'merge_field_format': '%{}%',
            },
        )
        message.send()
        recipient_status = message.anymail_status.recipients
        self.assertEqual(recipient_status['*****@*****.**'].status, 'queued')
        self.assertEqual(recipient_status['*****@*****.**'].status, 'queued')

    @override_settings(ANYMAIL_SENDGRID_API_KEY="Hey, that's not an API key!")
    def test_invalid_api_key(self):
        with self.assertRaises(AnymailAPIError) as cm:
            self.message.send()
        err = cm.exception
        self.assertEqual(err.status_code, 400)
        # Make sure the exception message includes SendGrid's response:
        self.assertIn("authorization grant is invalid", str(err))
class SparkPostBackendIntegrationTests(SimpleTestCase, AnymailTestMixin):
    """SparkPost API integration tests

    These tests run against the **live** SparkPost API, using the
    environment variable `SPARKPOST_TEST_API_KEY` as the API key
    If that variable is not set, these tests won't run.

    SparkPost doesn't offer a test mode -- it tries to send everything
    you ask. To avoid stacking up a pile of undeliverable @example.com
    emails, the tests use SparkPost's "sink domain" @*.sink.sparkpostmail.com.
    https://support.sparkpost.com/customer/en/portal/articles/2361300-how-to-test-integrations

    SparkPost also doesn't support arbitrary senders (so no [email protected]).
    We've set up @test-sp.anymail.info as a validated sending domain for these tests.

    """

    def setUp(self):
        super(SparkPostBackendIntegrationTests, self).setUp()
        self.message = AnymailMessage('Anymail SparkPost integration test', 'Text content',
                                      '*****@*****.**', ['*****@*****.**'])
        self.message.attach_alternative('<p>HTML content</p>', "text/html")

    def test_simple_send(self):
        # Example of getting the SparkPost send status and transmission id from the message
        sent_count = self.message.send()
        self.assertEqual(sent_count, 1)

        anymail_status = self.message.anymail_status
        sent_status = anymail_status.recipients['*****@*****.**'].status
        message_id = anymail_status.recipients['*****@*****.**'].message_id

        self.assertEqual(sent_status, 'queued')  # SparkPost always queues
        self.assertRegex(message_id, r'.+')  # this is actually the transmission_id; should be non-blank
        self.assertEqual(anymail_status.status, {sent_status})  # set of all recipient statuses
        self.assertEqual(anymail_status.message_id, message_id)

    def test_all_options(self):
        send_at = datetime.now() + timedelta(minutes=2)
        message = AnymailMessage(
            subject="Anymail all-options integration test",
            body="This is the text body",
            from_email="Test From <*****@*****.**>",
            to=["*****@*****.**", "Recipient 2 <*****@*****.**>"],
            cc=["*****@*****.**", "Copy 2 <*****@*****.**>"],
            bcc=["*****@*****.**", "Blind Copy 2 <*****@*****.**>"],
            reply_to=["*****@*****.**", "Reply 2 <*****@*****.**>"],
            headers={"X-Anymail-Test": "value"},

            metadata={"meta1": "simple string", "meta2": 2},
            send_at=send_at,
            tags=["tag 1"],  # SparkPost only supports single tags
            track_clicks=True,
            track_opens=True,
        )
        message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain")
        message.attach("attachment2.csv", "ID,Name\n1,Amy Lina", "text/csv")
        cid = message.attach_inline_image_file(sample_image_path())
        message.attach_alternative(
            "<p><b>HTML:</b> with <a href='http://example.com'>link</a>"
            "and image: <img src='cid:%s'></div>" % cid,
            "text/html")

        message.send()
        self.assertEqual(message.anymail_status.status, {'queued'})  # SparkPost always queues

    def test_merge_data(self):
        message = AnymailMessage(
            subject="Anymail merge_data test: {{ value }}",
            body="This body includes merge data: {{ value }}\n"
                 "And global merge data: {{ global }}",
            from_email="Test From <*****@*****.**>",
            to=["*****@*****.**", "Recipient 2 <*****@*****.**>"],
            merge_data={
                '*****@*****.**': {'value': 'one'},
                '*****@*****.**': {'value': 'two'},
            },
            merge_global_data={
                'global': 'global_value'
            },
        )
        message.send()
        recipient_status = message.anymail_status.recipients
        self.assertEqual(recipient_status['*****@*****.**'].status, 'queued')
        self.assertEqual(recipient_status['*****@*****.**'].status, 'queued')

    def test_stored_template(self):
        message = AnymailMessage(
            template_id='test-template',  # a real template in our SparkPost test account
            to=["*****@*****.**"],
            merge_data={
                '*****@*****.**': {
                    'name': "Test Recipient",
                }
            },
            merge_global_data={
                'order': '12345',
            },
        )
        message.send()
        recipient_status = message.anymail_status.recipients
        self.assertEqual(recipient_status['*****@*****.**'].status, 'queued')

    @override_settings(ANYMAIL_SPARKPOST_API_KEY="Hey, that's not an API key!")
    def test_invalid_api_key(self):
        with self.assertRaises(AnymailAPIError) as cm:
            self.message.send()
        err = cm.exception
        self.assertEqual(err.status_code, 403)
        # Make sure the exception message includes SparkPost's response:
        self.assertIn("Forbidden", str(err))
class PostmarkBackendIntegrationTests(SimpleTestCase, AnymailTestMixin):
    """Postmark API integration tests

    These tests run against the **live** Postmark API, but using a
    test key that's not capable of sending actual email.
    """

    def setUp(self):
        super(PostmarkBackendIntegrationTests, self).setUp()
        self.message = AnymailMessage('Anymail Postmark integration test', 'Text content',
                                      '*****@*****.**', ['*****@*****.**'])
        self.message.attach_alternative('<p>HTML content</p>', "text/html")

    def test_simple_send(self):
        # Example of getting the SendGrid send status and message id from the message
        sent_count = self.message.send()
        self.assertEqual(sent_count, 1)

        anymail_status = self.message.anymail_status
        sent_status = anymail_status.recipients['*****@*****.**'].status
        message_id = anymail_status.recipients['*****@*****.**'].message_id

        self.assertEqual(sent_status, 'sent')
        self.assertGreater(len(message_id), 0)  # non-empty string
        self.assertEqual(anymail_status.status, {sent_status})  # set of all recipient statuses
        self.assertEqual(anymail_status.message_id, message_id)

    def test_all_options(self):
        message = AnymailMessage(
            subject="Anymail all-options integration test",
            body="This is the text body",
            from_email="Test From <*****@*****.**>",
            to=["*****@*****.**", "Recipient 2 <*****@*****.**>"],
            cc=["*****@*****.**", "Copy 2 <*****@*****.**>"],
            bcc=["*****@*****.**", "Blind Copy 2 <*****@*****.**>"],
            reply_to=["*****@*****.**", "Reply 2 <*****@*****.**>"],
            headers={"X-Anymail-Test": "value"},

            # no metadata, send_at, track_clicks support
            tags=["tag 1"],  # max one tag
            track_opens=True,
        )
        message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain")
        message.attach("attachment2.csv", "ID,Name\n1,Amy Lina", "text/csv")
        cid = message.attach_inline_image_file(sample_image_path())
        message.attach_alternative(
            "<p><b>HTML:</b> with <a href='http://example.com'>link</a>"
            "and image: <img src='cid:%s'></div>" % cid,
            "text/html")

        message.send()
        self.assertEqual(message.anymail_status.status, {'sent'})

    def test_invalid_from(self):
        self.message.from_email = 'webmaster@localhost'  # Django's default From
        with self.assertRaises(AnymailAPIError) as cm:
            self.message.send()
        err = cm.exception
        self.assertEqual(err.status_code, 422)
        self.assertIn("Invalid 'From' address", str(err))

    @override_settings(ANYMAIL_POSTMARK_SERVER_TOKEN="Hey, that's not a server token!")
    def test_invalid_server_token(self):
        with self.assertRaises(AnymailAPIError) as cm:
            self.message.send()
        err = cm.exception
        self.assertEqual(err.status_code, 401)
        # Make sure the exception message includes Postmark's response:
        self.assertIn("Bad or missing Server API token", str(err))
class MailgunBackendIntegrationTests(SimpleTestCase, AnymailTestMixin):
    """Mailgun API integration tests

    These tests run against the **live** Mailgun API, using the
    environment variable `MAILGUN_TEST_API_KEY` as the API key
    and `MAILGUN_TEST_DOMAIN` as the sender domain.
    If those variables are not set, these tests won't run.

    """

    def setUp(self):
        super(MailgunBackendIntegrationTests, self).setUp()
        self.message = AnymailMessage('Anymail integration test', 'Text content',
                                      '*****@*****.**', ['*****@*****.**'])
        self.message.attach_alternative('<p>HTML content</p>', "text/html")

    def fetch_mailgun_events(self, message_id, event=None,
                             initial_delay=2, retry_delay=2, max_retries=5):
        """Return list of Mailgun events related to message_id"""
        url = "https://api.mailgun.net/v3/%s/events" % MAILGUN_TEST_DOMAIN
        auth = ("api", MAILGUN_TEST_API_KEY)

        # Despite the docs, Mailgun's events API actually expects the message-id
        # without the <...> brackets (so, not exactly "as returned by the messages API")
        # https://documentation.mailgun.com/api-events.html#filter-field
        params = {'message-id': message_id[1:-1]}  # strip <...>
        if event is not None:
            params['event'] = event

        # It can take a few seconds for the events to show up
        # in Mailgun's logs, so retry a few times if necessary:
        sleep(initial_delay)
        response = None
        for retry in range(max_retries):
            if retry > 0:
                sleep(retry_delay)
            response = requests.get(url, auth=auth, params=params)
            if 200 == response.status_code:
                items = response.json()["items"]
                if len(items) > 0:
                    return items
                # else no matching events found yet, so try again after delay
            elif 500 <= response.status_code < 600:
                # server error (hopefully transient); try again after delay
                pass
            elif 403 == response.status_code:
                # "forbidden": this may be related to API throttling; try again after delay
                pass
            else:
                response.raise_for_status()
        # Max retries exceeded:
        if response is not None and 200 != response.status_code:
            logging.warning("Ignoring Mailgun events API error %d:\n%s"
                            % (response.status_code, response.text))
        return None

    def test_simple_send(self):
        # Example of getting the Mailgun send status and message id from the message
        sent_count = self.message.send()
        self.assertEqual(sent_count, 1)

        anymail_status = self.message.anymail_status
        sent_status = anymail_status.recipients['*****@*****.**'].status
        message_id = anymail_status.recipients['*****@*****.**'].message_id

        self.assertEqual(sent_status, 'queued')  # Mailgun always queues
        self.assertGreater(len(message_id), 0)  # don't know what it'll be, but it should exist

        self.assertEqual(anymail_status.status, {sent_status})  # set of all recipient statuses
        self.assertEqual(anymail_status.message_id, message_id)

    def test_all_options(self):
        send_at = datetime.now().replace(microsecond=0) + timedelta(minutes=2)
        send_at_timestamp = mktime(send_at.timetuple())  # python3: send_at.timestamp()
        message = AnymailMessage(
            subject="Anymail all-options integration test",
            body="This is the text body",
            from_email="Test From <*****@*****.**>",
            to=["*****@*****.**", "Recipient 2 <*****@*****.**>"],
            cc=["*****@*****.**", "Copy 2 <*****@*****.**>"],
            bcc=["*****@*****.**", "Blind Copy 2 <*****@*****.**>"],
            reply_to=["*****@*****.**", "Reply 2 <*****@*****.**>"],
            headers={"X-Anymail-Test": "value"},

            metadata={"meta1": "simple string", "meta2": 2},
            send_at=send_at,
            tags=["tag 1", "tag 2"],
            track_clicks=False,
            track_opens=True,
        )
        message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain")
        message.attach("attachment2.csv", "ID,Name\n1,3", "text/csv")
        cid = message.attach_inline_image_file(sample_image_path(), domain=MAILGUN_TEST_DOMAIN)
        message.attach_alternative(
            "<div>This is the <i>html</i> body <img src='cid:%s'></div>" % cid,
            "text/html")

        message.send()
        self.assertEqual(message.anymail_status.status, {'queued'})  # Mailgun always queues
        message_id = message.anymail_status.message_id

        events = self.fetch_mailgun_events(message_id, event="accepted")
        if events is None:
            self.skipTest("No Mailgun 'accepted' event after 30sec -- can't complete this test")
            return

        event = events.pop()
        self.assertCountEqual(event["tags"], ["tag 1", "tag 2"])  # don't care about order
        self.assertEqual(event["user-variables"],
                         {"meta1": "simple string", "meta2": "2"})  # all metadata values become strings

        self.assertEqual(event["message"]["scheduled-for"], send_at_timestamp)
        self.assertCountEqual(event["message"]["recipients"],
                              ['*****@*****.**', '*****@*****.**', '*****@*****.**', '*****@*****.**',
                               '*****@*****.**', '*****@*****.**'])  # don't care about order

        headers = event["message"]["headers"]
        self.assertEqual(headers["from"], "Test From <*****@*****.**>")
        self.assertEqual(headers["to"], "[email protected], Recipient 2 <*****@*****.**>")
        self.assertEqual(headers["subject"], "Anymail all-options integration test")

        attachments = event["message"]["attachments"]
        self.assertEqual(len(attachments), 2)  # because inline image shouldn't be an attachment
        self.assertEqual(attachments[0]["filename"], "attachment1.txt")
        self.assertEqual(attachments[0]["content-type"], "text/plain")
        self.assertEqual(attachments[1]["filename"], "attachment2.csv")
        self.assertEqual(attachments[1]["content-type"], "text/csv")

        # No other fields are verifiable from the event data.
        # (We could try fetching the message from event["storage"]["url"]
        # to verify content and other headers.)

    def test_invalid_from(self):
        self.message.from_email = 'webmaster'
        with self.assertRaises(AnymailAPIError) as cm:
            self.message.send()
        err = cm.exception
        self.assertEqual(err.status_code, 400)
        self.assertIn("'from' parameter is not a valid address", str(err))

    @override_settings(ANYMAIL_MAILGUN_API_KEY="Hey, that's not an API key!")
    def test_invalid_api_key(self):
        with self.assertRaises(AnymailAPIError) as cm:
            self.message.send()
        err = cm.exception
        self.assertEqual(err.status_code, 401)
class MailjetBackendIntegrationTests(SimpleTestCase, AnymailTestMixin):
    """Mailjet API integration tests

    These tests run against the **live** Mailjet API, using the
    environment variables `MAILJET_TEST_API_KEY` and `MAILJET_TEST_SECRET_KEY`
    as the API key and API secret key, respectively.
    If those variables are not set, these tests won't run.

    Mailjet doesn't (in v3.0) offer a test/sandbox mode -- it tries to send everything
    you ask.

    Mailjet also doesn't support unverified senders (so no [email protected]).
    We've set up @test-mj.anymail.info as a validated sending domain for these tests.

    """

    def setUp(self):
        super(MailjetBackendIntegrationTests, self).setUp()
        self.message = AnymailMessage('Anymail Mailjet integration test', 'Text content',
                                      '*****@*****.**', ['*****@*****.**'])
        self.message.attach_alternative('<p>HTML content</p>', "text/html")

    def test_simple_send(self):
        # Example of getting the Mailjet send status and message id from the message
        sent_count = self.message.send()
        self.assertEqual(sent_count, 1)

        anymail_status = self.message.anymail_status
        sent_status = anymail_status.recipients['*****@*****.**'].status
        message_id = anymail_status.recipients['*****@*****.**'].message_id

        self.assertEqual(sent_status, 'sent')
        self.assertRegex(message_id, r'.+')
        self.assertEqual(anymail_status.status, {sent_status})  # set of all recipient statuses
        self.assertEqual(anymail_status.message_id, message_id)

    def test_all_options(self):
        message = AnymailMessage(
            subject="Anymail all-options integration test",
            body="This is the text body",
            from_email='"Test Sender, Inc." <*****@*****.**>',
            to=['*****@*****.**', '"Recipient, 2nd" <*****@*****.**>'],
            cc=['*****@*****.**', 'Copy 2 <*****@*****.**>'],
            bcc=['*****@*****.**', 'Blind Copy 2 <*****@*****.**>'],
            reply_to=['*****@*****.**', '"Reply, 2nd" <*****@*****.**>'],
            headers={"X-Anymail-Test": "value"},

            metadata={"meta1": "simple string", "meta2": 2},
            tags=["tag 1"],  # Mailjet only allows a single tag
            track_clicks=True,
            track_opens=True,
        )
        message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain")
        message.attach("attachment2.csv", "ID,Name\n1,Amy Lina", "text/csv")
        cid = message.attach_inline_image_file(sample_image_path())
        message.attach_alternative(
            "<p><b>HTML:</b> with <a href='http://example.com'>link</a>"
            "and image: <img src='cid:%s'></div>" % cid,
            "text/html")

        message.send()
        self.assertEqual(message.anymail_status.status, {'sent'})

    def test_merge_data(self):
        message = AnymailMessage(
            subject="Anymail merge_data test",  # Mailjet doesn't support merge fields in the subject
            body="This body includes merge data: [[var:value]]\n"
                 "And global merge data: [[var:global]]",
            from_email="Test From <*****@*****.**>",
            to=["*****@*****.**", "Recipient 2 <*****@*****.**>"],
            merge_data={
                '*****@*****.**': {'value': 'one'},
                '*****@*****.**': {'value': 'two'},
            },
            merge_global_data={
                'global': 'global_value'
            },
        )
        message.send()
        recipient_status = message.anymail_status.recipients
        self.assertEqual(recipient_status['*****@*****.**'].status, 'sent')
        self.assertEqual(recipient_status['*****@*****.**'].status, 'sent')

    def test_stored_template(self):
        message = AnymailMessage(
            template_id='176375',  # ID of the real template named 'test-template' in our Mailjet test account
            to=["*****@*****.**"],
            merge_data={
                '*****@*****.**': {
                    'name': "Test Recipient",
                }
            },
            merge_global_data={
                'order': '12345',
            },
        )
        message.from_email = None  # use the template's sender email/name
        message.send()
        recipient_status = message.anymail_status.recipients
        self.assertEqual(recipient_status['*****@*****.**'].status, 'sent')

    @override_settings(ANYMAIL_MAILJET_API_KEY="Hey, that's not an API key!")
    def test_invalid_api_key(self):
        with self.assertRaises(AnymailAPIError) as cm:
            self.message.send()
        err = cm.exception
        self.assertEqual(err.status_code, 401)
        self.assertIn("Invalid Mailjet API key or secret", str(err))
class SendGridBackendIntegrationTests(SimpleTestCase, AnymailTestMixin):
    """SendGrid v3 API integration tests

    These tests run against the **live** SendGrid API, using the
    environment variable `SENDGRID_TEST_API_KEY` as the API key
    If those variables are not set, these tests won't run.

    The SEND_DEFAULTS above force SendGrid's v3 sandbox mode, which avoids sending mail.
    (Sandbox sends also don't show in the activity feed, so disable that for live debugging.)

    The tests also use SendGrid's "sink domain" @sink.sendgrid.net for recipient addresses.
    https://support.sendgrid.com/hc/en-us/articles/201995663-Safely-Test-Your-Sending-Speed

    """

    def setUp(self):
        super(SendGridBackendIntegrationTests, self).setUp()
        self.message = AnymailMessage('Anymail SendGrid integration test', 'Text content',
                                      '*****@*****.**', ['*****@*****.**'])
        self.message.attach_alternative('<p>HTML content</p>', "text/html")

    def test_simple_send(self):
        # Example of getting the SendGrid send status and message id from the message
        sent_count = self.message.send()
        self.assertEqual(sent_count, 1)

        anymail_status = self.message.anymail_status
        sent_status = anymail_status.recipients['*****@*****.**'].status
        message_id = anymail_status.recipients['*****@*****.**'].message_id

        self.assertEqual(sent_status, 'queued')  # SendGrid always queues
        self.assertRegex(message_id, r'\<.+@example\.com\>')  # should use from_email's domain
        self.assertEqual(anymail_status.status, {sent_status})  # set of all recipient statuses
        self.assertEqual(anymail_status.message_id, message_id)

    def test_all_options(self):
        send_at = datetime.now().replace(microsecond=0) + timedelta(minutes=2)
        message = AnymailMessage(
            subject="Anymail all-options integration test",
            body="This is the text body",
            from_email='"Test From, with comma" <*****@*****.**>',
            to=["*****@*****.**", '"Recipient 2, OK?" <*****@*****.**>'],
            cc=["*****@*****.**", "Copy 2 <*****@*****.**>"],
            bcc=["*****@*****.**", "Blind Copy 2 <*****@*****.**>"],
            reply_to=['"Reply, with comma" <*****@*****.**>'],  # v3 only supports single reply-to
            headers={"X-Anymail-Test": "value", "X-Anymail-Count": 3},

            metadata={"meta1": "simple string", "meta2": 2},
            send_at=send_at,
            tags=["tag 1", "tag 2"],
            track_clicks=True,
            track_opens=True,
            # esp_extra={'asm': {'group_id': 1}},  # this breaks activity feed if you don't have an asm group
        )
        message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain")
        message.attach("attachment2.csv", "ID,Name\n1,Amy Lina", "text/csv")
        cid = message.attach_inline_image_file(sample_image_path())
        message.attach_alternative(
            "<p><b>HTML:</b> with <a href='http://example.com'>link</a>"
            "and image: <img src='cid:%s'></div>" % cid,
            "text/html")

        message.send()
        self.assertEqual(message.anymail_status.status, {'queued'})  # SendGrid always queues

    def test_merge_data(self):
        message = AnymailMessage(
            subject="Anymail merge_data test: %field%",
            body="This body includes merge data: %field%",
            from_email="Test From <*****@*****.**>",
            to=["*****@*****.**", "Recipient 2 <*****@*****.**>"],
            reply_to=['"Merge data in reply name: %field%" <*****@*****.**>'],
            merge_data={
                '*****@*****.**': {'field': 'one'},
                '*****@*****.**': {'field': 'two'},
            },
            esp_extra={
                'merge_field_format': '%{}%',
            },
        )
        message.send()
        recipient_status = message.anymail_status.recipients
        self.assertEqual(recipient_status['*****@*****.**'].status, 'queued')
        self.assertEqual(recipient_status['*****@*****.**'].status, 'queued')

    @unittest.skipUnless(SENDGRID_TEST_TEMPLATE_ID,
                         "Set the SENDGRID_TEST_TEMPLATE_ID environment variable "
                         "to a template in your SendGrid account to test stored templates")
    def test_stored_template(self):
        message = AnymailMessage(
            from_email="Test From <*****@*****.**>",
            to=["*****@*****.**"],
            template_id=SENDGRID_TEST_TEMPLATE_ID,
            # The test template in the Anymail Test account has a substitution "-field-":
            merge_global_data={
                'field': 'value from merge_global_data',
            },
            esp_extra={
                'merge_field_format': '-{}-',
            },
        )
        message.send()
        self.assertEqual(message.anymail_status.status, {'queued'})

    @override_settings(ANYMAIL_SENDGRID_API_KEY="Hey, that's not an API key!")
    def test_invalid_api_key(self):
        with self.assertRaises(AnymailAPIError) as cm:
            self.message.send()
        err = cm.exception
        self.assertEqual(err.status_code, 401)
        # Make sure the exception message includes SendGrid's response:
        self.assertIn("authorization grant is invalid", str(err))