Example #1
0
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
Example #2
0
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) ]
Example #3
0
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
Example #4
0
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) ]