def handle_one_mail(log, mail, file_alias, file_alias_url, signature_timestamp_checker): """Process one message. Returns None when the message has either been successfully processed, or handled as a known error condition, in which case a reply will have been sent if appropriate. """ log.debug('processing mail from %r message-id %r' % (mail['from'], mail['message-id'])) # If the Return-Path header is '<>', it probably means # that it's a bounce from a message we sent. if mail['Return-Path'] == '<>': log.info("Message had an empty Return-Path.") return if mail.get_content_type() == 'multipart/report': # Mails with a content type of multipart/report are # generally DSN messages and should be ignored. log.info("Got a multipart/report message.") return if 'precedence' in mail: log.info("Got a message with a precedence header.") return if mail.raw_length > MAX_EMAIL_SIZE: complaint = ( "The mail you sent to Launchpad is too long.\n\n" "Your message <%s>\nwas %d MB and the limit is %d MB." % (mail['message-id'], mail.raw_length / 1e6, MAX_EMAIL_SIZE / 1e6)) log.info(complaint) # It's probably big and it's probably mostly binary, so trim it pretty # aggressively. send_process_error_notification(mail['From'], 'Mail to Launchpad was too large', complaint, mail, max_return_size=8192) return try: principal = authenticateEmail(mail, signature_timestamp_checker) except (InvalidSignature, IncomingEmailError) as error: send_process_error_notification(mail['From'], 'Submit Request Failure', str(error), mail) return except InactiveAccount: log.info("Inactive account found for %s" % mail['From']) return addresses = extract_addresses(mail, file_alias_url, log) log.debug('mail was originally to: %r' % (addresses, )) try: do_paranoid_envelope_to_validation(addresses) except AssertionError as e: log.info("Invalid email address: %s" % e) return handler = None for email_addr in addresses: user, domain = email_addr.split('@') handler = mail_handlers.get(domain) if handler is not None: break else: raise AssertionError("No handler registered for '%s' " % (', '.join(addresses))) if principal is None and not handler.allow_unknown_users: log.info('Mail from unknown users not permitted for this handler') return handled = handler.process(mail, email_addr, file_alias) if not handled: raise AssertionError("Handler found, but message was not handled")
def test_get(self): handler = mail_handlers.get(config.launchpad.code_domain) self.assertIsInstance(handler, CodeHandler)
def handle_one_mail(log, mail, file_alias, file_alias_url, signature_timestamp_checker): """Process one message. Returns None when the message has either been successfully processed, or handled as a known error condition, in which case a reply will have been sent if appropriate. """ log.debug('processing mail from %r message-id %r' % (mail['from'], mail['message-id'])) # If the Return-Path header is '<>', it probably means # that it's a bounce from a message we sent. if mail['Return-Path'] == '<>': log.info("Message had an empty Return-Path.") return if mail.get_content_type() == 'multipart/report': # Mails with a content type of multipart/report are # generally DSN messages and should be ignored. log.info("Got a multipart/report message.") return if 'precedence' in mail: log.info("Got a message with a precedence header.") return if mail.raw_length > MAX_EMAIL_SIZE: complaint = ( "The mail you sent to Launchpad is too long.\n\n" "Your message <%s>\nwas %d MB and the limit is %d MB." % (mail['message-id'], mail.raw_length / 1e6, MAX_EMAIL_SIZE / 1e6)) log.info(complaint) # It's probably big and it's probably mostly binary, so trim it pretty # aggressively. send_process_error_notification( mail['From'], 'Mail to Launchpad was too large', complaint, mail, max_return_size=8192) return try: principal = authenticateEmail(mail, signature_timestamp_checker) except (InvalidSignature, IncomingEmailError) as error: send_process_error_notification( mail['From'], 'Submit Request Failure', str(error), mail) return except InactiveAccount: log.info("Inactive account found for %s" % mail['From']) return addresses = extract_addresses(mail, file_alias_url, log) log.debug('mail was originally to: %r' % (addresses,)) try: do_paranoid_envelope_to_validation(addresses) except AssertionError as e: log.info("Invalid email address: %s" % e) return handler = None for email_addr in addresses: user, domain = email_addr.split('@') handler = mail_handlers.get(domain) if handler is not None: break else: raise AssertionError( "No handler registered for '%s' " % (', '.join(addresses))) if principal is None and not handler.allow_unknown_users: log.info('Mail from unknown users not permitted for this handler') return handled = handler.process(mail, email_addr, file_alias) if not handled: raise AssertionError("Handler found, but message was not handled")