def test_invalid_signature(self):
        """Invalid signature should not be handled as an OOPs.

        It should produce a message explaining to the user what went wrong.
        """
        person = self.factory.makePerson()
        transaction.commit()
        email_address = person.preferredemail.email
        invalid_body = ('-----BEGIN PGP SIGNED MESSAGE-----\n'
                        'Hash: SHA1\n\n'
                        'Body\n'
                        '-----BEGIN PGP SIGNATURE-----\n'
                        'Not a signature.\n'
                        '-----END PGP SIGNATURE-----\n')
        ctrl = MailController(email_address,
                              '*****@*****.**',
                              'subject',
                              invalid_body,
                              bulk=False)
        ctrl.send()
        handleMail()
        self.assertEqual([], self.oopses)
        [notification] = pop_notifications()
        body = notification.get_payload()[0].get_payload(decode=True)
        self.assertIn(
            "An error occurred while processing a mail you sent to "
            "Launchpad's email\ninterface.\n\n\n"
            "Error message:\n\nSignature couldn't be verified: "
            "(7, 58, u'No data')", body)
示例#2
0
    def test_invalid_signature(self):
        """Invalid signature should not be handled as an OOPs.

        It should produce a message explaining to the user what went wrong.
        """
        person = self.factory.makePerson()
        transaction.commit()
        email_address = person.preferredemail.email
        invalid_body = (
            "-----BEGIN PGP SIGNED MESSAGE-----\n"
            "Hash: SHA1\n\n"
            "Body\n"
            "-----BEGIN PGP SIGNATURE-----\n"
            "Not a signature.\n"
            "-----END PGP SIGNATURE-----\n"
        )
        ctrl = MailController(email_address, "*****@*****.**", "subject", invalid_body, bulk=False)
        ctrl.send()
        handleMail()
        self.assertEqual([], self.oopses)
        [notification] = pop_notifications()
        body = notification.get_payload()[0].get_payload(decode=True)
        self.assertIn(
            "An error occurred while processing a mail you sent to "
            "Launchpad's email\ninterface.\n\n\n"
            "Error message:\n\nSignature couldn't be verified: "
            "(7, 58, u'No data')",
            body,
        )
示例#3
0
 def test_encodeOptimally_with_text(self):
     """Mostly-ascii attachments should be encoded as quoted-printable."""
     text = u'I went to the caf\u00e9 today.'.encode('utf-8')
     part = Message()
     part.set_payload(text)
     MailController.encodeOptimally(part)
     self.assertEqual(text, part.get_payload(decode=True))
     self.assertEqual('quoted-printable', part['Content-Transfer-Encoding'])
示例#4
0
 def test_encodeOptimally_with_binary(self):
     """Significantly non-ascii attachments should be base64-encoded."""
     bytes = '\x00\xff\x44\x55\xaa\x99'
     part = Message()
     part.set_payload(bytes)
     MailController.encodeOptimally(part)
     self.assertEqual(bytes, part.get_payload(decode=True))
     self.assertEqual('base64', part['Content-Transfer-Encoding'])
 def test_encodeOptimally_with_binary(self):
     """Significantly non-ascii attachments should be base64-encoded."""
     bytes = '\x00\xff\x44\x55\xaa\x99'
     part = Message()
     part.set_payload(bytes)
     MailController.encodeOptimally(part)
     self.assertEqual(bytes, part.get_payload(decode=True))
     self.assertEqual('base64', part['Content-Transfer-Encoding'])
 def test_MakeMessage_with_binary_attachment(self):
     """Message should still encode as ascii with non-ascii attachments."""
     ctrl = MailController(
         '*****@*****.**', '*****@*****.**', 'subject', u'Body')
     ctrl.addAttachment('\x00\xffattach')
     message = ctrl.makeMessage()
     self.assertTrue(
         is_ascii_only(message.as_string()), "Non-ascii message string.")
示例#7
0
 def test_MakeMessage_with_binary_attachment(self):
     """Message should still encode as ascii with non-ascii attachments."""
     ctrl = MailController('*****@*****.**', '*****@*****.**', 'subject',
                           u'Body')
     ctrl.addAttachment('\x00\xffattach')
     message = ctrl.makeMessage()
     self.assertTrue(is_ascii_only(message.as_string()),
                     "Non-ascii message string.")
示例#8
0
 def test_encodeOptimally_with_ascii_text(self):
     """Mostly-ascii attachments should be encoded as quoted-printable."""
     text = 'I went to the cafe today.\n\r'
     part = Message()
     part.set_payload(text)
     MailController.encodeOptimally(part, exact=False)
     self.assertEqual(part.get_payload(), part.get_payload(decode=True))
     self.assertIs(None, part['Content-Transfer-Encoding'])
 def test_encodeOptimally_with_ascii_text(self):
     """Mostly-ascii attachments should be encoded as quoted-printable."""
     text = 'I went to the cafe today.\n\r'
     part = Message()
     part.set_payload(text)
     MailController.encodeOptimally(part, exact=False)
     self.assertEqual(part.get_payload(), part.get_payload(decode=True))
     self.assertIs(None, part['Content-Transfer-Encoding'])
示例#10
0
 def test_MakeMessage_with_non_binary_attachment(self):
     """Simple ascii attachments should not be encoded."""
     ctrl = MailController('*****@*****.**', '*****@*****.**', 'subject',
                           u'Body')
     ctrl.addAttachment('Hello, I am ascii')
     message = ctrl.makeMessage()
     body, attachment = message.get_payload()
     self.assertEqual(attachment.get_payload(),
                      attachment.get_payload(decode=True))
示例#11
0
 def test_MakeMessage_with_non_binary_attachment(self):
     """Simple ascii attachments should not be encoded."""
     ctrl = MailController(
         '*****@*****.**', '*****@*****.**', 'subject', u'Body')
     ctrl.addAttachment('Hello, I am ascii')
     message = ctrl.makeMessage()
     body, attachment = message.get_payload()
     self.assertEqual(
         attachment.get_payload(), attachment.get_payload(decode=True))
示例#12
0
 def test_encodeOptimally_with_text(self):
     """Mostly-ascii attachments should be encoded as quoted-printable."""
     text = u'I went to the caf\u00e9 today.'.encode('utf-8')
     part = Message()
     part.set_payload(text)
     MailController.encodeOptimally(part)
     self.assertEqual(text, part.get_payload(decode=True))
     self.assertEqual('quoted-printable',
                      part['Content-Transfer-Encoding'])
示例#13
0
 def test_encodeOptimally_with_7_bit_binary(self):
     """Mostly-ascii attachments should be encoded as quoted-printable."""
     text = 'I went to the cafe today.\n\r'
     part = Message()
     part.set_payload(text)
     MailController.encodeOptimally(part)
     self.assertEqual(text, part.get_payload(decode=True))
     self.assertEqual('I went to the cafe today.=0A=0D', part.get_payload())
     self.assertEqual('quoted-printable', part['Content-Transfer-Encoding'])
示例#14
0
 def test_MakeMessage_no_attachment(self):
     """A message without an attachment should have a single body."""
     ctrl = MailController('*****@*****.**', '*****@*****.**', 'subject',
                           'body')
     message = ctrl.makeMessage()
     self.assertEqual('*****@*****.**', message['From'])
     self.assertEqual('*****@*****.**', message['To'])
     self.assertEqual('subject', message['Subject'])
     self.assertEqual('body', message.get_payload(decode=True))
示例#15
0
 def test_MakeMessage_no_attachment(self):
     """A message without an attachment should have a single body."""
     ctrl = MailController(
         '*****@*****.**', '*****@*****.**', 'subject', 'body')
     message = ctrl.makeMessage()
     self.assertEqual('*****@*****.**', message['From'])
     self.assertEqual('*****@*****.**', message['To'])
     self.assertEqual('subject', message['Subject'])
     self.assertEqual('body', message.get_payload(decode=True))
示例#16
0
 def test_MakeMessage_unicode_body(self):
     # A message without an attachment with a unicode body gets sent as
     # UTF-8 encoded MIME text, and the message as a whole can be flattened
     # to a string with Unicode errors.
     ctrl = MailController('*****@*****.**', '*****@*****.**', 'subject',
                           u'Bj\xf6rn')
     message = ctrl.makeMessage()
     # Make sure that the message can be flattened to a string as sendmail
     # does without raising a UnicodeEncodeError.
     message.as_string()
     self.assertEqual('Bj\xc3\xb6rn', message.get_payload(decode=True))
示例#17
0
 def test_MakeMessage_unicode_body(self):
     # A message without an attachment with a unicode body gets sent as
     # UTF-8 encoded MIME text, and the message as a whole can be flattened
     # to a string with Unicode errors.
     ctrl = MailController(
         '*****@*****.**', '*****@*****.**', 'subject', u'Bj\xf6rn')
     message = ctrl.makeMessage()
     # Make sure that the message can be flattened to a string as sendmail
     # does without raising a UnicodeEncodeError.
     message.as_string()
     self.assertEqual('Bj\xc3\xb6rn', message.get_payload(decode=True))
示例#18
0
 def test_MakeMessageSpecialChars(self):
     """A message should have its to and from addrs converted to ascii."""
     to_addr = u'\[email protected]'
     from_addr = u'\[email protected]'
     ctrl = MailController(from_addr, to_addr, 'subject', 'body')
     message = ctrl.makeMessage()
     self.assertEqual('=?utf-8?b?4YSAZnJvbUBleGFtcGxlLmNvbQ==?=',
                      message['From'])
     self.assertEqual('=?utf-8?b?4YSAdG9AZXhhbXBsZS5jb20=?=', message['To'])
     self.assertEqual('subject', message['Subject'])
     self.assertEqual('body', message.get_payload(decode=True))
示例#19
0
 def test_encodeOptimally_with_7_bit_binary(self):
     """Mostly-ascii attachments should be encoded as quoted-printable."""
     text = 'I went to the cafe today.\n\r'
     part = Message()
     part.set_payload(text)
     MailController.encodeOptimally(part)
     self.assertEqual(text, part.get_payload(decode=True))
     self.assertEqual('I went to the cafe today.=0A=0D',
                      part.get_payload())
     self.assertEqual('quoted-printable',
                      part['Content-Transfer-Encoding'])
示例#20
0
 def test_MakeMessageSpecialChars(self):
     """A message should have its to and from addrs converted to ascii."""
     to_addr = u'\[email protected]'
     from_addr = u'\[email protected]'
     ctrl = MailController(from_addr, to_addr, 'subject', 'body')
     message = ctrl.makeMessage()
     self.assertEqual('=?utf-8?b?4YSAZnJvbUBleGFtcGxlLmNvbQ==?=',
         message['From'])
     self.assertEqual('=?utf-8?b?4YSAdG9AZXhhbXBsZS5jb20=?=',
         message['To'])
     self.assertEqual('subject', message['Subject'])
     self.assertEqual('body', message.get_payload(decode=True))
示例#21
0
 def test_MakeMessage_long_address(self):
     # Long email addresses are not wrapped if very long.  These are due to
     # the paranoid checks that are in place to make sure that there are no
     # carriage returns in the to or from email addresses.
     to_addr = ('Launchpad Community Help Rotation team '
                '<*****@*****.**>')
     from_addr = ('Some Random User With Many Public Names '
                  '<*****@*****.**')
     ctrl = MailController(from_addr, to_addr, 'subject', 'body')
     message = ctrl.makeMessage()
     self.assertEqual(from_addr, message['From'])
     self.assertEqual(to_addr, message['To'])
示例#22
0
 def test_MailController_into_timeline(self):
     """sendmail records stuff in the timeline."""
     fake_mailer = RecordingMailer()
     self.useFixture(ZopeUtilityFixture(fake_mailer, IMailDelivery, 'Mail'))
     to_addresses = ['*****@*****.**', '*****@*****.**']
     subject = self.getUniqueString('subject')
     with CaptureTimeline() as ctl:
         ctrl = MailController('*****@*****.**', to_addresses, subject,
                               'body', {'key': 'value'})
         ctrl.send()
     self.assertEqual(fake_mailer.from_addr, '*****@*****.**')
     self.assertEqual(fake_mailer.to_addr, to_addresses)
     self.checkTimelineHasOneMailAction(ctl.timeline, subject=subject)
示例#23
0
 def test_MakeMessage_with_specific_attachment(self):
     """Explicit attachment params should be obeyed."""
     ctrl = MailController(
         '*****@*****.**', '*****@*****.**', 'subject', 'body')
     ctrl.addAttachment(
         'attach', 'text/plain', inline=True, filename='README')
     message = ctrl.makeMessage()
     attachment = message.get_payload()[1]
     self.assertEqual('attach', attachment.get_payload(decode=True))
     self.assertEqual(
         'text/plain', attachment['Content-Type'])
     self.assertEqual(
         'inline; filename="README"', attachment['Content-Disposition'])
示例#24
0
 def test_MakeMessage_with_specific_attachment(self):
     """Explicit attachment params should be obeyed."""
     ctrl = MailController('*****@*****.**', '*****@*****.**', 'subject',
                           'body')
     ctrl.addAttachment('attach',
                        'text/plain',
                        inline=True,
                        filename='README')
     message = ctrl.makeMessage()
     attachment = message.get_payload()[1]
     self.assertEqual('attach', attachment.get_payload(decode=True))
     self.assertEqual('text/plain', attachment['Content-Type'])
     self.assertEqual('inline; filename="README"',
                      attachment['Content-Disposition'])
示例#25
0
 def test_MakeMessage_long_address(self):
     # Long email addresses are not wrapped if very long.  These are due to
     # the paranoid checks that are in place to make sure that there are no
     # carriage returns in the to or from email addresses.
     to_addr = (
         'Launchpad Community Help Rotation team '
         '<*****@*****.**>')
     from_addr = (
         'Some Random User With Many Public Names '
         '<*****@*****.**')
     ctrl = MailController(from_addr, to_addr, 'subject', 'body')
     message = ctrl.makeMessage()
     self.assertEqual(from_addr, message['From'])
     self.assertEqual(to_addr, message['To'])
示例#26
0
 def test_MakeMessage_with_attachment(self):
     """A message with an attachment should be multipart."""
     ctrl = MailController('*****@*****.**', '*****@*****.**', 'subject',
                           'body')
     ctrl.addAttachment('attach')
     message = ctrl.makeMessage()
     self.assertEqual('*****@*****.**', message['From'])
     self.assertEqual('*****@*****.**', message['To'])
     self.assertEqual('subject', message['Subject'])
     body, attachment = message.get_payload()
     self.assertEqual('body', body.get_payload(decode=True))
     self.assertEqual('attach', attachment.get_payload(decode=True))
     self.assertEqual('application/octet-stream',
                      attachment['Content-Type'])
     self.assertEqual('attachment', attachment['Content-Disposition'])
示例#27
0
 def test_MakeMessage_with_attachment(self):
     """A message with an attachment should be multipart."""
     ctrl = MailController(
         '*****@*****.**', '*****@*****.**', 'subject', 'body')
     ctrl.addAttachment('attach')
     message = ctrl.makeMessage()
     self.assertEqual('*****@*****.**', message['From'])
     self.assertEqual('*****@*****.**', message['To'])
     self.assertEqual('subject', message['Subject'])
     body, attachment = message.get_payload()
     self.assertEqual('body', body.get_payload(decode=True))
     self.assertEqual('attach', attachment.get_payload(decode=True))
     self.assertEqual(
         'application/octet-stream', attachment['Content-Type'])
     self.assertEqual('attachment', attachment['Content-Disposition'])
示例#28
0
 def test_MailController_into_timeline(self):
     """sendmail records stuff in the timeline."""
     fake_mailer = RecordingMailer()
     self.useFixture(ZopeUtilityFixture(
         fake_mailer, IMailDelivery, 'Mail'))
     to_addresses = ['*****@*****.**', '*****@*****.**']
     subject = self.getUniqueString('subject')
     with CaptureTimeline() as ctl:
         ctrl = MailController(
             '*****@*****.**', to_addresses,
             subject, 'body', {'key': 'value'})
         ctrl.send()
     self.assertEquals(fake_mailer.from_addr, '*****@*****.**')
     self.assertEquals(fake_mailer.to_addr, to_addresses)
     self.checkTimelineHasOneMailAction(ctl.timeline, subject=subject)
示例#29
0
    def test_sendUsesRealTo(self):
        """MailController.envelope_to is provided as to_addrs."""
        ctrl = MailController('*****@*****.**', '*****@*****.**', 'subject',
                              'body', envelope_to=['*****@*****.**'])
        sendmail_kwargs = {}

        def fake_sendmail(message, to_addrs=None, bulk=True):
            sendmail_kwargs.update(locals())
        real_sendmail = sendmail.sendmail
        sendmail.sendmail = fake_sendmail
        try:
            ctrl.send()
        finally:
            sendmail.sendmail = real_sendmail
        self.assertEqual('*****@*****.**', sendmail_kwargs['message']['To'])
        self.assertEqual(['*****@*****.**'], sendmail_kwargs['to_addrs'])
示例#30
0
def create_mail_for_directoryMailBox(from_addr, to_addrs, subject, body,
                                     headers=None):
    """Create a email in the DirectoryMailBox."""
    mc = MailController(from_addr, to_addrs, subject, body, headers)
    message = mc.makeMessage()
    if 'message-id' not in message:
        message['Message-Id'] = get_msgid()
    if 'date' not in message:
        message['Date'] = formatdate()
    # Since this is faking incoming email, set the X-Original-To.
    message['X-Original-To'] = to_addrs
    mailbox = getUtility(IMailBox)
    msg_file = open(
        os.path.join(mailbox.mail_dir, message['Message-Id']), 'w')
    msg_file.write(message.as_string())
    msg_file.close()
示例#31
0
    def test_mail_too_big(self):
        """Much-too-big mail should generate a bounce, not an OOPS.

        See <https://bugs.launchpad.net/launchpad/+bug/893612>.
        """
        person = self.factory.makePerson()
        transaction.commit()
        email_address = person.preferredemail.email
        fat_body = "\n".join(["some big mail with this line repeated many many times\n"] * 1000000)
        ctrl = MailController(email_address, "*****@*****.**", "subject", fat_body, bulk=False)
        ctrl.send()
        handleMail()
        self.assertEqual([], self.oopses)
        [notification] = pop_notifications()
        body = notification.get_payload()[0].get_payload(decode=True)
        self.assertIn("The mail you sent to Launchpad is too long.", body)
        self.assertIn("was 55 MB and the limit is 10 MB.", body)
示例#32
0
def create_mail_for_directoryMailBox(from_addr,
                                     to_addrs,
                                     subject,
                                     body,
                                     headers=None):
    """Create a email in the DirectoryMailBox."""
    mc = MailController(from_addr, to_addrs, subject, body, headers)
    message = mc.makeMessage()
    if 'message-id' not in message:
        message['Message-Id'] = get_msgid()
    if 'date' not in message:
        message['Date'] = formatdate()
    # Since this is faking incoming email, set the X-Original-To.
    message['X-Original-To'] = to_addrs
    mailbox = getUtility(IMailBox)
    msg_file = open(os.path.join(mailbox.mail_dir, message['Message-Id']), 'w')
    msg_file.write(message.as_string())
    msg_file.close()
示例#33
0
    def test_sendUsesRealTo(self):
        """MailController.envelope_to is provided as to_addrs."""
        ctrl = MailController('*****@*****.**',
                              '*****@*****.**',
                              'subject',
                              'body',
                              envelope_to=['*****@*****.**'])
        sendmail_kwargs = {}

        def fake_sendmail(message, to_addrs=None, bulk=True):
            sendmail_kwargs.update(locals())

        real_sendmail = sendmail.sendmail
        sendmail.sendmail = fake_sendmail
        try:
            ctrl.send()
        finally:
            sendmail.sendmail = real_sendmail
        self.assertEqual('*****@*****.**', sendmail_kwargs['message']['To'])
        self.assertEqual(['*****@*****.**'], sendmail_kwargs['to_addrs'])
示例#34
0
    def test_mail_too_big(self):
        """Much-too-big mail should generate a bounce, not an OOPS.

        See <https://bugs.launchpad.net/launchpad/+bug/893612>.
        """
        person = self.factory.makePerson()
        transaction.commit()
        email_address = person.preferredemail.email
        fat_body = '\n'.join(
            ['some big mail with this line repeated many many times\n']
            * 1000000)
        ctrl = MailController(
            email_address, '*****@*****.**', 'subject', fat_body,
            bulk=False)
        ctrl.send()
        handleMail()
        self.assertEqual([], self.oopses)
        [notification] = pop_notifications()
        body = notification.get_payload()[0].get_payload(decode=True)
        self.assertIn("The mail you sent to Launchpad is too long.", body)
        self.assertIn("was 55 MB and the limit is 10 MB.", body)
示例#35
0
    def test_constructor2(self):
        """Test the explicit construction behaviour.

        Since to is a list, it is not converted into a list.
        """
        ctrl = MailController('*****@*****.**',
                              ['*****@*****.**', '*****@*****.**'],
                              'subject', 'body', {'key': 'value'})
        self.assertEqual(['*****@*****.**', '*****@*****.**'], ctrl.to_addrs)
        self.assertEqual({'key': 'value'}, ctrl.headers)
        self.assertEqual('body', ctrl.body)
        self.assertEqual([], ctrl.attachments)
示例#36
0
    def test_constructor(self):
        """Test the default construction behaviour.

        Defaults should be empty.  The 'to' should be converted to a list.
        """
        ctrl = MailController('*****@*****.**', '*****@*****.**', 'subject',
                              'body')
        self.assertEqual('*****@*****.**', ctrl.from_addr)
        self.assertEqual(['*****@*****.**'], ctrl.to_addrs)
        self.assertEqual('subject', ctrl.subject)
        self.assertEqual({}, ctrl.headers)
        self.assertEqual('body', ctrl.body)
        self.assertEqual([], ctrl.attachments)
示例#37
0
    def getOopsMailController(self, oops_id):
        """Return a MailController for notifying people about oopses.

        Return None if there is no-one to notify.
        """
        recipients = self.getOopsRecipients()
        if len(recipients) == 0:
            return None
        subject = 'Launchpad internal error'
        body = ('Launchpad encountered an internal error during the following'
                ' operation: %s.  It was logged with id %s.  Sorry for the'
                ' inconvenience.' % (self.getOperationDescription(), oops_id))
        from_addr = config.canonical.noreply_from_address
        return MailController(from_addr, recipients, subject, body)
示例#38
0
    def getUserErrorMailController(self, e):
        """Return a MailController for notifying about user errors.

        Return None if there is no-one to notify.
        """
        recipients = self.getErrorRecipients()
        if len(recipients) == 0:
            return None
        subject = 'Launchpad error while %s' % self.getOperationDescription()
        body = ('Launchpad encountered an error during the following'
                ' operation: %s.  %s' %
                (self.getOperationDescription(), str(e)))
        from_addr = config.canonical.noreply_from_address
        return MailController(from_addr, recipients, subject, body)
示例#39
0
 def test_addAttachment(self):
     """addAttachment should add a part to the list of attachments."""
     ctrl = MailController('*****@*****.**', '*****@*****.**', 'subject',
                           'body')
     ctrl.addAttachment('content1')
     attachment = ctrl.attachments[0]
     self.assertEqual('application/octet-stream',
                      attachment['Content-Type'])
     self.assertEqual('attachment', attachment['Content-Disposition'])
     self.assertEqual('content1', attachment.get_payload(decode=True))
     ctrl.addAttachment('content2',
                        'text/plain',
                        inline=True,
                        filename='name1')
     attachment = ctrl.attachments[1]
     self.assertEqual('text/plain', attachment['Content-Type'])
     self.assertEqual('inline; filename="name1"',
                      attachment['Content-Disposition'])
     self.assertEqual('content2', attachment.get_payload(decode=True))
     ctrl.addAttachment('content2',
                        'text/plain',
                        inline=True,
                        filename='name1')
示例#40
0
 def test_addAttachment(self):
     """addAttachment should add a part to the list of attachments."""
     ctrl = MailController(
         '*****@*****.**', '*****@*****.**', 'subject', 'body')
     ctrl.addAttachment('content1')
     attachment = ctrl.attachments[0]
     self.assertEqual(
         'application/octet-stream', attachment['Content-Type'])
     self.assertEqual(
         'attachment', attachment['Content-Disposition'])
     self.assertEqual(
         'content1', attachment.get_payload(decode=True))
     ctrl.addAttachment(
         'content2', 'text/plain', inline=True, filename='name1')
     attachment = ctrl.attachments[1]
     self.assertEqual(
         'text/plain', attachment['Content-Type'])
     self.assertEqual(
         'inline; filename="name1"', attachment['Content-Disposition'])
     self.assertEqual(
         'content2', attachment.get_payload(decode=True))
     ctrl.addAttachment(
         'content2', 'text/plain', inline=True, filename='name1')