def parsemail(mail, logger='none'): log = logging.getLogger(logger) if len(mail) == 0: raise MailParserException('Empty mail') data = { 'type': 'mail' } # parse mail try: message = email.parser.Parser().parsestr(mail) except UnicodeEncodeError: message = email.parser.Parser().parsestr(mail.encode('latin_1')) # test defects and try to save defect mails if len(message.defects) != 0: raise MailParserException("Parser signaled defect:\n %s" % (str(message.defects))) # encoded word is not decoded here, because it only should appear in the # display name that is discarded by the last map function # parse from and sender addresses addresses = itertools.chain(*(message.get_all(field) for field in ('from', 'sender') if message.has_key(field))) data['from'] = map(lambda adrs: adrs[1], set(email.utils.getaddresses(addresses))) log.info("From: %s"%(' '.join(data['from']))) # parse recipient addresses addresses = itertools.chain(*(message.get_all(field) for field in ('to', 'cc') if message.has_key(field))) data['to'] = map(lambda adrs: adrs[1], set(email.utils.getaddresses(addresses))) log.info("To: %s"%(' '.join(data['to']))) # parse date and convert it to standard format in UTC if message.get('Date', None): try: # guesses format and parses 10-tuple parsedtime = email.utils.parsedate_tz(message.get('Date')) # seconds since epoch utc_timestamp = calendar.timegm(parsedtime[0:9])-parsedtime[9] # formatted data['date'] = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(utc_timestamp)) log.info("Date: %s", data['date']) except Exception as e: raise MailParserException("Could not convert %s to YYYY-MM-DD hh:mm:ss\n %s" % (message.get('Date'), str(e))) # format current UTC time data['upload_date'] = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(time.time())) log.info("upload-date: %s", data['upload_date']) # add labels data['labels'] = [] if message.get('Status', None): if not 'R' in message.get('Status'): data['labels'].append('unread') else: data['labels'].append('unread') if config.autolabels: labeller = labels.Labeller(path=config.autolabels) labeller.check(data) log.info("Labels: %s", ' '.join(data['labels'])) return data
def encrypt_all_payloads_mime( message, gpg_to_cmdline ): # Convert a plain text email into PGP/MIME attachment style. Modeled after enigmail. submsg1 = email.message.Message() submsg1.set_payload("Version: 1\n") submsg1.set_type("application/pgp-encrypted") submsg1.set_param('PGP/MIME version identification', "", 'Content-Description' ) submsg2 = email.message.Message() submsg2.set_type("application/octet-stream") submsg2.set_param('name', "encrypted.asc") submsg2.set_param('OpenPGP encrypted message', "", 'Content-Description' ) submsg2.set_param('inline', "", 'Content-Disposition' ) submsg2.set_param('filename', "encrypted.asc", 'Content-Disposition' ) if type ( message.get_payload() ) == str: # WTF! It seems to swallow the first line. Not sure why. Perhaps # it's skipping an imaginary blank line someplace. (ie skipping a header) # Workaround it here by prepending a blank line. # This happens only on text only messages. additionalSubHeader="" if message.has_key('Content-Type') and not message['Content-Type'].startswith('multipart'): additionalSubHeader="Content-Type: "+message['Content-Type']+"\n" submsg2.set_payload(additionalSubHeader+"\n" +message.get_payload(decode=True)) check_nested = True else: processed_payloads = generate_message_from_payloads(message) submsg2.set_payload(processed_payloads.as_string()) check_nested = False message.preamble = "This is an OpenPGP/MIME encrypted message (RFC 2440 and 3156)" # Use this just to generate a MIME boundary string. junk_msg = MIMEMultipart() junk_str = junk_msg.as_string() # WTF! Without this, get_boundary() will return 'None'! boundary = junk_msg.get_boundary() # This also modifies the boundary in the body of the message, ie it gets parsed. if message.has_key('Content-Type'): message.replace_header('Content-Type', "multipart/encrypted; protocol=\"application/pgp-encrypted\";\nboundary=\"%s\"\n" % boundary) else: message['Content-Type'] = "multipart/encrypted; protocol=\"application/pgp-encrypted\";\nboundary=\"%s\"\n" % boundary return [ submsg1, encrypt_payload(submsg2, gpg_to_cmdline, check_nested) ]
def encrypt_all_payloads(message, gpg_to_cmdline): encrypted_payloads = list() if type(message.get_payload()) == str: if ( cfg.has_key("default") and cfg["default"].has_key("mime_conversion") and cfg["default"]["mime_conversion"] == "yes" ): # Convert a plain text email into PGP/MIME attachment style. Modeled after enigmail. submsg1 = email.message.Message() submsg1.set_payload("Version: 1\n") submsg1.set_type("application/pgp-encrypted") submsg1.set_param("PGP/MIME version identification", "", "Content-Description") submsg2 = email.message.Message() submsg2.set_type("application/octet-stream") submsg2.set_param("name", "encrypted.asc") submsg2.set_param("OpenPGP encrypted message", "", "Content-Description") submsg2.set_param("inline", "", "Content-Disposition") submsg2.set_param("filename", "encrypted.asc", "Content-Disposition") # WTF! It seems to swallow the first line. Not sure why. Perhaps # it's skipping an imaginary blank line someplace. (ie skipping a header) # Workaround it here by prepending a blank line. submsg2.set_payload("\n" + message.get_payload()) message.preamble = "This is an OpenPGP/MIME encrypted message (RFC 2440 and 3156)" # Use this just to generate a MIME boundary string. junk_msg = MIMEMultipart() junk_str = junk_msg.as_string() # WTF! Without this, get_boundary() will return 'None'! boundary = junk_msg.get_boundary() # This also modifies the boundary in the body of the message, ie it gets parsed. if message.has_key("Content-Type"): message.replace_header( "Content-Type", 'multipart/encrypted; protocol="application/pgp-encrypted";\nboundary="%s"\n' % boundary, ) else: message["Content-Type"] = ( 'multipart/encrypted; protocol="application/pgp-encrypted";\nboundary="%s"\n' % boundary ) return [submsg1, encrypt_payload(submsg2, gpg_to_cmdline)] else: # Do a simple in-line PGP conversion of a plain text email. return encrypt_payload(message, gpg_to_cmdline).get_payload() for payload in message.get_payload(): if type(payload.get_payload()) == list: encrypted_payloads.extend(encrypt_all_payloads(payload, gpg_to_cmdline)) else: encrypted_payloads.append(encrypt_payload(payload, gpg_to_cmdline)) return encrypted_payloads
def encrypt_all_payloads_mime( message, gpg_to_cmdline ): # Convert a plain text email into PGP/MIME attachment style. Modeled after enigmail. submsg1 = email.message.Message() submsg1.set_payload("Version: 1\n") submsg1.set_type("application/pgp-encrypted") submsg1.set_param('PGP/MIME version identification', "", 'Content-Description' ) submsg2 = email.message.Message() submsg2.set_type("application/octet-stream") submsg2.set_param('name', "encrypted.asc") submsg2.set_param('OpenPGP encrypted message', "", 'Content-Description' ) submsg2.set_param('inline', "", 'Content-Disposition' ) submsg2.set_param('filename', "encrypted.asc", 'Content-Disposition' ) if type ( message.get_payload() ) == str: # WTF! It seems to swallow the first line. Not sure why. Perhaps # it's skipping an imaginary blank line someplace. (ie skipping a header) # Workaround it here by prepending a blank line. # This happens only on text only messages. submsg2.set_payload("\n" + message.get_payload()) check_nested = True else: processed_payloads = generate_message_from_payloads(message) submsg2.set_payload(processed_payloads.as_string()) check_nested = False message.preamble = "This is an OpenPGP/MIME encrypted message (RFC 2440 and 3156)" # Use this just to generate a MIME boundary string. junk_msg = MIMEMultipart() junk_str = junk_msg.as_string() # WTF! Without this, get_boundary() will return 'None'! boundary = junk_msg.get_boundary() # This also modifies the boundary in the body of the message, ie it gets parsed. if message.has_key('Content-Type'): message.replace_header('Content-Type', "multipart/encrypted; protocol=\"application/pgp-encrypted\";\nboundary=\"%s\"\n" % boundary) else: message['Content-Type'] = "multipart/encrypted; protocol=\"application/pgp-encrypted\";\nboundary=\"%s\"\n" % boundary return [ submsg1, encrypt_payload(submsg2, gpg_to_cmdline, check_nested) ]