Beispiel #1
0
    def encodeOptimally(part, exact=True):
        """Encode a message part as needed.

        If the part is more than 10% high-bit characters, it will be encoded
        using base64 encoding.  If the contents are 7-bit and exact is False,
        the part will not be encoded.  Otherwise, the message will be encoded
        as quoted-printable.

        If quoted-printable encoding is used, exact will cause all line-ending
        characters to be quoted.

        :param part: The message part to encode.
        :param exact: If True, the encoding will ensure newlines are not
            mangled.  If False, 7-bit attachments will not be encoded.
        """
        # If encoding has already been done by virtue of a charset being
        # previously specified, then do nothing.
        if 'Content-Transfer-Encoding' in part:
            return
        orig_payload = part.get_payload()
        if not exact and is_ascii_only(orig_payload):
            return
        # Payloads which are completely ascii need no encoding.
        quopri_bytes = b2a_qp(orig_payload, istext=not exact)
        # If 10% of characters need to be encoded, len is 1.2 times
        # the original len.  If more than 10% need encoding, the result
        # is unlikely to be readable.
        if len(quopri_bytes) < len(orig_payload) * 1.2:
            part.set_payload(quopri_bytes)
            part['Content-Transfer-Encoding'] = 'quoted-printable'
        else:
            encode_base64(part)
Beispiel #2
0
    def encodeOptimally(part, exact=True):
        """Encode a message part as needed.

        If the part is more than 10% high-bit characters, it will be encoded
        using base64 encoding.  If the contents are 7-bit and exact is False,
        the part will not be encoded.  Otherwise, the message will be encoded
        as quoted-printable.

        If quoted-printable encoding is used, exact will cause all line-ending
        characters to be quoted.

        :param part: The message part to encode.
        :param exact: If True, the encoding will ensure newlines are not
            mangled.  If False, 7-bit attachments will not be encoded.
        """
        # If encoding has already been done by virtue of a charset being
        # previously specified, then do nothing.
        if 'Content-Transfer-Encoding' in part:
            return
        orig_payload = part.get_payload()
        if not exact and is_ascii_only(orig_payload):
            return
        # Payloads which are completely ascii need no encoding.
        quopri_bytes = b2a_qp(orig_payload, istext=not exact)
        # If 10% of characters need to be encoded, len is 1.2 times
        # the original len.  If more than 10% need encoding, the result
        # is unlikely to be readable.
        if len(quopri_bytes) < len(orig_payload) * 1.2:
            part.set_payload(quopri_bytes)
            part['Content-Transfer-Encoding'] = 'quoted-printable'
        else:
            encode_base64(part)
Beispiel #3
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.")
 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.")
    def publishTraverse(self, request, name):
        """Shim, to set objects in the launchbag when traversing them.

        This needs moving into the publication component, once it has been
        refactored.
        """
        # Launchpad only produces ascii URLs.  If the name is not ascii, we
        # can say nothing is found here.
        if not is_ascii_only(name):
            raise NotFound(self.context, name)
        nextobj = self._publishTraverse(request, name)
        getUtility(IOpenLaunchBag).add(nextobj)
        return nextobj
Beispiel #6
0
 def test_MakeMessage_unicode_body_with_attachment(self):
     # A message with 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')
     ctrl.addAttachment('attach')
     message = ctrl.makeMessage()
     # Make sure that the message can be flattened to a string as sendmail
     # does without raising a UnicodeEncodeError.
     message.as_string()
     body, attachment = message.get_payload()
     self.assertEqual('Bj\xc3\xb6rn', body.get_payload(decode=True))
     self.assertTrue(is_ascii_only(message.as_string()))
 def test_MakeMessage_unicode_body_with_attachment(self):
     # A message with 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')
     ctrl.addAttachment('attach')
     message = ctrl.makeMessage()
     # Make sure that the message can be flattened to a string as sendmail
     # does without raising a UnicodeEncodeError.
     message.as_string()
     body, attachment = message.get_payload()
     self.assertEqual('Bj\xc3\xb6rn', body.get_payload(decode=True))
     self.assertTrue(is_ascii_only(message.as_string()))
Beispiel #8
0
    def makeMessage(self):
        # It's the caller's responsibility to either encode the address fields
        # to ASCII strings or pass in Unicode strings.

        # Using the maxlinelen for the Headers as we have paranoid checks to
        # make sure that we have no carriage returns in the to or from email
        # addresses.  We use nice email addresses like 'Launchpad Community
        # Help Rotation team <*****@*****.**>' that
        # get broken over two lines in the header.  RFC 5322 specified that
        # the lines MUST be no more than 998, so we use that as our maximum.
        from_addr = Header(self.from_addr, maxlinelen=998).encode()
        to_addrs = [
            Header(address, maxlinelen=998).encode()
            for address in list(self.to_addrs)
        ]

        for address in [from_addr] + to_addrs:
            if not isinstance(address, str) or not is_ascii_only(address):
                raise AssertionError('Expected an ASCII str object, got: %r' %
                                     address)

        do_paranoid_email_content_validation(from_addr=from_addr,
                                             to_addrs=to_addrs,
                                             subject=self.subject,
                                             body=self.body)
        if len(self.attachments) == 0:
            msg = MIMEText(self.body.encode('utf-8'), 'plain', 'utf-8')
        else:
            msg = MIMEMultipart()
            body_part = MIMEText(self.body.encode('utf-8'), 'plain', 'utf-8')
            msg.attach(body_part)
            for attachment in self.attachments:
                msg.attach(attachment)

        # The header_body_values may be a list or tuple of values, so we will
        # add a header once for each value provided for that header.
        # (X-Launchpad-Bug, for example, may often be set more than once for a
        # bugmail.)
        for header, header_body_values in self.headers.items():
            if not zisinstance(header_body_values, (list, tuple)):
                header_body_values = [header_body_values]
            for header_body_value in header_body_values:
                msg[header] = header_body_value
        msg['To'] = ','.join(to_addrs)
        msg['From'] = from_addr
        msg['Subject'] = self.subject
        return msg
Beispiel #9
0
    def makeMessage(self):
        # It's the caller's responsibility to either encode the address fields
        # to ASCII strings or pass in Unicode strings.

        # Using the maxlinelen for the Headers as we have paranoid checks to
        # make sure that we have no carriage returns in the to or from email
        # addresses.  We use nice email addresses like 'Launchpad Community
        # Help Rotation team <*****@*****.**>' that
        # get broken over two lines in the header.  RFC 5322 specified that
        # the lines MUST be no more than 998, so we use that as our maximum.
        from_addr = Header(self.from_addr, maxlinelen=998).encode()
        to_addrs = [Header(address, maxlinelen=998).encode()
            for address in list(self.to_addrs)]

        for address in [from_addr] + to_addrs:
            if not isinstance(address, str) or not is_ascii_only(address):
                raise AssertionError(
                    'Expected an ASCII str object, got: %r' % address)

        do_paranoid_email_content_validation(
            from_addr=from_addr, to_addrs=to_addrs,
            subject=self.subject, body=self.body)
        if len(self.attachments) == 0:
            msg = MIMEText(self.body.encode('utf-8'), 'plain', 'utf-8')
        else:
            msg = MIMEMultipart()
            body_part = MIMEText(self.body.encode('utf-8'), 'plain', 'utf-8')
            msg.attach(body_part)
            for attachment in self.attachments:
                msg.attach(attachment)

        # The header_body_values may be a list or tuple of values, so we will
        # add a header once for each value provided for that header.
        # (X-Launchpad-Bug, for example, may often be set more than once for a
        # bugmail.)
        for header, header_body_values in self.headers.items():
            if not zisinstance(header_body_values, (list, tuple)):
                header_body_values = [header_body_values]
            for header_body_value in header_body_values:
                msg[header] = header_body_value
        msg['To'] = ','.join(to_addrs)
        msg['From'] = from_addr
        msg['Subject'] = self.subject
        return msg