mirror of https://github.com/zulip/zulip.git
email_mirror: Add the sender at the start of stream message.
Fixes part 3 of #10612. When sending an email to the email mirror to a stream address, if "+show-sender" is added in the address, the stream message will now include "From: <sender>" at the top.
This commit is contained in:
parent
60c7467464
commit
dbff533e09
|
@ -4465,20 +4465,28 @@ def get_email_gateway_message_string_from_address(address: str) -> Optional[str]
|
|||
|
||||
return msg_string
|
||||
|
||||
def decode_email_address(email: str) -> Optional[Tuple[str, str]]:
|
||||
# Perform the reverse of encode_email_address. Returns a tuple of (streamname, email_token)
|
||||
def decode_email_address(email: str) -> Optional[Tuple[str, str, bool]]:
|
||||
# Perform the reverse of encode_email_address. Returns a tuple of
|
||||
# (streamname, email_token, show_sender)
|
||||
msg_string = get_email_gateway_message_string_from_address(email)
|
||||
|
||||
if msg_string is None:
|
||||
return None
|
||||
elif '.' in msg_string:
|
||||
|
||||
if msg_string.endswith(('+show-sender', '.show-sender')):
|
||||
show_sender = True
|
||||
msg_string = msg_string[:-12] # strip "+show-sender"
|
||||
else:
|
||||
show_sender = False
|
||||
|
||||
if '.' in msg_string:
|
||||
# Workaround for Google Groups and other programs that don't accept emails
|
||||
# that have + signs in them (see Trac #2102)
|
||||
encoded_stream_name, token = msg_string.split('.')
|
||||
else:
|
||||
encoded_stream_name, token = msg_string.split('+')
|
||||
|
||||
stream_name = re.sub(r"%\d{4}", lambda x: chr(int(x.group(0)[1:])), encoded_stream_name)
|
||||
return stream_name, token
|
||||
return stream_name, token, show_sender
|
||||
|
||||
SubHelperT = Tuple[List[Dict[str, Any]], List[Dict[str, Any]], List[Dict[str, Any]]]
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Any, Dict, Optional
|
||||
from typing import Any, Dict, Optional, Tuple
|
||||
|
||||
import logging
|
||||
import re
|
||||
|
@ -133,7 +133,8 @@ def mark_missed_message_address_as_used(address: str) -> None:
|
|||
redis_client.delete(key)
|
||||
raise ZulipEmailForwardError('Missed message address has already been used')
|
||||
|
||||
def construct_zulip_body(message: message.Message, realm: Realm) -> str:
|
||||
def construct_zulip_body(message: message.Message, realm: Realm,
|
||||
show_sender: bool=False) -> str:
|
||||
body = extract_body(message)
|
||||
# Remove null characters, since Zulip will reject
|
||||
body = body.replace("\x00", "")
|
||||
|
@ -142,6 +143,11 @@ def construct_zulip_body(message: message.Message, realm: Realm) -> str:
|
|||
body = body.strip()
|
||||
if not body:
|
||||
body = '(No email body)'
|
||||
|
||||
if show_sender:
|
||||
sender = message.get("From")
|
||||
body = "From: %s\n%s" % (sender, body)
|
||||
|
||||
return body
|
||||
|
||||
def send_to_missed_message_address(address: str, message: message.Message) -> None:
|
||||
|
@ -282,16 +288,16 @@ def extract_and_upload_attachments(message: message.Message, realm: Realm) -> st
|
|||
|
||||
return "\n".join(attachment_links)
|
||||
|
||||
def extract_and_validate(email: str) -> Stream:
|
||||
def extract_and_validate(email: str) -> Tuple[Stream, bool]:
|
||||
temp = decode_email_address(email)
|
||||
if temp is None:
|
||||
raise ZulipEmailForwardError("Malformed email recipient " + email)
|
||||
stream_name, token = temp
|
||||
stream_name, token, show_sender = temp
|
||||
|
||||
if not valid_stream(stream_name, token):
|
||||
raise ZulipEmailForwardError("Bad stream token from email recipient " + email)
|
||||
|
||||
return Stream.objects.get(email_token=token)
|
||||
return Stream.objects.get(email_token=token), show_sender
|
||||
|
||||
def find_emailgateway_recipient(message: message.Message) -> str:
|
||||
# We can't use Delivered-To; if there is a X-Gm-Original-To
|
||||
|
@ -322,8 +328,8 @@ def strip_from_subject(subject: str) -> str:
|
|||
|
||||
def process_stream_message(to: str, subject: str, message: message.Message,
|
||||
debug_info: Dict[str, Any]) -> None:
|
||||
stream = extract_and_validate(to)
|
||||
body = construct_zulip_body(message, stream.realm)
|
||||
stream, show_sender = extract_and_validate(to)
|
||||
body = construct_zulip_body(message, stream.realm, show_sender)
|
||||
debug_info["stream"] = stream
|
||||
send_zulip(settings.EMAIL_GATEWAY_BOT, stream, subject, body)
|
||||
logger.info("Successfully processed email to %s (%s)" % (
|
||||
|
|
|
@ -54,24 +54,54 @@ class TestEncodeDecode(ZulipTestCase):
|
|||
self.assertTrue(email_address.endswith('@testserver'))
|
||||
tup = decode_email_address(email_address)
|
||||
assert tup is not None
|
||||
(decoded_stream_name, token) = tup
|
||||
(decoded_stream_name, token, show_sender) = tup
|
||||
self.assertFalse(show_sender)
|
||||
self.assertEqual(decoded_stream_name, stream_name)
|
||||
self.assertEqual(token, stream.email_token)
|
||||
|
||||
email_address = email_address.replace('+', '.')
|
||||
tup = decode_email_address(email_address)
|
||||
parts = email_address.split('@')
|
||||
parts[0] += "+show-sender"
|
||||
email_address_show = '@'.join(parts)
|
||||
tup = decode_email_address(email_address_show)
|
||||
assert tup is not None
|
||||
(decoded_stream_name, token) = tup
|
||||
(decoded_stream_name, token, show_sender) = tup
|
||||
self.assertTrue(show_sender)
|
||||
self.assertEqual(decoded_stream_name, stream_name)
|
||||
self.assertEqual(token, stream.email_token)
|
||||
|
||||
email_address_dots = email_address.replace('+', '.')
|
||||
tup = decode_email_address(email_address_dots)
|
||||
assert tup is not None
|
||||
(decoded_stream_name, token, show_sender) = tup
|
||||
self.assertFalse(show_sender)
|
||||
self.assertEqual(decoded_stream_name, stream_name)
|
||||
self.assertEqual(token, stream.email_token)
|
||||
|
||||
email_address_dots_show = email_address_show.replace('+', '.')
|
||||
tup = decode_email_address(email_address_dots_show)
|
||||
assert tup is not None
|
||||
(decoded_stream_name, token, show_sender) = tup
|
||||
self.assertTrue(show_sender)
|
||||
self.assertEqual(decoded_stream_name, stream_name)
|
||||
self.assertEqual(token, stream.email_token)
|
||||
|
||||
email_address = email_address.replace('@testserver', '@zulip.org')
|
||||
email_address_show = email_address_show.replace('@testserver', '@zulip.org')
|
||||
self.assertEqual(decode_email_address(email_address), None)
|
||||
self.assertEqual(decode_email_address(email_address_show), None)
|
||||
|
||||
with self.settings(EMAIL_GATEWAY_EXTRA_PATTERN_HACK='@zulip.org'):
|
||||
tup = decode_email_address(email_address)
|
||||
assert tup is not None
|
||||
(decoded_stream_name, token) = tup
|
||||
(decoded_stream_name, token, show_sender) = tup
|
||||
self.assertFalse(show_sender)
|
||||
self.assertEqual(decoded_stream_name, stream_name)
|
||||
self.assertEqual(token, stream.email_token)
|
||||
|
||||
tup = decode_email_address(email_address_show)
|
||||
assert tup is not None
|
||||
(decoded_stream_name, token, show_sender) = tup
|
||||
self.assertTrue(show_sender)
|
||||
self.assertEqual(decoded_stream_name, stream_name)
|
||||
self.assertEqual(token, stream.email_token)
|
||||
|
||||
|
@ -206,6 +236,30 @@ 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_show_sender_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_to_address = encode_email_address(stream)
|
||||
parts = stream_to_address.split('@')
|
||||
parts[0] += "+show-sender"
|
||||
stream_to_address = '@'.join(parts)
|
||||
|
||||
incoming_valid_message = MIMEText('TestStreamEmailMessages Body')
|
||||
incoming_valid_message['Subject'] = 'TestStreamEmailMessages Subject'
|
||||
incoming_valid_message['From'] = self.example_email('hamlet')
|
||||
incoming_valid_message['To'] = stream_to_address
|
||||
incoming_valid_message['Reply-to'] = self.example_email('othello')
|
||||
|
||||
process_message(incoming_valid_message)
|
||||
message = most_recent_message(user_profile)
|
||||
|
||||
self.assertEqual(message.content, "From: %s\n%s" % (self.example_email('hamlet'),
|
||||
"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