def handle(self, *args, **options): # type: (*Any, **str) -> None if six.PY3: print(py3_warning) return rcpt_to = os.environ.get("ORIGINAL_RECIPIENT", options['recipient']) if rcpt_to is not None: if is_missed_message_address(rcpt_to): try: mark_missed_message_address_as_used(rcpt_to) except ZulipEmailForwardError: print( "5.1.1 Bad destination mailbox address: Bad or expired missed message address." ) exit( posix.EX_NOUSER ) # type: ignore # There are no stubs for posix in python 3 else: try: extract_and_validate(rcpt_to) except ZulipEmailForwardError: print( "5.1.1 Bad destination mailbox address: Please use the address specified " "in your Streams page.") exit( posix.EX_NOUSER ) # type: ignore # There are no stubs for posix in python 3 # Read in the message, at most 25MiB. This is the limit enforced by # Gmail, which we use here as a decent metric. message = sys.stdin.read(25 * 1024 * 1024) if len(sys.stdin.read(1)) != 0: # We're not at EOF, reject large mail. print("5.3.4 Message too big for system: Max size is 25MiB") exit( posix.EX_DATAERR ) # type: ignore # There are no stubs for posix in python 3 queue_json_publish("email_mirror", { "message": message, "rcpt_to": rcpt_to }, lambda x: None) else: # We're probably running from cron, try to batch-process mail if (not settings.EMAIL_GATEWAY_BOT or not settings.EMAIL_GATEWAY_LOGIN or not settings.EMAIL_GATEWAY_PASSWORD or not settings.EMAIL_GATEWAY_IMAP_SERVER or not settings.EMAIL_GATEWAY_IMAP_PORT or not settings.EMAIL_GATEWAY_IMAP_FOLDER): print( "Please configure the Email Mirror Gateway in /etc/zulip/, " "or specify $ORIGINAL_RECIPIENT if piping a single mail.") exit(1) reactor.callLater(0, main) reactor.run()
def test_get_missed_message_token(self) -> None: with self.settings(EMAIL_GATEWAY_PATTERN="*****@*****.**"): address = 'mm' + ('x' * 32) + '@example.com' self.assertTrue(is_missed_message_address(address)) token = get_missed_message_token_from_address(address) self.assertEqual(token, 'x' * 32) # This next section was a bug at one point--we'd treat ordinary # user addresses that happened to begin with "mm" as being # the special mm+32chars tokens. address = '*****@*****.**' self.assertFalse(is_missed_message_address(address)) with self.assertRaises(ZulipEmailForwardError): get_missed_message_token_from_address(address) # Now test the case where we our address does not match the # EMAIL_GATEWAY_PATTERN. # This used to crash in an ugly way; we want to throw a proper # exception. address = '*****@*****.**' self.assertFalse(is_missed_message_address(address)) with self.assertRaises(ZulipEmailForwardError): get_missed_message_token_from_address(address)
def handle(self, *args, **options): # type: (*Any, **str) -> None if six.PY3: print(py3_warning) return rcpt_to = os.environ.get("ORIGINAL_RECIPIENT", options['recipient']) if rcpt_to is not None: if is_missed_message_address(rcpt_to): try: mark_missed_message_address_as_used(rcpt_to) except ZulipEmailForwardError: print("5.1.1 Bad destination mailbox address: Bad or expired missed message address.") exit(posix.EX_NOUSER) # type: ignore # There are no stubs for posix in python 3 else: try: extract_and_validate(rcpt_to) except ZulipEmailForwardError: print("5.1.1 Bad destination mailbox address: Please use the address specified " "in your Streams page.") exit(posix.EX_NOUSER) # type: ignore # There are no stubs for posix in python 3 # Read in the message, at most 25MiB. This is the limit enforced by # Gmail, which we use here as a decent metric. message = sys.stdin.read(25*1024*1024) if len(sys.stdin.read(1)) != 0: # We're not at EOF, reject large mail. print("5.3.4 Message too big for system: Max size is 25MiB") exit(posix.EX_DATAERR) # type: ignore # There are no stubs for posix in python 3 queue_json_publish( "email_mirror", { "message": message, "rcpt_to": rcpt_to }, lambda x: None ) else: # We're probably running from cron, try to batch-process mail if (not settings.EMAIL_GATEWAY_BOT or not settings.EMAIL_GATEWAY_LOGIN or not settings.EMAIL_GATEWAY_PASSWORD or not settings.EMAIL_GATEWAY_IMAP_SERVER or not settings.EMAIL_GATEWAY_IMAP_PORT or not settings.EMAIL_GATEWAY_IMAP_FOLDER): print("Please configure the Email Mirror Gateway in /etc/zulip/, " "or specify $ORIGINAL_RECIPIENT if piping a single mail.") exit(1) reactor.callLater(0, main) reactor.run()
def consume(self, event: Mapping[str, Any]) -> None: rcpt_to = event['rcpt_to'] if not is_missed_message_address(rcpt_to): # Missed message addresses are one-time use, so we don't need # to worry about emails to them resulting in message spam. recipient_realm = decode_stream_email_address(rcpt_to)[0].realm try: rate_limit_mirror_by_realm(recipient_realm) except RateLimited: msg = email.message_from_string(event["message"]) logger.warning("MirrorWorker: Rejecting an email from: %s " "to realm: %s - rate limited." % (msg['From'], recipient_realm.name)) return mirror_email(email.message_from_string(event["message"]), rcpt_to=rcpt_to)
def consume(self, event: Mapping[str, Any]) -> None: rcpt_to = event['rcpt_to'] msg = email.message_from_bytes( base64.b64decode(event["msg_base64"]), policy=email.policy.default, ) assert isinstance(msg, EmailMessage) # https://github.com/python/typeshed/issues/2417 if not is_missed_message_address(rcpt_to): # Missed message addresses are one-time use, so we don't need # to worry about emails to them resulting in message spam. recipient_realm = decode_stream_email_address(rcpt_to)[0].realm try: rate_limit_mirror_by_realm(recipient_realm) except RateLimited: logger.warning("MirrorWorker: Rejecting an email from: %s " "to realm: %s - rate limited.", msg['From'], recipient_realm.name) return mirror_email(msg, rcpt_to=rcpt_to)