Example #1
0
    def load_from_checkpoint(self, checkpoint_data):
        parser = email.parser.BytesParser()
        message = parser.parsebytes(checkpoint_data)

        version = int(message['Version'])
        if version not in self.SUPPORTED_VERSIONS:
            raise storage.UnsupportedFileVersionError()

        if message.get_content_type() != 'application/json':
            raise storage.CorruptedProjectError(
                "Unexpected content type %s" % message.get_content_type())

        serialized_checkpoint = message.get_payload()

        checkpoint = json.loads(serialized_checkpoint, cls=JSONDecoder)

        self.deserialize(checkpoint)
        self.init_references()

        def validate_node(root, parent, node):
            assert node.parent is parent, (node.parent, parent)
            assert node.root is root, (node.root, root)

            for c in node.list_children():
                validate_node(root, node, c)

        validate_node(self, None, self)
Example #2
0
    def set_message(self, message):
        """
        Change the message assigned to the instance and extract its metadata.

        Parameters
        ----------
        message: email.message.Message
            The new message from which the metadata will be extracted.
        """
        assert isinstance(message, email.message.Message)
        self.message = message
        self.message_id = message['Message-ID']
        self.to = self._address('To')
        senders = self._address('From')
        self.sender = senders[0] if senders else None
        addresses = self._address('Reply-To')
        self.reply_to = addresses[0] if addresses else None
        self.cc = self._address('Cc')
        self.bcc = self._address('Bcc')
        in_replay_to = message['In-Reply-To']
        if in_replay_to:
            items = self.re_in_reply_to.findall(in_replay_to)
            in_replay_to = items[0] if items else in_replay_to
        self.in_reply_to = in_replay_to
        self.subject = self._header_str('Subject')
        self.content_type = message.get_content_type()
        self.date = self._date('Date')
        self.timestamp = self._timestamp('Date')
        self.received_date = self._date('Received-Date')
        self.received_timestamp = self._timestamp('Received-Date')
        self.charset = message.get_charset()
        self.receivers = self._receivers()
Example #3
0
    def set_message(self, message):
        """
        Change the message assigned to the instance and extract its metadata.

        Parameters
        ----------
        message: email.message.Message
            The new message from which the metadata will be extracted.
        """
        assert isinstance(message, email.message.Message)
        self.message = message
        self.message_id = message['Message-ID']
        self.to = self._address('To')
        senders = self._address('From')
        self.sender = senders[0] if senders else None
        addresses = self._address('Reply-To')
        self.reply_to = addresses[0] if addresses else None
        self.cc = self._address('Cc')
        self.bcc = self._address('Bcc')
        in_replay_to = message['In-Reply-To']
        if in_replay_to:
            items = self.re_in_reply_to.findall(in_replay_to)
            in_replay_to = items[0] if items else in_replay_to
        self.in_reply_to = in_replay_to
        self.subject = self._header_str('Subject')
        self.content_type = message.get_content_type()
        self.date = self._date('Date')
        self.timestamp = self._timestamp('Date')
        self.received_date = self._date('Received-Date')
        self.received_timestamp = self._timestamp('Received-Date')
        self.charset = message.get_charset()
        self.receivers = self._receivers()
Example #4
0
    def test_customize_message_encoding(self):
        mailing = factories.MailingFactory(
            header="""Content-Transfer-Encoding: 7bit
Content-Type: multipart/alternative; boundary="===============2840728917476054151=="
Subject: Great news!
From: Mailing Sender <*****@*****.**>
To: <*****@*****.**>
Date: Wed, 05 Jun 2013 06:05:56 -0000
""",
            body="""
This is a multi-part message in MIME format.
--===============2840728917476054151==
Content-Type: text/plain; charset="iso-8859-1"
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable

This is a very simple mailing. I'm happy.
--===============2840728917476054151==
Content-Type: text/html; charset="iso-8859-1"
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html><head>
<META http-equiv=3DContent-Type content=3D"text/html; charset=3Diso-8859-1">
</head>
<body>
This is <strong> a very simple</strong> <u>mailing</u>. =
I'm happy! Nothing else to say...
</body></html>

--===============2840728917476054151==--
"""
        )
        recipient = factories.RecipientFactory(mailing=mailing)

        customizer = MailCustomizer(recipient)
        fullpath = os.path.join(customizer.temp_path, MailCustomizer.make_file_name(recipient.mailing.id, recipient.id))
        if os.path.exists(fullpath):
            os.remove(fullpath)

        self.assertFalse(os.path.exists(fullpath))

        customizer._run_customizer()

        self.assertTrue(os.path.exists(fullpath))
        parser = email.parser.Parser()
        message = parser.parse(file(fullpath, 'rt'), headersonly = False)
        assert(isinstance(message, email.message.Message))
        self.assertTrue(message.is_multipart())
        self.assertEquals("multipart/alternative", message.get_content_type())
        self.assertEquals("text/plain", message.get_payload(i=0).get_content_type())
        self.assertEquals("text/html", message.get_payload(i=1).get_content_type())
        self.assertEquals(message.get_payload(i=0).get_payload(decode=True), "This is a very simple mailing. I'm happy.")
        self.assertIn("This is <strong> a very simple</strong> <u>mailing</u>. I'm happy! ", message.get_payload(i=1).get_payload(decode=True))
Example #5
0
 def _structure(
         message: email.message.EmailMessage,
         level: int,
         include_default: bool) -> None:
     result.append('{0}{1}{2}'.format(
             indent * level,
             message.get_content_type(),
             ' [{0}]'.format(message.get_default_type())
             if include_default else ''))
     if message.is_multipart():
         for subpart in message.get_payload():
             _structure(subpart, level + 1, include_default)
Example #6
0
 def _get_text(message):
     if message.is_multipart():
         for part in message.get_payload():
             text = _get_text(part)
             if text is not None:
                 return text
     else:
         mimetype = message.get_content_type()
         if mimetype == 'text/plain':
             payload = message.get_payload()
             charset = message.get_content_charset()
             if charset is not None:
                 payload = payload.decode(charset, 'replace')
             return payload
Example #7
0
 def _get_text(message):
     if message.is_multipart():
         for part in message.get_payload():
             text = _get_text(part)
             if text is not None:
                 return text
     else:
         mimetype = message.get_content_type()
         if mimetype == 'text/plain':
             payload = message.get_payload()
             charset = message.get_content_charset()
             if charset is not None:
                 payload = payload.decode(charset, 'replace')
             return payload
Example #8
0
    def read(self) -> Tuple[FileInfo, bytes]:
        if not os.path.exists(self.path):
            raise NotFoundError()

        with open(self.path, 'rb') as fp:
            magic = fp.read(len(self.MAGIC))
            if magic != self.MAGIC:
                raise BadFileFormatError("Not an noisicaƤ file")

            # email.parser's headersonly attribute doesn't seem to work the
            # way I would expect it.
            headers = b''
            while headers[-2:] != b'\n\n':
                b = fp.read(1)
                if not b:
                    break
                headers += b

            parser = email.parser.BytesParser()
            message = parser.parsebytes(headers)

            content = fp.read()

            if 'Checksum' in message:
                should_checksum = cast(str, message['Checksum']).split(';')[0]
                checksum_type = cast(
                    str, message.get_param('type', None, 'Checksum'))
                if checksum_type is None:
                    raise BadFileFormatError("Checksum type not specified")
                if checksum_type == 'md5':
                    have_checksum = hashlib.md5(content).hexdigest()
                else:
                    raise BadFileFormatError("Unsupported checksum type '%s'" %
                                             checksum_type)

                if have_checksum != should_checksum:
                    raise CorruptedFileError("Checksum mismatch (%s != %s)" %
                                             (have_checksum, should_checksum))

            file_info = FileInfo()
            file_info.content_type = message.get_content_type()
            file_info.encoding = cast(str,
                                      message.get_param('charset', 'ascii'))
            if 'Version' in message:
                file_info.version = int(cast(str, message['Version']))
            if 'File-Type' in message:
                file_info.filetype = cast(str, message['File-Type'])

            return file_info, content
Example #9
0
    def read(self):
        if not os.path.exists(self.path):
            raise NotFoundError()

        with open(self.path, 'rb') as fp:
            magic = fp.read(len(self.MAGIC))
            if magic != self.MAGIC:
                raise BadFileFormatError("Not an noisicaƤ file")

            # email.parser's headersonly attribute doesn't seem to work the
            # way I would expect it.
            headers = b''
            while headers[-2:] != b'\n\n':
                b = fp.read(1)
                if not b:
                    break
                headers += b

            parser = email.parser.BytesParser()
            message = parser.parsebytes(headers)

            content = fp.read()

            if 'Checksum' in message:
                should_checksum = message['Checksum'].split(';')[0]
                checksum_type = message.get_param('type', None, 'Checksum')
                if checksum_type is None:
                    raise BadFileFormatError("Checksum type not specified")
                if checksum_type == 'md5':
                    have_checksum = hashlib.md5(content).hexdigest()
                else:
                    raise BadFileFormatError(
                        "Unsupported checksum type '%s'" % checksum_type)

                if have_checksum != should_checksum:
                    raise CorruptedFileError(
                        "Checksum mismatch (%s != %s)"
                        % (have_checksum, should_checksum))

            file_info = FileInfo()
            file_info.content_type = message.get_content_type()
            file_info.encoding = message.get_param('charset', 'ascii')
            if 'Version' in message:
                file_info.version = int(message['Version'])
            if 'File-Type' in message:
                file_info.filetype = message['File-Type']

            return file_info, content
Example #10
0
    def test_create_mailing_from_message(self):

        parser = email.parser.Parser()
        msg = parser.parsestr("""Content-Transfer-Encoding: 7bit
Content-Type: multipart/alternative; boundary="===============2840728917476054151=="
Subject: Great news!
From: Mailing Sender <*****@*****.**>
To: <*****@*****.**>
Date: Wed, 05 Jun 2013 06:05:56 -0000

This is a multi-part message in MIME format.
--===============2840728917476054151==
Content-Type: text/plain; charset="windows-1252"
Content-Transfer-Encoding: quoted-printable

This is a very simple mailing. I=92m happy.
--===============2840728917476054151==
Content-Type: text/html; charset="windows-1252"
Content-Transfer-Encoding: quoted-printable

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html><head>
<META http-equiv=3DContent-Type content=3D"text/html; charset=3Diso-8859-1">
</head>
<body>
This is <strong> a very simple</strong> <u>mailing</u>. =
I=92m happy! Nothing else to say...
</body></html>

--===============2840728917476054151==--
""")
        mailing = Mailing.create_from_message(msg, mail_from='*****@*****.**',
                                                   sender_name='Mailing Sender',
                                                   scheduled_start=None, scheduled_duration=None)

        message = parser.parsestr(mailing.header + mailing.body)
        assert(isinstance(message, email.message.Message))
        self.assertTrue(message.is_multipart())
        self.assertEquals("multipart/alternative", message.get_content_type())
        self.assertIsInstance(message.get_payload(i=0), email.message.Message)
        self.assertEquals("text/plain", message.get_payload(i=0).get_content_type())
        self.assertEquals("windows-1252", message.get_payload(i=0).get_param('charset'))
        self.assertEquals("text/html", message.get_payload(i=1).get_content_type())
        self.assertEquals("windows-1252", message.get_payload(i=1).get_param('charset'))
        self.assertEquals("This is a very simple mailing. I\x92m happy.", message.get_payload(i=0).get_payload(decode=True))
        self.assertIn("This is <strong> a very simple</strong> <u>mailing</u>. I\x92m happy! ", message.get_payload(i=1).get_payload(decode=True))
Example #11
0
    def __init__(self, message=None, mailbox=None, messageUID=None, agent=None):

        YCommandMessage.__init__(self,
                                 message=message,
                                 mailbox=mailbox,
                                 messageUID=messageUID,
                                 agent=agent)
        opmlMimeTypes = ['text/xml', 'text/x-opml+xml']
        self.opml = None
        if message is None:
            return
        if message.get_content_maintype() == 'multipart':
            parts = message.get_payload()
            for part in parts:
                if part.get_content_type() in opmlMimeTypes:
                    self.opml = part.get_payload(decode=True)
                elif message.get_content_type() in opmlMimeTypes:
                    self.opml = message.get_payload(decode=True)
Example #12
0
def construct_gmail_message(payload):
    message = email.message.Message()
    for header in payload['headers']:
        message[header['name']] = header['value']
    if message.get_content_maintype() == 'multipart':
        message.set_payload(
            [construct_gmail_message(part) for part in payload['parts']])
    else:
        cte = message.get('Content-Transfer-Encoding')
        if cte is not None:
            del message['Content-Transfer-Encoding']
            message['X-Original-Content-Transfer-Encoding'] = cte
        try:
            external_id = payload['body']['attachmentId']
            ct = message.get_content_type()
            message.replace_header('Content-Type', 'text/plain')
            message.set_payload(
                'Attachment with type %s, ID %r omitted; retrieve separately' %
                (ct, external_id))
        except KeyError:
            body = payload['body']['data']
            body += '=' * (4 - len(body) % 4)
            message.set_payload(base64.urlsafe_b64decode(body))
    return message
Example #13
0
    def test_customize_mixed_and_alternative_and_related_message_with_recipient_attachment(self):
        recipient = factories.RecipientFactory(
            mailing = factories.MailingFactory(
                header="""Content-Transfer-Encoding: 7bit
Content-Type: multipart/mixed; boundary="===============0000000000000000000=="
Subject: Great news!
From: Mailing Sender <*****@*****.**>
To: <*****@*****.**>
Date: Wed, 05 Jun 2013 06:05:56 -0000
""",
                body="""
This is a multi-part message in MIME format.
--===============0000000000000000000==
Content-Type: multipart/alternative; boundary="===============1111111111111111111=="

--===============1111111111111111111==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit

This is a very simple mailing.
--===============1111111111111111111==
Content-Type: multipart/related; boundary="===============2222222222222222222=="

This is a multi-part message in MIME format.
--===============2222222222222222222==
Content-Type: text/html; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit

<html><head></head>
<body>
This is <strong> a very simple</strong> <u>mailing</u>.
Nothing else to say...
<img id="Image 2"src="cid:[email protected]"
                 height="45" width="130" border="0">
</body></html>
--===============2222222222222222222==
Content-Type: image/jpeg;
 name="akema_logo_signatures.jpg"
Content-Transfer-Encoding: base64
Content-ID: <*****@*****.**>
Content-Disposition: inline;
 filename="akema_logo_signatures.jpg"

/9j/4AAQSkZJRgABAQEASABIAAD/4QESRXhpZgAATU0AKgAAAAgABgEaAAUAAAABAAAAVgEb
AAUAAAABAAAAXgEoAAMAAAABAAIAAAExAAIAAAASAAAAZgEyAAIAAAAUAAAAeIdpAAQAAAAB
AAAAjAAAANAAAABIAAAAAQAAAEgAAAABUGFpbnQuTkVUIHYzLjUuMTAAMjAxMjoxMjoxMSAx

--===============2222222222222222222==--

--===============1111111111111111111==--

--===============0000000000000000000==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="common.txt"

This is an attachment common for all recipients.
Nothing else to say...

--===============0000000000000000000==--

"""
            ),
            contact_data={
                'email': '*****@*****.**',
                'custom': 'very simple',
                'attachments': [
                    {
                        'filename': "export.csv",
                        'data': base64.b64encode("col1;col2;col3\nval1;val2;val3\n"),
                        'content-type': 'text/plain',
                        'charset': 'us-ascii',
                    },
                ]
            }
        )

        customizer = MailCustomizer(recipient)
        fullpath = os.path.join(customizer.temp_path, MailCustomizer.make_file_name(recipient.mailing.id, recipient.id))
        if os.path.exists(fullpath):
            os.remove(fullpath)

        self.assertFalse(os.path.exists(fullpath))

        customizer._run_customizer()

        self.assertTrue(os.path.exists(fullpath))
        parser = email.parser.Parser()
        message = parser.parse(file(fullpath, 'rt'), headersonly = False)
        assert(isinstance(message, email.message.Message))
        # print
        # print message.as_string()
        self.assertTrue(message.is_multipart())
        self.assertEquals("multipart/mixed",       message.get_content_type())
        self.assertEquals("multipart/alternative", message.get_payload(i=0).get_content_type())
        self.assertEquals("text/plain",            message.get_payload(i=0).get_payload(i=0).get_content_type())
        self.assertEquals("multipart/related",     message.get_payload(i=0).get_payload(i=1).get_content_type())
        self.assertEquals('This is a very simple mailing.', message.get_payload(i=0).get_payload(i=0).get_payload())
        self.assertIn("This is <strong> a very simple</strong> <u>mailing</u>.", message.get_payload(i=0).get_payload(i=1).get_payload(i=0).get_payload())
        self.assertIn("This is an attachment", message.get_payload(i=1).get_payload())
        self.assertEquals(message.get_payload(i=2).get_payload(), 'col1;col2;col3\nval1;val2;val3\n')
Example #14
0
	# <http://www.python.org/peps/pep-0234.html>
	while True:
		line = INPUT.readline()

		if msg_lines and (not line or re_message_start.match( line )):

			(headers, body, attachments, embeddeds, mbx, is_html) = extract_pieces(msg_lines, last_file_position, mbx)

			message = craft_message(headers, body, attachments, embeddeds, mbx, is_html)

			try:
				message_count = message_count + 1
				newmailbox.add(message)
			except TypeError:
				print str(headers)
				print message.get_content_type()
				traceback.print_exc(file=sys.stdout)

			EudoraLog.msg_no = EudoraLog.msg_no + 1
			msg_offset = last_file_position

			msg_lines = []

		if not line:
			break

		msg_lines.append(strip_linesep(line) + "\n")
		last_file_position = INPUT.tell()
		EudoraLog.line_no += 1

	# Check if the file isn't empty and any messages have been processed.
Example #15
0
    def _process(self, message, rec=0):
        """
        Recursively scan and filter a MIME message.
        
        _process will scan the passed message part for invalid headers
        as well as mailman signatures and modify them according to
        the global settings.
        
        Generic modifications include:
        
            * fixing of broken **References:** and **In-Reply-To** headers
            
            * generic header filtering (see :meth:`FuCore._filter_headers`)
            
            * removal of Mailman or Mailman-like headers (see :meth:`_mutate_part`)
        
        Args:
            message: a :class:`email.message` object containing a set of MIME parts
            rec:  Recursion level used to prettify log messages.
            
        Returns:
            A (probably) filtered / modified :class:`email.message` object. 
        """
        mm_parts = 0
        text_parts = 0
        mailman_sig = Reactor.MAILMAN_SIG

        self._log('>>> processing {0}', message.get_content_type(), rec=rec)

        if self._conf.complex_footer:
            self._log('--- using complex mailman filter', rec=rec)
            mailman_sig = Reactor.MAILMAN_COMPLEX

        if message.is_multipart():
            parts = message._payload
        else:
            parts = [
                message,
            ]

        list_tag = self._find_list_tag(message, rec)
        reference = message.get('References', None)
        in_reply = message.get('In-Reply-To', None)
        x_mailman = message.get('X-Mailman-Version', None)

        message._headers = self._filter_headers(list_tag, message._headers,
                                                self._conf.outlook_hacks,
                                                self._conf.fix_dateline, rec)

        if in_reply and not reference and rec == 0:
            # set References: to In-Reply-To: if where in toplevel
            # and References was not set properly
            self._log('--- set References: {0}', in_reply, rec=rec)
            try:
                # uncertain this will ever happen..
                message.replace_header('References', in_reply)
            except KeyError:
                message._headers.append(('References', in_reply))

        for i in xrange(len(parts) - 1, -1, -1):
            # again, crude since we mutate the list while iterating it..
            # the whole reason is the deeply nested structure of email.message
            p = parts[i]

            ct = p.get_content_maintype()
            cs = p.get_content_subtype()
            ce = p.get('Content-Transfer-Encoding', None)
            cb = p.get_boundary()

            self._log('-- [ct = {0}, cs = {1}, ce = <{2}>]',
                      ct,
                      cs,
                      ce,
                      rec=rec)

            if ct == 'text':
                text_parts += 1

                payload = p.get_payload(decode=True)
                self._log('--- scan: """{0}"""', payload, rec=rec, verbosity=3)

                if mailman_sig[0].search(payload) and \
                   mailman_sig[1].match(payload.split('\n')[0]):

                    self._log('*** removing this part', rec=rec)
                    self._log('--- """{0}"""', payload, rec=rec, verbosity=2)

                    message._payload.remove(p)
                    text_parts -= 1
                    mm_parts += 1

                elif mailman_sig[0].search(payload):
                    self._log('--- trying to mutate..', rec=rec)

                    (use, mutation) = self._mutate_part(payload, rec)
                    if use:
                        self._log('*** mutated this part', rec=rec)
                        self._log('--- """{0}"""',
                                  payload,
                                  rec=rec,
                                  verbosity=2)

                        payload = mutation
                        mm_parts += 1

                    # if it was encoded we need to re-encode it
                    # to keep SMIME happy

                    if ce == 'base64':
                        payload = payload.encode('base64')

                    elif ce == 'quoted-printable':
                        payload = quopri.encodestring(payload)

                    p.set_payload(payload)

                elif ct == 'message' or \
                     (ct == 'multipart' and cs in ['alternative', 'mixed']):
                    p = self._process(p, rec + 1)

                else:
                    self._log('--- what about {0}?',
                              p.get_content_type(),
                              rec=rec)

        if rec == 0:
            self._log('--- [mm_parts: {0}, text_parts: {1}, x_mailman: {0}]',
                      mm_parts,
                      text_parts,
                      x_mailman,
                      rec=rec)

            if x_mailman and mm_parts and not text_parts:
                # if we have
                # - modified the content
                # - no text parts left in outer message
                # - a valid X-Mailmann-Version:
                # --> remove outer message
                self._log('!!! beheading this one..', rec=rec)

                mm = message._payload[0]
                for h in message._headers:
                    if h[0] == 'Content-Type':
                        continue

                    try:
                        mm.replace_header(h[0], h[1])
                    except KeyError:
                        mm._headers.append(h)

                return mm

        return message
Example #16
0
 def _process(self, message, rec=0):
     """
     Recursively scan and filter a MIME message.
     
     _process will scan the passed message part for invalid headers
     as well as mailman signatures and modify them according to
     the global settings.
     
     Generic modifications include:
     
         * fixing of broken **References:** and **In-Reply-To** headers
         
         * generic header filtering (see :meth:`FuCore._filter_headers`)
         
         * removal of Mailman or Mailman-like headers (see :meth:`_mutate_part`)
     
     Args:
         message: a :class:`email.message` object containing a set of MIME parts
         rec:  Recursion level used to prettify log messages.
         
     Returns:
         A (probably) filtered / modified :class:`email.message` object. 
     """
     mm_parts    = 0
     text_parts  = 0
     mailman_sig = Reactor.MAILMAN_SIG
     
     self._log('>>> processing {0}', message.get_content_type(), rec=rec)
     
     if self._conf.complex_footer:
         self._log('--- using complex mailman filter', rec=rec)
         mailman_sig = Reactor.MAILMAN_COMPLEX
         
     if message.is_multipart():
         parts = message._payload
     else:
         parts = [message,]
         
     list_tag  = self._find_list_tag(message, rec)
     reference = message.get('References', None)
     in_reply  = message.get('In-Reply-To', None)
     x_mailman = message.get('X-Mailman-Version', None)
     
     message._headers = self._filter_headers(list_tag, message._headers,
                                             self._conf.outlook_hacks, 
                                             self._conf.fix_dateline, rec)
     
     if in_reply and not reference and rec == 0:
         # set References: to In-Reply-To: if where in toplevel
         # and References was not set properly
         self._log('--- set References: {0}', in_reply, rec=rec)
         try:
             # uncertain this will ever happen..
             message.replace_header('References', in_reply)
         except KeyError:
             message._headers.append(('References', in_reply))
             
     for i in xrange(len(parts) - 1, -1, -1):
         # again, crude since we mutate the list while iterating it..
         # the whole reason is the deeply nested structure of email.message
         p = parts[i]
         
         ct = p.get_content_maintype()
         cs = p.get_content_subtype()
         ce = p.get('Content-Transfer-Encoding', None)
         cb = p.get_boundary()
         
         self._log('-- [ct = {0}, cs = {1}, ce = <{2}>]', ct, cs, ce,
                   rec=rec)
         
         if ct == 'text':
             text_parts += 1
             
             payload = p.get_payload(decode=True)
             self._log('--- scan: """{0}"""', payload, rec=rec, verbosity=3)
             
             if mailman_sig[0].search(payload) and \
                mailman_sig[1].match(payload.split('\n')[0]):
                 
                 self._log('*** removing this part', rec=rec)
                 self._log('--- """{0}"""', payload, rec=rec, verbosity=2)
                 
                 message._payload.remove(p)
                 text_parts -= 1
                 mm_parts   += 1
                 
             elif mailman_sig[0].search(payload):
                 self._log('--- trying to mutate..', rec=rec)
                 
                 (use, mutation) = self._mutate_part(payload, rec)
                 if use:
                     self._log('*** mutated this part', rec=rec)
                     self._log('--- """{0}"""', payload, rec=rec, verbosity=2)
                     
                     payload   = mutation
                     mm_parts += 1
                     
                 # if it was encoded we need to re-encode it
                 # to keep SMIME happy
                 
                 if ce == 'base64':
                     payload = payload.encode('base64')
                     
                 elif ce == 'quoted-printable':
                     payload = quopri.encodestring(payload)
                     
                 p.set_payload(payload)
                 
             elif ct == 'message' or \
                  (ct == 'multipart' and cs in ['alternative', 'mixed']):
                 p = self._process(p, rec + 1)
                  
             else:
                 self._log('--- what about {0}?', p.get_content_type(), rec=rec)
     
     if rec == 0:
         self._log('--- [mm_parts: {0}, text_parts: {1}, x_mailman: {0}]',
                   mm_parts, text_parts, x_mailman, rec=rec)
         
         if x_mailman and mm_parts and not text_parts:
             # if we have
             # - modified the content
             # - no text parts left in outer message
             # - a valid X-Mailmann-Version:
             # --> remove outer message
             self._log('!!! beheading this one..', rec=rec)
             
             mm = message._payload[0]
             for h in message._headers:
                 if h[0] == 'Content-Type':
                     continue
                     
                 try:
                     mm.replace_header(h[0], h[1])
                 except KeyError:
                     mm._headers.append(h)
                     
             return mm
             
     return message
Example #17
0
        line = INPUT.readline()

        if msg_lines and (not line or re_message_start.match(line)):

            (headers, body, attachments, embeddeds, mbx,
             is_html) = extract_pieces(msg_lines, last_file_position, mbx)

            message = craft_message(headers, body, attachments, embeddeds, mbx,
                                    is_html)

            try:
                message_count = message_count + 1
                newmailbox.add(message)
            except TypeError:
                print str(headers)
                print message.get_content_type()
                traceback.print_exc(file=sys.stdout)

            EudoraLog.msg_no = EudoraLog.msg_no + 1
            msg_offset = last_file_position

            msg_lines = []

        if not line:
            break

        msg_lines.append(strip_linesep(line) + "\n")
        last_file_position = INPUT.tell()
        EudoraLog.line_no += 1

    # Check if the file isn't empty and any messages have been processed.
Example #18
0
    def test_customize_alternative_message_with_recipient_attachment(self):
        recipient = factories.RecipientFactory(
            mailing = factories.MailingFactory(
                header="""Content-Transfer-Encoding: 7bit
Content-Type: multipart/alternative; boundary="===============2840728917476054151=="
Subject: Great news!
From: Mailing Sender <*****@*****.**>
To: <*****@*****.**>
Date: Wed, 05 Jun 2013 06:05:56 -0000
""",
                body="""
This is a multi-part message in MIME format.
--===============2840728917476054151==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit

This is a very simple mailing.
--===============2840728917476054151==
Content-Type: text/html; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit

<html><head></head>
<body>
This is <strong> a very simple</strong> <u>mailing</u>.
Nothing else to say...

--===============2840728917476054151==--
"""
            ),
            contact_data={
                'email': '*****@*****.**',
                'custom': 'very simple',
                'attachments': [
                    {
                        'filename': "export.csv",
                        'data': base64.b64encode("col1;col2;col3\nval1;val2;val3\n"),
                        'content-type': 'text/plain',
                        'charset': 'us-ascii',
                    },
                ]
            }
        )

        customizer = MailCustomizer(recipient)
        fullpath = os.path.join(customizer.temp_path, MailCustomizer.make_file_name(recipient.mailing.id, recipient.id))
        if os.path.exists(fullpath):
            os.remove(fullpath)

        self.assertFalse(os.path.exists(fullpath))

        customizer._run_customizer()

        self.assertTrue(os.path.exists(fullpath))
        parser = email.parser.Parser()
        message = parser.parse(file(fullpath, 'rt'), headersonly = False)
        assert(isinstance(message, email.message.Message))
        # print
        # print message.as_string()
        self.assertTrue(message.is_multipart())
        self.assertEquals("multipart/mixed", message.get_content_type())
        self.assertEquals("multipart/alternative", message.get_payload(i=0).get_content_type())
        self.assertEquals(message.get_payload(i=0).get_payload(i=0).get_payload(), 'This is a very simple mailing.')
        self.assertIn("This is <strong> a very simple</strong> <u>mailing</u>.", message.get_payload(i=0).get_payload(i=1).get_payload())
        self.assertEquals(message.get_payload(i=1).get_payload(), 'col1;col2;col3\nval1;val2;val3\n')