Exemple #1
0
 def process_maildir(d, dosa=1, pats=None):

    parser = Parser()

    for fn in glob.glob(os.path.join(d, "cur", "*")):

        print ("reading from %s..." % fn),

        file = open(fn)

        msg = parser.parse(file)

        process_message(msg, dosa, pats)

        tmpfn = os.path.join(d, "tmp", os.path.basename(fn))

        tmpfile = open(tmpfn, "w")

        print "writing to %s" % tmpfn

        gen = email.Generator.Generator(tmpfile, maxheaderlen=0)

        gen.flatten(msg, unixfrom=0)

        os.rename(tmpfn, fn)
Exemple #2
0
def create_message(corpus, data, msg0=None):
    from email import Charset, Parser, MIMEMessage
    if not isinstance(data, unicode):
        raise TypeError('data must be a unicode.')
    p = Parser.FeedParser()
    p.feed(data)
    msg1 = p.close()
    csmap = Charset.Charset(config.MESSAGE_CHARSET)
    attach_msgs = []
    # Re-encode the headers.
    headers = []
    labels = []
    for (k, v) in msg1.items():
        v = rmsp(v)
        if not v: continue
        kl = k.lower()
        if kl == 'x-forward-msg':
            attach_msgs.extend(get_numbers(v))
            continue
        if kl == 'label':
            labels = v.split(',')
            continue
        headers.append((k.encode('ascii', 'strict'), encode_header(v, csmap)))
    # Remove all the existing headers.
    for k in msg1.keys():
        del msg1[k]
    # Reattach the headers.
    for (k, v) in headers:
        msg1[k] = v
    # Change the body.
    data = msg1.get_payload(decode=False)
    try:
        # First try to encode with us-ascii.
        data.encode('ascii', 'strict')
        # Succeed.
        msg1.set_charset('ascii')
    except UnicodeError:
        # Re-encode the body.
        if not csmap.output_charset:
            csmap = Charset.Charset('utf-8')
        msg1.set_charset(str(csmap.output_charset))
        data = data.encode(str(csmap.output_codec), 'replace')
    msg1.set_payload(data)
    # Attach other messages (for forwarding).
    if attach_msgs:
        for loc in attach_msgs:
            p = Parser.FeedParser()
            p.feed(corpus.get_message(loc))
            msg1 = mime_add(msg1, MIMEMessage.MIMEMessage(p.close()))
    # Integrate other mime objects.
    if msg0 and msg0.is_multipart():
        for obj in msg0.get_payload()[1:]:
            msg1 = mime_add(msg1, obj)
    validate_message_structure(msg1)
    return (msg1, labels)
def process_maildir(d, dosa=1, pats=None):
    parser = Parser()
    for fn in glob.glob(os.path.join(d, "cur", "*")):
        print("reading from %s..." % fn),
        file = open(fn)
        msg = parser.parse(file)
        process_message(msg, dosa, pats)

        tmpfn = os.path.join(d, "tmp", os.path.basename(fn))
        tmpfile = open(tmpfn, "w")
        print "writing to %s" % tmpfn
        gen = email.Generator.Generator(tmpfile, maxheaderlen=0)
        gen.flatten(msg, unixfrom=0)

        os.rename(tmpfn, fn)
Exemple #4
0
    def _createBounceMessage(self, log, toAddress, msg):
        """
        Create a multipart MIME message that will be sent to the user to indicate
        that their message has bounced.

        @param log: ???
        @param toAddress: The email address that bounced
        @param msg: The message that bounced

        @return: L{MP.MIMEMultipart}
        """
        bounceText = (
            'Your message to %(recipient)s, subject "%(subject)s", '
            'could not be delivered.')
        bounceText %= {
            'recipient': toAddress,
            'subject': msg.impl.getHeader(u'subject')}

        original = P.Parser().parse(msg.impl.source.open())

        m = MMP.MIMEMultipart(
            'mixed',
            None,
            [MT.MIMEText(bounceText, 'plain'),
             MT.MIMEText(log, 'plain'),
             MM.MIMEMessage(original)])

        m['Subject'] = 'Unable to deliver message to ' + toAddress
        m['From'] = '<>'
        m['To'] = ''
        return m
    def test_createMessageWrapsLines(self):
        """
        Ensure that the text of an outgoing message is wrapped to 78
        characters and that its MIME type is 'text/plain; format=flowed'.
        """
        self.cf._sendOrSave(fromAddress=self.defaultFromAddr,
                            toAddresses=[
                                mimeutil.EmailAddress(u'[email protected]',
                                                      mimeEncoded=False)
                            ],
                            subject=u'The subject of the message.',
                            messageBody=u' '.join([u'some words'] * 1000),
                            cc=[],
                            bcc=[],
                            files=[],
                            draft=False)

        msg = self.userStore.findUnique(
            smtpout.DeliveryToAddress)._getMessageSource()
        textPart = Parser.Parser().parse(msg)
        self.assertEqual(textPart.get_content_type(), "text/plain")
        self.assertEqual(textPart.get_param("format"), "flowed")
        body = textPart.get_payload().decode("quoted-printable")
        maxLineLength = max([len(line) for line in body.split("\n")])
        self.failIf(maxLineLength > 78)
Exemple #6
0
    def createRedirectedMessage(self, fromAddress, toAddresses, message):
        """
        Create a L{Message} item based on C{message}, with the C{Resent-From}
        and C{Resent-To} headers set

        @type fromAddress: L{smtpout.FromAddress}

        @type toAddresses: sequence of L{mimeutil.EmailAddress}

        @type message: L{Message}

        @rtype: L{Message}
        """
        m = P.Parser().parse(message.impl.source.open())
        def insertResentHeaders(i):
            m._headers.insert(i, ('resent-from', MH.Header(
                fromAddress.address).encode()))
            m._headers.insert(i, ('resent-to', MH.Header(
                mimeutil.flattenEmailAddresses(toAddresses)).encode()))
            m._headers.insert(i, ('resent-date', EU.formatdate()))
            m._headers.insert(i, ('resent-message-id',
                                  smtp.messageid('divmod.xquotient')))
        for (i, (name, _)) in enumerate(m._headers):
            #insert Resent-* headers after all Received headers but
            #before the rest
            if name.lower() != "received":
                insertResentHeaders(i)
                break
        else:
            insertResentHeaders(0)
        s = S.StringIO()
        G.Generator(s).flatten(m)
        s.seek(0)

        return self.createMessageAndQueueIt(fromAddress.address, s, True)
    def test_redirectHeaderOrdering(self):
        """
        Test that Resent headers get added after Received headers but
        before the rest.
        """
        msgtext = """\
Received: from bob by example.com with smtp (SuparMTA 9.99)
        id 1BfraZ-0001D0-QA
        for [email protected]; Thu, 01 Jul 2004 02:46:15 +0000
received: from bob by example.com with smtp (SuparMTA 9.99)
        id 1BfraZ-0001D0-QA
        for [email protected]; Thu, 01 Jul 2004 02:46:17 +0000
From: <*****@*****.**>
To: <*****@*****.**>
Subject: Hi

Hi
""".replace('\n', '\r\n')

        class StubMsgFile:
            def open(self):
                return StringIO(msgtext)

        message = StubStoredMessageAndImplAndSource(store=self.userStore)
        message.__dict__['_source'] = StubMsgFile()
        msg = self.composer.createRedirectedMessage(
            self.defaultFromAddr,
            [mimeutil.EmailAddress(u'testuser@localhost', mimeEncoded=False)],
            message)
        m = Parser.Parser().parse(msg.impl.source.open())
        self.assertEqual(len(m._headers), 9)
        self.assertEqual(m._headers[0][0].lower(), "received")
        self.assertEqual(m._headers[6][0].lower(), "from")
Exemple #8
0
    def __init__(self, fromlines=None, fromstring=None, fromfile=None):
        #self.log = Logger()
        self.recipient = None
        self.received_by = None
        self.received_from = None
        self.received_with = None
        self.__raw = None
        try:
            parser = Parser.BytesParser()
            parsestr = parser.parsebytes
        except:
            parser = Parser.Parser()
            parsestr = parser.parsestr


        # Message is instantiated with fromlines for POP3, fromstring for
        # IMAP (both of which can be badly-corrupted or invalid, i.e. spam,
        # MS worms, etc).  It's instantiated with fromfile for the output
        # of filters, etc, which should be saner.
        if fromlines:
            try:
                self.__msg = parsestr(_NL.join(fromlines))
            except Errors.MessageError as o:
                self.__msg = corrupt_message(o, fromlines=fromlines)
            self.__raw = _NL.join(fromlines)
        elif fromstring:
            try:
                self.__msg = parsestr(fromstring)
            except Errors.MessageError as o:
                self.__msg = corrupt_message(o, fromstring=fromstring)
            self.__raw = fromstring
        elif fromfile:
            try:
                self.__msg = parser.parse(fromfile)
            except Errors.MessageError as o:
                # Shouldn't happen
                self.__msg = corrupt_message(o, fromstring=fromfile.read())
            # fromfile is only used by getmail_maildir, getmail_mbox, and
            # from reading the output of a filter.  Ignore __raw here.
        else:
            # Can't happen?
            raise SystemExit('Message() called with wrong arguments')

        self.sender = address_no_brackets(self.__msg['Return-Path']
                                          or self.__msg['Sender']
                                          or 'unknown')
 def test_createMessageHonorsSmarthostFromAddress(self):
     """
     Sending a message through the Compose UI should honor the from
     address we give to it
     """
     self.defaultFromAddr.address = u'*****@*****.**'
     msg = createMessage(
         self.composer, self.cabinet, None, self.defaultFromAddr,
         [mimeutil.EmailAddress('*****@*****.**', mimeEncoded=False)],
         u'Sup dood', u'A body', (), (), u'')
     file = msg.impl.source.open()
     msg = Parser.Parser().parse(file)
     self.assertEquals(msg["from"], '*****@*****.**')
Exemple #10
0
def _fileItemToEmailPart(fileItem):
    """
    Convert a L{File} item into an appropriate MIME part object
    understandable by the stdlib's C{email} package
    """
    (majorType, minorType) = fileItem.type.split('/')
    if majorType == 'multipart':
        part = P.Parser().parse(fileItem.body.open())
    else:
        part = MB.MIMEBase(majorType, minorType)
        if majorType == 'message':
            part.set_payload([P.Parser().parse(fileItem.body.open())])
        else:
            part.set_payload(fileItem.body.getContent())
            if majorType == 'text':
                EE.encode_quopri(part)
            else:
                EE.encode_base64(part)
    part.add_header('content-disposition',
                    'attachment',
                    filename=fileItem.name)
    return part
 def test_createRedirectedMessage(self):
     """
     Test that L{compose.Composer.createRedirectedMessage} sets the right
     headers
     """
     message = StubStoredMessageAndImplAndSource(store=self.userStore)
     msg = self.composer.createRedirectedMessage(
         self.defaultFromAddr,
         [mimeutil.EmailAddress(u'testuser@localhost', mimeEncoded=False)],
         message)
     m = Parser.Parser().parse(msg.impl.source.open())
     self.assertEquals(m['Resent-To'], 'testuser@localhost')
     self.assertEquals(m['Resent-From'], self.defaultFromAddr.address)
     self.failIfEqual(m['Resent-Date'], None)
     self.failIfEqual(m['Resent-Message-ID'], None)
Exemple #12
0
 def read_messages(self):
   from email import Parser
   for fname in os.listdir(self.dirname):
     if fname.startswith('.'): continue
     fname = os.path.join(self.dirname, fname)
     fp = file(fname, 'rb')
     p = Parser.FeedParser()
     for line in fp:
       p.feed(line)
       if not line.strip(): break
     msg = p.close()
     if self.ruleset:
       labels = self.ruleset.apply_msg(msg)
     else:
       labels = []
     self.msgs.append((fname, labels, get_message_date(msg)))
   return
Exemple #13
0
 def finish(self):
   import poplib
   from email import Parser
   for i in xrange(self.msgcount):
     try:
       data = self.server.retr(i+1)[1]
     except poplib.error_proto, e:
       raise MessagePOP3Error(str(e))
     data = '\r\n'.join(data)
     p = Parser.FeedParser()
     p.feed(data)
     msg = p.close()
     if self.ruleset:
       labels = self.ruleset.apply_msg(msg)
     else:
       labels = []
     yield (data, labels, get_message_date(msg))
Exemple #14
0
 def finish(self):
   from mailbox import PortableUnixMailbox
   from email import Parser
   try:
     fp = file(self.fname, 'rb')
   except IOError:
     return
   for data in PortableUnixMailbox(fp, lambda msgfp: msgfp.read()):
     p = Parser.FeedParser()
     p.feed(data)
     msg = p.close()
     if self.ruleset:
       labels = self.ruleset.apply_msg(msg)
     else:
       labels = []
     yield (data, labels, get_message_date(msg))
   fp.close()
   return
    def test_redirect(self):
        """
        Test L{compose.Composer.redirect}
        """
        message = StubStoredMessageAndImplAndSource(store=self.userStore)
        msg = self.composer.redirect(
            self.defaultFromAddr,
            [mimeutil.EmailAddress(u'testuser@localhost', mimeEncoded=False)],
            message)

        self.assertEquals(str(self.reactor.factory.fromEmail),
                          self.defaultFromAddr.address)

        self.assertEquals(list(self.reactor.factory.toEmail),
                          ['testuser@localhost'])

        m = Parser.Parser().parse(
            self.userStore.findUnique(exmess.Message).impl.source.open())

        self.assertEquals(m['Resent-From'], self.defaultFromAddr.address)
        self.assertEquals(m['Resent-To'], 'testuser@localhost')
        self.assertEquals(message.statuses, [exmess.REDIRECTED_STATUS])
Exemple #16
0
 def process_message(self, peer, mailfrom, rcpttos, data):
     ipaddr = peer[0]
     print "Message sent from %s" % ipaddr
     if ipaddr[0:3] == localNetwork:
         #Parse the message into an email.Message instance
         p = Parser.Parser()
         m = p.parsestr(data)
         print "Received Message"
         body = m.get_payload(decode=1)
         toAddr = m['To']
         if string.find(toAddr, '<') > 0:
             toAddr = re.search("<(?P<email>.+)>", toAddr).group('email')
         status, encMessage = gnupg.encryptMessage(body, toAddr)
         if status == 1:
             m.set_payload(encMessage)
             self.sendEncMessage(m)
             status = ''
         else:
             print "Error in encrypting message"
     else:
         print "Not authorised smtp user"
         status = "Not authorised smtp user"
     return status
def process_mailbox(f, dosa=1, pats=None):
    gen = email.Generator.Generator(sys.stdout, maxheaderlen=0)
    for msg in mailbox.PortableUnixMailbox(f, Parser().parse):
        process_message(msg, dosa, pats)
        gen.flatten(msg, unixfrom=1)
Exemple #18
0
    def _post(self):

        if self.request.body:
            message = self.request.body
        else:
            message = self.get_argument('message')

        parser = Parser.Parser()
        msg = parser.parsestr(message)

        ## Check that it's sent to the right address
        email_tos = parse_email_line(msg['To'])
        email_reminder = None
        # need to turn then reply to address into a regex
        reply_to_parts = EMAIL_REMINDER_SENDER % dict(id='XXX')
        reply_to_parts = reply_to_parts.split('XXX')
        assert len(reply_to_parts) == 2
        regex = re.compile(re.escape(reply_to_parts[0]) + '(\w+)' \
          + re.escape(reply_to_parts[1]), re.I)
        for email_to in email_tos:
            if regex.findall(email_to):
                _id = regex.findall(email_to)[0]
                try:
                    email_reminder = self.db.EmailReminder\
                      .one({'_id': ObjectId(_id)})
                except InvalidId:
                    pass

        ## Check that it was sent from someone we know
        from_user = None
        for from_email in parse_email_line(msg['From']):
            from_user = self.find_user(from_email)

        message_body = None
        character_set = 'utf-8'
        if msg.is_multipart():
            for part in msg.walk():
                if part.is_multipart():
                    continue
                name = part.get_param('name')
                if not part.get_param('name') and part.get_content_type(
                ).lower() == 'text/plain':
                    message_body = part.get_payload(decode=True)
                    if isinstance(message_body, str):
                        for charset in part.get_charsets():
                            if not charset:
                                charset = 'utf8'
                            message_body = unicode(message_body, charset)
                            character_set = charset
                            break
                    #print "BODY"
                    #print repr(message_body)
                    #print message_body
                    # If it's a multipart email, only use the first part
                    break

        else:
            # not a multipart message then it's easy
            message_body = msg.get_payload(decode=True)
            for each in msg.get_charsets():
                if each:
                    character_set = each
                    break
            if character_set:
                message_body = unicode(message_body, character_set)
            else:
                message_body = unicode(message_body, 'utf-8')

        if not from_user:
            # only bother to reply if the email appears to be sent from
            # us originally
            if 'INSTRUCTIONS' in message_body and 'DoneCal' in msg['Subject']:
                self.error_reply("Not a registered account: %s" % msg['From'],
                                 msg, message_body)

            self.write("Not recognized from user (%r)" % msg['From'])
            return

        assert from_user

        if not email_reminder:
            # At this point, we know it was not a proper reply,
            # but it was sent from one of our users because otherwise it would have been
            # dealt with just above this
            err_msg = u"This is not a reply to an email reminder from your account.\n"\
                      u"To set some up, go to http://%s/emailreminders/" % \
                      self.request.host
            self.error_reply(err_msg, msg, message_body)

            self.write("Not a reply to an email reminder")
            return

        assert email_reminder

        if email_reminder.user._id != from_user._id:
            if 'INSTRUCTIONS' in message_body \
              and 'DoneCal' in msg['Subject']:
                owner_email = email_reminder.user.email
                p = owner_email.find('@')
                owner_email_brief = owner_email[:p -
                                                2] + '...' + owner_email[p +
                                                                         2:]
                err_msg = u"This is a reply to someone else's email reminder "\
                          u"that belonged to: %s" % owner_email_brief
                self.error_reply(err_msg,
                                 msg,
                                 message_body,
                                 email_reminder=email_reminder)

            self.write("No email reminders set up")
            return

        CRLF = '\r\n'
        # formatflowed expects the line breakers to be \r\n
        if not message_body.count(CRLF):
            message_body = message_body.replace('\n', CRLF)
        original_message_lines = [
            x for x in message_body.splitlines() if x.startswith('> ')
        ]
        if not original_message_lines:
            # then desperately look for something like
            # ------Mensaje original------
            new_text = []
            for line in message_body.splitlines():
                if line.startswith('------') and line.endswith('------'):
                    break
                new_text.append(line)
            else:
                err_msg = u"Your email is not a reply to an email reminder. "\
                          u"When sending your reply try to use inline style."
                self.error_reply(err_msg, msg, message_body)
                self.write("Not a reply email")
                return
            remove_last_paragraph = False
        else:
            remove_last_paragraph = True
            message_body_ascii = message_body.encode(character_set)
            from formatflowed import decode
            try:
                if character_set:
                    textflow = decode(message_body_ascii,
                                      character_set=character_set)
                else:
                    textflow = decode(message_body_ascii)
            except LookupError:
                if not character_set:
                    raise
                # _character_set is quite likly 'iso-8859-1;format=flowed'
                _character_set = _character_set.split(';')[0].strip()
                textflow = decode(message_body_ascii,
                                  character_set=character_set)

            new_text = []
            for segment in textflow:
                if not segment[0]['quotedepth']:
                    # level zero
                    new_text.append(segment[1])
                else:
                    break

        new_text = u"\n".join(new_text)
        if email_reminder:
            if email_reminder.time[0] > 12:
                about_today = True
            else:
                about_today = False
        else:
            if 'today' in msg['Subject']:
                about_today = True
            else:
                about_today = False

        tz_offset = email_reminder.tz_offset
        count_new_events = 0
        paragraphs = re.split('\n\n+', new_text.strip())
        if remove_last_paragraph:
            # Because we expect the last line to be something like
            #    On 25 December 2010 09:00, DoneCal
            #    <*****@*****.**> wrote:
            #
            # So we have to remove it.
            paragraphs = paragraphs[:-1]
        previous_duration = None
        for text in paragraphs:
            if not text.strip():
                # it was blank
                continue
            try:
                event = self.parse_and_create_event(
                    from_user,
                    text,
                    about_today,
                    tz_offset,
                    previous_duration=previous_duration)
                if event:
                    if not event.all_day:
                        previous_duration = (event.end -
                                             event.start).seconds / 60
                    self.write("Created %r\n" % event.title)
                    count_new_events += 1
            except ParseEventError, exception_message:
                self.write("Parse event error (%s)\n" % exception_message)
                if 'INSTRUCTIONS' in message_body and \
                 'DoneCal' in msg['Subject']:
                    err_msg = "Failed to create an event from this line:\n\t%s\n" \
                      % text
                    err_msg += "(Error message: %s)\n" % exception_message
                    self.error_reply(err_msg,
                                     msg,
                                     message_body,
                                     email_reminder=email_reminder)
                else:
                    logging.error("Parse event error on email not replied to",
                                  exc_info=True)
    sys.exit(69)  # Hard Bounce - don't retry bad arguments
logging.debug("From : %s, to : %r" % (cli_from, cli_to))

try:
    conn = sqlite3.connect('/etc/postfix/db/undel.db')
    logging.debug("Opening database")
except Exception, e:
    logging.error("Error opening database: %s" % (e))
    sys.exit(75)  # tempfail

if "uatbounce." not in cli_from:
    logging.debug("Starting Outbound Mail Process")
    verp = "uatbounce." + str(time.time()) + "." + cli_from
    sender = re.sub(r'\+.+@', '@', cli_from)
    content = ''.join(sys.stdin.readlines())
    p = Parser.Parser()
    parsed = p.parsestr(content, True)
    logging.debug("email source : %s" % parsed.as_string())
    subject = parsed.get('Subject')
    try:
        sql = ("INSERT INTO mails"
               "(verp, sender, recipient, subject, bouncetime)"
               " VALUES ('%s', '%s', '%s', '%s', 0)" %
               (verp, sender, cli_to, subject))
        logging.debug("Trying SQL: %s" % (sql))
        conn.execute(sql)
    except Exception, e:
        logging.error("Error inserting record: %s" % (e))
    conn.commit()
    conn.close()
Exemple #20
0
	"""
    items = decode_header(h)
    parts = []
    for item in items:
        if item[1] == None:
            parts.append(item[0])
        else:
            parts.append(item[0].decode(item[1]).encode('utf-8'))
    return ' '.join(parts)


for partner in session.query(Partner).all():
    log(3, 'partner', partner=partner)

log(3, 'begin mail processing from stdin')
mail_parser = Parser.Parser()
parsed_mail = mail_parser.parsestr(sys.stdin.read())
log(3, 'mail parsed')

from email.header import decode_header

log(3, 'parsing mail From: header')
mail_from = parseaddr(parsed_mail.get('From'))
mail_from_decoded = decode_header_ng(mail_from[0])
mail_domain = mail_from[1].split('@')[1]
log(3,
    'mail From: header parsed',
    raw_name=mail_from[0],
    decoded_name=mail_from_decoded,
    mail_address=mail_from[1],
    mail_domain=mail_domain)