mirror of https://github.com/zulip/zulip.git
email_mirror: Add email address parsing.
When trying to find the email gateway address, use the `email.util.getaddresses` function to deal with cases where multiple recipients are included in the email header or the stream address appears as an angle-addr with a name given (e.g. if someone added it to their address book). Added some other headers where the required address may appear: "Resent" headers are sometimes used for forwarding, and streams may also be found in CC. There is no way to find the address if the email was recieved as a BCC.
This commit is contained in:
parent
e3c8e8a839
commit
f2e06128c6
|
@ -4,6 +4,7 @@ import logging
|
|||
import re
|
||||
|
||||
from email.header import decode_header, Header
|
||||
from email.utils import getaddresses
|
||||
import email.message as message
|
||||
|
||||
from django.conf import settings
|
||||
|
@ -287,19 +288,19 @@ def find_emailgateway_recipient(message: message.Message) -> str:
|
|||
# We can't use Delivered-To; if there is a X-Gm-Original-To
|
||||
# it is more accurate, so try to find the most-accurate
|
||||
# recipient list in descending priority order
|
||||
recipient_headers = ["X-Gm-Original-To", "Delivered-To", "To"]
|
||||
recipients = [] # type: List[Union[str, Header]]
|
||||
for recipient_header in recipient_headers:
|
||||
r = message.get_all(recipient_header, None)
|
||||
if r:
|
||||
recipients = r
|
||||
break
|
||||
recipient_headers = ["X-Gm-Original-To", "Delivered-To",
|
||||
"Resent-To", "Resent-CC", "To", "CC"]
|
||||
|
||||
pattern_parts = [re.escape(part) for part in settings.EMAIL_GATEWAY_PATTERN.split('%s')]
|
||||
match_email_re = re.compile(".*?".join(pattern_parts))
|
||||
for recipient_email in [str(recipient) for recipient in recipients]:
|
||||
if match_email_re.match(recipient_email):
|
||||
return recipient_email
|
||||
|
||||
header_addresses = [str(addr)
|
||||
for recipient_header in recipient_headers
|
||||
for addr in message.get_all(recipient_header, [])]
|
||||
|
||||
for addr_tuple in getaddresses(header_addresses):
|
||||
if match_email_re.match(addr_tuple[1]):
|
||||
return addr_tuple[1]
|
||||
|
||||
raise ZulipEmailForwardError("Missing recipient in mirror email")
|
||||
|
||||
|
|
|
@ -185,6 +185,33 @@ class TestStreamEmailMessagesSuccess(ZulipTestCase):
|
|||
self.assertEqual(get_display_recipient(message.recipient), stream.name)
|
||||
self.assertEqual(message.topic_name(), incoming_valid_message['Subject'])
|
||||
|
||||
def test_receive_stream_email_multiple_recipient_success(self) -> None:
|
||||
user_profile = self.example_user('hamlet')
|
||||
self.login(user_profile.email)
|
||||
self.subscribe(user_profile, "Denmark")
|
||||
stream = get_stream("Denmark", user_profile.realm)
|
||||
|
||||
# stream address is angle-addr within multiple addresses
|
||||
stream_to_addresses = ["A.N. Other <another@example.org>",
|
||||
"Denmark <{}>".format(encode_email_address(stream))]
|
||||
|
||||
incoming_valid_message = MIMEText('TestStreamEmailMessages Body') # type: Any # https://github.com/python/typeshed/issues/275
|
||||
|
||||
incoming_valid_message['Subject'] = 'TestStreamEmailMessages Subject'
|
||||
incoming_valid_message['From'] = self.example_email('hamlet')
|
||||
incoming_valid_message['To'] = ", ".join(stream_to_addresses)
|
||||
incoming_valid_message['Reply-to'] = self.example_email('othello')
|
||||
|
||||
process_message(incoming_valid_message)
|
||||
|
||||
# Hamlet is subscribed to this stream so should see the email message from Othello.
|
||||
message = most_recent_message(user_profile)
|
||||
|
||||
self.assertEqual(message.content, "TestStreamEmailMessages Body")
|
||||
self.assertEqual(get_display_recipient(message.recipient), stream.name)
|
||||
self.assertEqual(message.topic_name(), incoming_valid_message['Subject'])
|
||||
|
||||
|
||||
class TestStreamEmailMessagesEmptyBody(ZulipTestCase):
|
||||
def test_receive_stream_email_messages_empty_body(self) -> None:
|
||||
|
||||
|
|
Loading…
Reference in New Issue