class EmailParser(object): def __init__ (self): self.raw = None self.body = None self.subject = None self.sender = None self.recipient = None self.recipientbm = None self.pgpbody = None self.headers = {} self.signature = False self.encryption = False self.dkim = False self.status = False self.multipart = False self.maintype = None self.subtype = None self.charset = None self.attachment = None self.dsn = None self.parent = None self.out = None def parse(self): if self.parent == None: try: self.parse_headers() except: return False try: self.parse_body() except: return False self.subject = base64.b64encode(subject) self.body = base64.b64encode(body) if (sender[0:3] == "BM-"): senderbm = sender else: senderbm = BMAPI().get_address(sender) recipientbm = recipient userdata = lib.user.GWUser(bm = recipient) if userdata.check(): recipient = userdata['email'] try: ackData = BMAPI().conn().sendMessage(recipientbm, senderbm, self.subject, self.body, 2) logging.info("Sent BM from %s to %s", sender, recipient) except: logging.error("Failure sending BM from %s to %s", sender, recipient) return False return True def read_from_file(self, fname): try: fullpath = os.path.join(BMConfig().get("bmgateway", "bmgateway", "mail_folder"), fname) f = open(fullpath, 'r') self.raw = f.read() f.close() except IOError: logging.error('Could not read email from: ' + fullpath) def from_data(self, data): self.raw = data def parse_headers(self): self.headers = email.parser.Parser().parsestr(self.raw) if not self.headers: logging.error('Email missing headers') raise self.extract_sender() self.extract_recipient() if not self.sender or not self.recipient: logging.warn('Email missing sender or recipient') raise self.extract_subject() self.extract_dkim() def extract_sender(self): self.sender = self.headers["From"] ## DSN or missing sender if self.sender == '<>' or not self.sender: self.sender = BMConfig().get("bmgateway", "bmgateway", "relay_address_label") else: self.sender = re.findall(r'[\w\.+-]+@[\w\.-]+.[\w]+', self.sender)[0] self.sender = self.sender.lower() self.body = email.message_from_string(self.raw) if self.body.get_content_maintype == "multipart": self.multipart = True self.maintype = self.body.get_content_maintype() self.subtype = self.body.get_content_subtype() self.charset = self.body.get_content_charset() def attachment( if self.body.has_key("Content-Disposition") and self.body.__getitem__("Content-Disposition")[:11] == "attachment": self.attachment = email.header.decode_header(part.get_filename())[0] def extract_recipient(self): ## find email details userdata = None rcpts = () for rcpthdr in ("To", "X-Original-To", "Cc"): rcpts.extend(re.findall(r'[\w\.+-]+@[\w\.-]+.[\w]+', self.headers[rcpthdr])) for candidate in rcpts: ## strip extension (user+foo@domain) self.recipient = re.sub(r'\+.*@', '@', candidate) ## lowercasse self.recipient = self.recipient.lower() ## check if user exists userdata = lib.user.GWUser(email = self.recipient, unalias = True) if userdata.check(): break def extract_subject(self): self.subject = email.header.decode_header(self.headers['Subject'])[0] if(self.subject[1]): self.subject = unicode(self.subject[0], self.subject[1]) else: self.subject = self.subject[0] def extract_dkim(self): ar = self.body.get_param("dkim", "missing", "Authentication-Results") if ar == "missing": domain = self.sender.split("@")[-1] if lib.user.GWDomain(domain).check() and domain == self.body.get_param("d", "missing", "DKIM-Signature"): ar = "pass" # we trust MTA to reject fakes from domains that hare handled locally if ar[0:4] == "pass": self.dkim = True def parse_body(self) cipher = None signature = None if self.multipart: for part in self.body.walk(): if part.get_content_type() == 'message/delivery-status': part_str = part.get_payload(decode = 0) for subpart in part_str: if subpart.get("Action", "") in ("relayed", "delivered", "expanded") and self.body.get_param("report-type", "") == "delivery-status" and self.body.get("Auto-Submitted", "") == "auto-replied": self.dsn = True elif part.get_content_type() == 'text/plain' and (self.subtype != "alternative" or self.out == None): # lower precedence if other content exists self.handle_text(part) elif part.get_content_type() == 'message/rfc822': self.handle_text(part) elif part.get_content_type() == 'text/html': self.handle_html(part) elif part.has_key("Content-Disposition") and part.__getitem__("Content-Disposition")[:11] == "attachment;": if has setting handle_attachment() elif self.subtype == "mixed": elif self.subtype == "digest": elif self.subtype == "alternative": elif self.subtype == "related": elif self.subtype == "signed": elif self.subtype == "encrypted": elif self.maintype == "message" and self.subtype == "rfc822": self.handle_text(self.body) elif self.maintype == "text" and self.subtype == "plain": self.handle_text(self.body) elif self.maintype == "text" and self.subtype == "html": self.handle_html(part) return True def handle_text(self, msg): text = msg.get_payload(decode = True) if (self.has_pgp(text)): self.out += self.handle_pgp(msg) else: self.out += text def handle_html(self, msg): text = msg.get_payload(decode = True) if (self.has_pgp(text)): text = self.handle_pgp(text) h = html2text.HTML2Text() h.inline_links = False if not msg.get_content_charset(): charset = chardet.detect(text) if charset['encoding'] == None: charset = 'ascii' else: charset = charset['encoding'] text = h.handle(text).decode(charset)) self.out += text
def handle_email(k): global address_list userdata = None ## read email from file msg_raw = read_email(k) if not msg_raw: logging.error('Could not open email file: ' + k) return ## extract header msg_headers = Parser().parsestr(msg_raw) ## check if email was valid if not msg_headers: logging.error('Malformed email detected and purged') delete_email(k) return ## find email source and dest addresses msg_sender = msg_headers["From"] ## failed delivery email if msg_sender == '<>' or not msg_sender: msg_sender = BMConfig().get("bmgateway", "bmgateway", "relay_address_label") else: try: msg_sender = re.findall(r'[\w\.+-]+@[\w\.-]+.[\w]+', msg_sender)[0] except: pass msg_sender = msg_sender.lower() msg_recipient = "" ## find email details if msg_headers["To"]: rcpts = re.findall(r'[\w\.+-]+@[\w\.-]+.[\w]+', msg_headers["To"]) if len(rcpts) > 0: msg_recipient = rcpts[0] ## strip extension (user+foo@domain) msg_recipient = re.sub(r'\+.*@', '@', msg_recipient) msg_recipient = msg_recipient.lower() userdata = lib.user.GWUser(email = msg_recipient, unalias = True) ## check if we have a recipient address for the receiving email if not userdata or not userdata.check(): ## look for X-Original-To instead rcpts = re.findall(r'[\w\.+-]+@[\w\.-]+.[\w]+', msg_headers["X-Original-To"]) if len(rcpts) > 0: msg_recipient = rcpts[0] msg_recipient = re.sub(r'\+.*@', '@', msg_recipient) msg_recipient = msg_recipient.lower() userdata = lib.user.GWUser(email = msg_recipient, unalias = True) ## no valid recipient #if not msg_recipient in addressbook: # logging.warn('Purged email destined for unknown user ' + msg_recipient + ' from ' + msg_sender) # logging.debug(msg_headers) # delete_email(k) # return ## check if we have valid sender and recipient details if not msg_sender or not msg_recipient: logging.warn('Malformed email detected and purged') delete_email(k) return ## set bitmessage destination address bm_to_address = userdata.bm ## set from address ## check to see if we need to generate a sending address for the source email address # if not msg_sender in address_list: # bm_from_address = generate_sender_address(msg_sender) # address_list[msg_sender] = bm_from_address # else: bm_from_address = BMAPI().get_address(BMConfig().get("bmgateway", "bmgateway", "relay_address_label")) ## find message subject msg_subject = decode_header(msg_headers['subject'])[0] if(msg_subject[1]): msg_subject = unicode(msg_subject[0], msg_subject[1]) else: msg_subject = lib.charset.safeDecode(msg_subject[0]) ## find message body contents in plaintext msg_tmp = email.message_from_string(msg_raw) # handle DSN if msg_tmp.get_content_type() == "multipart/report" and msg_tmp.get_param("report-type", "") == "delivery-status" and msg_tmp.get("Auto-Submitted", "") == "auto-replied": for part in msg_tmp.walk(): if part and part.get_content_type() == 'message/delivery-status': for subpart in part.get_payload(decode = 0): if subpart.get("Action", "") in ("relayed", "delivered", "expanded"): logging.info ("Successful DSN from " + bm_to_address) lib.user.GWUser(bm = bm_to_address).setlastrelay(lastrelay = time.time()) delete_email(k) return msg_body = u'' body_raw = '' decrypt_ok = False sigverify_ok = False mega_fileids = [] # DKIM ar = msg_tmp.get_param("dkim", "missing", "Authentication-Results") if ar == "missing": try: domain = msg_sender.split("@")[-1] if lib.user.GWDomain(domain).check() and domain == msg_tmp.get_param("d", "missing", "DKIM-Signature"): ar = "pass" # we trust MTA to reject fakes except: pass ## inline PGP for part in msg_tmp.walk(): if part and part.get_content_type() == 'text/plain' and not (part.has_key("Content-Disposition") and part.__getitem__("Content-Disposition")[:11] == "attachment;"): part_str = part.get_payload(decode=1) if userdata.pgp == 1: if userdata.flags & 1 == 1: pgpparts = part_str.split("-----") # hack for absent pgp if not pgpparts or len(pgpparts) < 4: msg_body += lib.charset.safeDecode(part_str, part.get_content_charset(None)) continue state = 0 pgp_body = "" for pgppart in pgpparts: if pgppart == "BEGIN PGP MESSAGE": pgp_body = "-----" + pgppart + "-----" state = 1 elif pgppart == "END PGP MESSAGE": pgp_body += "-----" + pgppart + "-----" # import from sql if necessary lib.gpg.check_key(msg_recipient) decrypted, sigverify_ok = lib.gpg.decrypt_content(pgp_body, msg_sender, msg_recipient) if isinstance(decrypted, basestring): part_str = decrypted decrypt_ok = True #else: #part_str = part.get_payload(decode = 0) sigresult = "fail" if sigverify_ok: sigresult = "ok" logging.info("Decrypted email from " + msg_sender + " to " + msg_recipient + ", signature: " + sigresult) state = 0 elif pgppart == "BEGIN PGP SIGNED MESSAGE": pgp_body += "-----" + pgppart + "-----" state = 2 elif pgppart == "BEGIN PGP SIGNATURE": pgp_body += "-----" + pgppart + "-----" state = 3 elif pgppart == "END PGP SIGNATURE": pgp_body += "-----" + pgppart + "-----" # import from sql if necessary lib.gpg.check_key(msg_recipient) plain, sigverify_ok = lib.gpg.verify(pgp_body, msg_sender, msg_recipient) if isinstance(plain, basestring): part_str = plain #else: #part_str = part.get_payload(decode = 0) sigresult = "fail" if sigverify_ok: sigresult = "ok" logging.info("Verifying PGP signature from " + msg_sender + " to " + msg_recipient + ": " + sigresult) state = 0 elif state == 0: msg_body += lib.charset.safeDecode(pgppart, part.get_content_charset(None)) elif state > 0: pgp_body += lib.charset.safeDecode(pgppart, part.get_content_charset(None)) else: if "BEGIN PGP MESSAGE" in part_str: # import from sql if necessary lib.gpg.check_key(msg_recipient) decrypted, sigverify_ok = lib.gpg.decrypt_content(part_str, msg_sender, msg_recipient) if isinstance(decrypted, basestring): part_str = decrypted decrypt_ok = True else: part_str = part.get_payload(decode = 0) logging.info("Decrypted email from " + msg_sender + " to " + msg_recipient) elif "BEGIN PGP SIGNED MESSAGE" in part_str: # import from sql if necessary lib.gpg.check_key(msg_recipient) plain, sigverify_ok = lib.gpg.verify(part_str, msg_sender, msg_recipient) if isinstance(plain, basestring): part_str = plain else: part_str = part.get_payload(decode = 0) # PGP END body_raw += part.as_string(False) #print part.get_content_charset() #print msg_tmp.get_charset() part_str = lib.charset.safeDecode(part_str, part.get_content_charset(None)) msg_body += part_str ## if there's no plaintext content, convert the html if not msg_body or userdata.html == 2: for part in msg_tmp.walk(): if part and part.get_content_type() == 'text/html' and not (part.has_key("Content-Disposition") and part.__getitem__("Content-Disposition")[:11] == "attachment;"): part_str = part.get_payload(decode=1) h = html2text.HTML2Text() h.inline_links = False if userdata.html == 1: msg_body += lib.charset.safeDecode(part_str, part.get_content_charset(None)) elif userdata.html == 2: msg_body = lib.charset.safeDecode(part_str, part.get_content_charset(None)) else: msg_body += h.handle(lib.charset.safeDecode(part_str, part.get_content_charset(None))) #msg_body = msg_body + html2text.html2text(unicode(part.get_payload(), part.get_content_charset())) ## if there's no plaintext or html, check if it's encrypted # PGP/MIME has_encrypted_parts = False if not msg_body: for part in msg_tmp.walk(): if part.get_content_type() == 'application/pgp-encrypted': has_encrypted_parts = True # import from sql if necessary if userdata.pgp == 1: lib.gpg.check_key(msg_recipient) ## look for encrypted attachment containing text if part.get_content_type() == 'application/octet-stream' and has_encrypted_parts: part_str = part.get_payload(decode=1) if userdata.pgp == 0: msg_body += part_str continue ## if we see the pgp header, decrypt if 'BEGIN PGP MESSAGE' in part_str: decrypted_data, sigverify_ok = lib.gpg.decrypt_content(part_str, msg_sender, msg_recipient, True) ## decrypt failed if not decrypted_data: logging.error("Decryption of email destined for " + msg_recipient + " failed") msg_body += part.get_payload(decode=0) continue logging.info("Decrypted email from " + msg_sender + " to " + msg_recipient) msg_body += decrypted_data decrypt_ok = True elif "BEGIN PGP SIGNED MESSAGE" in part_str: plain, sigverify_ok = lib.gpg.verify(part_str, msg_sender, msg_recipient) if isinstance(plain, basestring): msg_body += plain else: msg_body += part.get_payload(decode = 0) ## unknown attachment else: logging.debug("Received application/octet-stream type in inbound email, but did not see encryption header") if not sigverify_ok: for part in msg_tmp.walk(): if part.get_content_type() == 'application/pgp-signature': if userdata.pgp == 0: msg_body = '-----BEGIN PGP SIGNED MESSAGE-----\n' + msg_body msg_body += '\n-----BEGIN PGP SIGNATURE-----\n' msg_body += part.get_payload(decode=0) msg_body += '\n-----END PGP SIGNATURE-----\n' continue # import from sql if necessary lib.gpg.check_key(msg_recipient) plain, sigverify_ok = lib.gpg.verify(body_raw, msg_sender, msg_recipient, part.get_payload(decode=1)) if userdata.attachments == 1 and not userdata.expired(): for part in msg_tmp.walk(): if part.has_key("Content-Disposition") and part.__getitem__("Content-Disposition")[:11] == "attachment;": # fix encoding try: filename = email.header.decode_header(part.get_filename()) encoding = filename[0][1] filename = filename[0][0] except: filename = part.get_filename() encoding = False fileid, link = lib.bmmega.mega_upload(userdata.bm, filename, part.get_payload(decode = 1)) mega_fileids.append(fileid) if encoding: filename = unicode(filename, encoding) logging.info("Attachment \"%s\" (%s)", filename, part.get_content_type()) msg_body = "Attachment \"" + filename + "\" (" + part.get_content_type() + "): " + link + "\n" + msg_body if userdata.pgp == 1: if not decrypt_ok: msg_body = "WARNING: PGP encryption missing or invalid. The message content could be exposed to third parties.\n" + msg_body if not sigverify_ok: msg_body = "WARNING: PGP signature missing or invalid. The authenticity of the message could not be verified.\n" + msg_body else: # msg_body = "WARNING: Server-side PGP is off, passing message as it is.\n" + msg_body pass if not ar[0:4] == "pass": msg_body = "WARNING: DKIM signature missing or invalid. The email may not have been sent through legitimate servers.\n" + msg_body logging.info('Incoming email from %s to %s', msg_sender, msg_recipient) sent = SendBM(bm_from_address, bm_to_address, 'MAILCHUCK-FROM::' + msg_sender + ' | ' + msg_subject.encode('utf-8'), msg_body.encode('utf-8')) if sent.status: for fileid in mega_fileids: # cur.execute ("UPDATE mega SET ackdata = %s WHERE fileid = %s AND ackdata IS NULL", (ackdata.decode("hex"), fileid)) pass ## remove email file if userdata.archive == 1: #print msg_body save_email(k) else: delete_email(k)
def handle_email(k): global address_list userdata = None ## read email from file msg_raw = read_email(k) if not msg_raw: logging.error('Could not open email file: ' + k) return ## extract header msg_headers = Parser().parsestr(msg_raw) ## check if email was valid if not msg_headers: logging.error('Malformed email detected and purged') delete_email(k) return ## find email source and dest addresses msg_sender = msg_headers["From"] ## failed delivery email if msg_sender == '<>' or not msg_sender: msg_sender = BMConfig().get("bmgateway", "bmgateway", "relay_address_label") else: try: msg_sender = re.findall(r'[\w\.+-]+@[\w\.-]+.[\w]+', msg_sender)[0] except: pass msg_sender = msg_sender.lower() msg_recipient = "" ## find email details if msg_headers["To"]: rcpts = re.findall(r'[\w\.+-]+@[\w\.-]+.[\w]+', msg_headers["To"]) if len(rcpts) > 0: msg_recipient = rcpts[0] ## strip extension (user+foo@domain) msg_recipient = re.sub(r'\+.*@', '@', msg_recipient) msg_recipient = msg_recipient.lower() userdata = lib.user.GWUser(email = msg_recipient, unalias = True) ## check if we have a recipient address for the receiving email if not userdata.check(): ## look for X-Original-To instead rcpts = re.findall(r'[\w\.+-]+@[\w\.-]+.[\w]+', msg_headers["X-Original-To"]) if len(rcpts) > 0: msg_recipient = rcpts[0] msg_recipient = re.sub(r'\+.*@', '@', msg_recipient) msg_recipient = msg_recipient.lower() userdata = lib.user.GWUser(email = msg_recipient, unalias = True) ## no valid recipient #if not msg_recipient in addressbook: # logging.warn('Purged email destined for unknown user ' + msg_recipient + ' from ' + msg_sender) # logging.debug(msg_headers) # delete_email(k) # return ## check if we have valid sender and recipient details if not msg_sender or not msg_recipient: logging.warn('Malformed email detected and purged') delete_email(k) return ## set bitmessage destination address bm_to_address = userdata.bm ## set from address ## check to see if we need to generate a sending address for the source email address # if not msg_sender in address_list: # bm_from_address = generate_sender_address(msg_sender) # address_list[msg_sender] = bm_from_address # else: bm_from_address = BMAPI().get_address(BMConfig().get("bmgateway", "bmgateway", "relay_address_label")) ## find message subject msg_subject = decode_header(msg_headers['subject'])[0] if(msg_subject[1]): msg_subject = unicode(msg_subject[0], msg_subject[1]) else: msg_subject = msg_subject[0] ## find message body contents in plaintext msg_tmp = email.message_from_string(msg_raw) # handle DSN if msg_tmp.get_content_type() == "multipart/report" and msg_tmp.get_param("report-type", "") == "delivery-status" and msg_tmp.get("Auto-Submitted", "") == "auto-replied": for part in msg_tmp.walk(): if part and part.get_content_type() == 'message/delivery-status': part_str = part.get_payload(decode = 0) for subpart in part_str: if subpart.get("Action", "") in ("relayed", "delivered", "expanded"): logging.info ("Successful DSN from " + bm_to_address) lib.user.GWUser(bm = bm_to_address).setlastrelay(lastrelay = time.time()) delete_email(k) return msg_body = '' body_raw = '' decrypt_ok = False sigverify_ok = False # DKIM ar = msg_tmp.get_param("dkim", "missing", "Authentication-Results") if ar == "missing": try: domain = msg_sender.split("@")[-1] if lib.user.GWDomain(domain).check() and domain == msg_tmp.get_param("d", "missing", "DKIM-Signature"): ar = "pass" # we trust MTA to reject fakes except: pass ## inline PGP for part in msg_tmp.walk(): if part and part.get_content_type() == 'text/plain' and not (part.has_key("Content-Disposition") and part.__getitem__("Content-Disposition")[:11] == "attachment;"): part_str = part.get_payload(decode=1) if userdata.flags & 1 == 1: pgpparts = part_str.split("-----") state = 0 pgp_body = "" for pgppart in pgpparts: if pgppart == "BEGIN PGP MESSAGE": pgp_body = "-----" + pgppart + "-----" state = 1 elif pgppart == "END PGP MESSAGE": pgp_body += "-----" + pgppart + "-----" decrypted, sigverify_ok = lib.gpg.decrypt_content(pgp_body, msg_sender, msg_recipient) if isinstance(decrypted, basestring): part_str = decrypted decrypt_ok = True #else: #part_str = part.get_payload(decode = 0) sigresult = "fail" if sigverify_ok: sigresult = "ok" logging.info("Decrypted email from " + msg_sender + " to " + msg_recipient + ", signature: " + sigresult) state = 0 elif pgppart == "BEGIN PGP SIGNED MESSAGE": pgp_body += "-----" + pgppart + "-----" state = 2 elif pgppart == "BEGIN PGP SIGNATURE": pgp_body += "-----" + pgppart + "-----" state = 3 elif pgppart == "END PGP SIGNATURE": pgp_body += "-----" + pgppart + "-----" plain, sigverify_ok = lib.gpg.verify(pgp_body, msg_sender, msg_recipient) if isinstance(plain, basestring): part_str = plain #else: #part_str = part.get_payload(decode = 0) sigresult = "fail" if sigverify_ok: sigresult = "ok" logging.info("Verifying PGP signature from " + msg_sender + " to " + msg_recipient + ": " + sigresult) state = 0 elif state == 0: if part.get_content_charset(): msg_body += pgppart.decode(part.get_content_charset()) else: charset = chardet.detect(pgppart) if charset['encoding']: msg_body += pgppart.decode(charset['encoding']) else: msg_body += pgppart.decode('ascii') elif state > 0: pgp_body += pgppart else: if "BEGIN PGP MESSAGE" in part_str: decrypted, sigverify_ok = lib.gpg.decrypt_content(part_str, msg_sender, msg_recipient) if isinstance(decrypted, basestring): part_str = decrypted decrypt_ok = True else: part_str = part.get_payload(decode = 0) logging.info("Decrypted email from " + msg_sender + " to " + msg_recipient) elif "BEGIN PGP SIGNED MESSAGE" in part_str: plain, sigverify_ok = lib.gpg.verify(part_str, msg_sender, msg_recipient) if isinstance(plain, basestring): part_str = plain else: part_str = part.get_payload(decode = 0) body_raw += part.as_string(False) #print part.get_content_charset() #print msg_tmp.get_charset() if part.get_content_charset(): try: part_str = part_str.decode(part.get_content_charset()) except: charset = chardet.detect(part_str) part_str = part_str.decode(charset['encoding']) msg_body += part_str ## if there's no plaintext content, convert the html if not msg_body: for part in msg_tmp.walk(): if part and part.get_content_type() == 'text/html' and not (part.has_key("Content-Disposition") and part.__getitem__("Content-Disposition")[:11] == "attachment;"): part_str = part.get_payload(decode=1) h = html2text.HTML2Text() h.inline_links = False if part.get_content_charset(): msg_body += h.handle(part_str.decode(part.get_content_charset())) else: charset = chardet.detect(part_str) msg_body += h.handle(part_str.decode(charset['encoding'])) #msg_body = msg_body + html2text.html2text(unicode(part.get_payload(), part.get_content_charset())) ## if there's no plaintext or html, check if it's encrypted # PGP/MIME has_encrypted_parts = False if not msg_body: for part in msg_tmp.walk(): if part.get_content_type() == 'application/pgp-encrypted': has_encrypted_parts = True ## look for encrypted attachment containing text if part.get_content_type() == 'application/octet-stream' and has_encrypted_parts: part_str = part.get_payload(decode=1) ## if we see the pgp header, decrypt if 'BEGIN PGP MESSAGE' in part_str: decrypted_data, sigverify_ok = lib.gpg.decrypt_content(part_str, msg_sender, msg_recipient, True) ## decrypt failed if not decrypted_data: logging.error("Decryption of email destined for " + msg_recipient + " failed") msg_body += part.get_payload(decode=0) continue logging.info("Decrypted email from " + msg_sender + " to " + msg_recipient) msg_body += decrypted_data decrypt_ok = True elif "BEGIN PGP SIGNED MESSAGE" in part_str: plain, sigverify_ok = lib.gpg.verify(part_str, msg_sender, msg_recipient) if isinstance(plain, basestring): msg_body += plain else: msg_body += part.get_payload(decode = 0) ## unknown attachment else: logging.debug("Received application/octet-stream type in inbound email, but did not see encryption header") if not sigverify_ok: for part in msg_tmp.walk(): if part.get_content_type() == 'application/pgp-signature': plain, sigverify_ok = lib.gpg.verify(body_raw, msg_sender, msg_recipient, part.get_payload(decode=1)) if userdata.attachments == 1 and not userdata.expired(): for part in msg_tmp.walk(): if part.has_key("Content-Disposition") and part.__getitem__("Content-Disposition")[:11] == "attachment;": # fix encoding try: filename = email.header.decode_header(part.get_filename()) encoding = filename[0][1] filename = filename[0][0] except: filename = part.get_filename() encoding = False file_id, link = lib.bmmega.mega_upload(userdata.bm, filename, part.get_payload(decode = 1)) if encoding: filename = unicode(filename, encoding) logging.info("Attachment \"%s\" (%s)", filename, part.get_content_type()) msg_body = "Attachment \"" + filename + "\" (" + part.get_content_type() + "): " + link + "\n" + msg_body if not decrypt_ok: msg_body = "WARNING: PGP encryption missing or invalid. The message content could be exposed to third parties.\n" + msg_body if not sigverify_ok: msg_body = "WARNING: PGP signature missing or invalid. The authenticity of the message could not be verified.\n" + msg_body if not ar[0:4] == "pass": msg_body = "WARNING: DKIM signature missing or invalid. The email may not have been sent through legitimate servers.\n" + msg_body logging.info('Incoming email from %s to %s', msg_sender, msg_recipient) if SendBM(bm_from_address, bm_to_address, 'MAILCHUCK-FROM::' + msg_sender + ' | ' + msg_subject.encode('utf-8'), msg_body.encode('utf-8')).status: ## remove email file if userdata.archive == 1: #print msg_body save_email(k) else: delete_email(k)