def instanciate_answer(self, lines): answer = self.answer_class() msgtxt = ''.join(lines) msg = email.message_from_string(msgtxt) temporary, permanent = all_failures(msg) if permanent: answer.is_bounced = True answer.email_from = scan_message(msg).pop() elif temporary: raise TemporaryFailure else: answer.email_from = msg["From"] the_recipient = msg["To"] answer.subject = msg["Subject"] answer.when = msg["Date"] answer.message_id = msg["Message-ID"] the_recipient = re.sub(r"\n", "", the_recipient) regex = re.compile(r".*[\+\-](.*)@.*") the_match = regex.match(the_recipient) if the_match is None: raise CouldNotFindIdentifier answer.email_to = the_recipient answer.outbound_message_identifier = the_match.groups()[0] logging.info("Reading the parts") for part in msg.walk(): logging.info("Part of type " + part.get_content_type()) content_type_attr = self.content_types_attrs.get( part.get_content_type()) if content_type_attr: charset = part.get_content_charset() or "ISO-8859-1" data = part.get_payload(decode=True).decode(charset) setattr( answer, content_type_attr, EmailReplyParser.parse_reply(data).strip(), ) else: self.handle_not_processed_part(part) attachment = self.parse_attachment(part) if attachment: answer.add_attachment(attachment) log = 'New incoming email from %(from)s sent on %(date)s with subject %(subject)s and content %(content)s' log = log % { 'from': answer.email_from, 'date': answer.when, 'subject': answer.subject, 'content': answer.content_text, } logging.info(log) return answer
def instanciate_answer(self, lines): answer = self.answer_class() msgtxt = ''.join(lines) msg = email.message_from_string(msgtxt) temporary, permanent = all_failures(msg) if permanent: answer.is_bounced = True answer.email_from = scan_message(msg).pop() elif temporary: raise TemporaryFailure else: answer.email_from = msg["From"] the_recipient = msg["To"] answer.subject = msg["Subject"] answer.when = msg["Date"] answer.message_id = msg["Message-ID"] the_recipient = re.sub(r"\n", "", the_recipient) regex = re.compile(r".*[\+\-](.*)@.*") the_match = regex.match(the_recipient) if the_match is None: raise CouldNotFindIdentifier answer.email_to = the_recipient answer.outbound_message_identifier = the_match.groups()[0] logging.info("Reading the parts") for part in msg.walk(): logging.info("Part of type " + part.get_content_type()) content_type_attr = self.content_types_attrs.get(part.get_content_type()) if content_type_attr: charset = part.get_content_charset() or "ISO-8859-1" data = part.get_payload(decode=True).decode(charset) setattr( answer, content_type_attr, EmailReplyParser.parse_reply(data).strip(), ) else: self.handle_not_processed_part(part) attachment = self.parse_attachment(part) if attachment: answer.add_attachment(attachment) log = 'New incoming email from %(from)s sent on %(date)s with subject %(subject)s and content %(content)s' log = log % { 'from': answer.email_from, 'date': answer.when, 'subject': answer.subject, 'content': answer.content_text, } logging.info(log) return answer
def __call__(self, msg): # This probe only from flufl.bounce import scan_message failed_addresses = scan_message(msg) if failed_addresses: message_id = msg['Message-Id'] logger.warn('Possible bounce: %s', message_id, extra=dict(message_details=msg.items(), failed_addresses=failed_addresses))
def parseForReturns(self, damail = 0, emailid = 0 ): if (damail == 0): damail, emailid = self.next() fails = scan_message(damail) if len(fails) != 0: mail.store(emailid, '+FLAGS', '\\Deleted') for fail_s in fails: r = session.query(PhoneCarrier).filter_by(email=fail_s).all() if len(r) == 0: continue r = r[0] session.delete(r) return fails
def _dispose(self, mlist, msg, msgdata): # List isn't doing bounce processing? if not mlist.process_bounces: return False # Try VERP detection first, since it's quick and easy context = BounceContext.normal addresses = StandardVERP().get_verp(mlist, msg) if len(addresses) > 0: # Scan the message to see if it contained permanent or temporary # failures. We'll ignore temporary failures, but even if there # are no permanent failures, we'll assume VERP bounces are # permanent. temporary, permanent = all_failures(msg) if len(temporary) > 0: # This was a temporary failure, so just ignore it. return False else: # See if this was a probe message. addresses = ProbeVERP().get_verp(mlist, msg) if len(addresses) > 0: context = BounceContext.probe else: # That didn't give us anything useful, so try the old fashion # bounce matching modules. This returns only the permanently # failing addresses. Since Mailman currently doesn't score # temporary failures, if we get no permanent failures, we're # done.s addresses = scan_message(msg) # If that still didn't return us any useful addresses, then send it on # or discard it. The addresses will come back from flufl.bounce as # bytes/8-bit strings, but we must store them as unicodes in the # database. Assume utf-8 encoding, but be cautious. if len(addresses) > 0: for address in addresses: if isinstance(address, bytes): try: address = address.decode('utf-8') except UnicodeError: log.exception('Ignoring non-UTF-8 encoded ' 'address: {0}'.format(address)) continue self._processor.register(mlist, address, msg, context) else: log.info('Bounce message w/no discernable addresses: %s', msg.get('message-id', 'n/a')) maybe_forward(mlist, msg) # Dequeue this message. return False
def _dispose(self, mlist, msg, msgdata): # List isn't doing bounce processing? if not mlist.process_bounces: return False # Try VERP detection first, since it's quick and easy context = BounceContext.normal addresses = StandardVERP().get_verp(mlist, msg) if len(addresses) > 0: # Scan the message to see if it contained permanent or temporary # failures. We'll ignore temporary failures, but even if there # are no permanent failures, we'll assume VERP bounces are # permanent. temporary, permanent = all_failures(msg) if len(temporary) > 0: # This was a temporary failure, so just ignore it. return False else: # See if this was a probe message. addresses = ProbeVERP().get_verp(mlist, msg) if len(addresses) > 0: context = BounceContext.probe else: # That didn't give us anything useful, so try the old fashion # bounce matching modules. This returns only the permanently # failing addresses. Since Mailman currently doesn't score # temporary failures, if we get no permanent failures, we're # done.s addresses = scan_message(msg) # If that still didn't return us any useful addresses, then send it on # or discard it. The addresses will come back from flufl.bounce as # bytes/8-bit strings, but we must store them as unicodes in the # database. Assume utf-8 encoding, but be cautious. if len(addresses) > 0: for address in addresses: if isinstance(address, bytes): try: address = address.decode('utf-8') except UnicodeError: log.exception('Ignoring non-UTF-8 encoded ' 'address: {}'.format(address)) continue self._processor.register(mlist, address, msg, context) else: log.info('Bounce message w/no discernable addresses: %s', msg.get('message-id', 'n/a')) maybe_forward(mlist, msg) # Dequeue this message. return False
def handle(self, lines): answer = self.answer_class() msgtxt = ''.join(lines) msg = email.message_from_string(msgtxt) temporary, permanent = all_failures(msg) if temporary or permanent: answer.is_bounced = True answer.email_from = scan_message(msg).pop() else: answer.email_from = msg["From"] the_recipient = msg["To"] answer.subject = msg["Subject"] answer.when = msg["Date"] the_recipient = re.sub(r"\n", "", the_recipient) regex = re.compile(r".*[\+\-](.*)@.*") answer.outbound_message_identifier = regex.match(the_recipient).groups()[0] charset = msg.get_charset() logging.info("Reading the parts") for part in msg.walk(): logging.info("Part of type "+part.get_content_type()) if part.get_content_type() == 'text/plain': charset = part.get_content_charset() if not charset: charset = "ISO-8859-1" data = part.get_payload(decode=True).decode(charset) text = EmailReplyParser.parse_reply(data) text.strip() answer.content_text = text #logging stuff log = 'New incoming email from %(from)s sent on %(date)s with subject %(subject)s and content %(content)s' log = log % { 'from':answer.email_from, 'date':answer.when, 'subject':answer.subject, 'content':answer.content_text } logging.info(log) return answer