mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	send_email: Parse emails in a way mypy 1.14 understands.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
(cherry picked from commit 63aaafb94a)
			
			
This commit is contained in:
		
				
					committed by
					
						
						Tim Abbott
					
				
			
			
				
	
			
			
			
						parent
						
							4431bd3018
						
					
				
				
					commit
					729d1f078b
				
			@@ -6,6 +6,7 @@ from collections.abc import Callable, Mapping
 | 
			
		||||
from contextlib import suppress
 | 
			
		||||
from datetime import timedelta
 | 
			
		||||
from email.headerregistry import Address
 | 
			
		||||
from email.message import EmailMessage
 | 
			
		||||
from email.parser import Parser
 | 
			
		||||
from email.policy import default
 | 
			
		||||
from email.utils import formataddr, parseaddr
 | 
			
		||||
@@ -526,7 +527,7 @@ def custom_email_sender(
 | 
			
		||||
) -> Callable[..., None]:
 | 
			
		||||
    with open(markdown_template_path) as f:
 | 
			
		||||
        text = f.read()
 | 
			
		||||
        parsed_email_template = Parser(policy=default).parsestr(text)
 | 
			
		||||
        parsed_email_template = Parser(_class=EmailMessage, policy=default).parsestr(text)
 | 
			
		||||
        email_template_hash = hashlib.sha256(text.encode()).hexdigest()[0:32]
 | 
			
		||||
 | 
			
		||||
    email_id = f"zerver/emails/custom/custom_email_{email_template_hash}"
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ recipient address and retrieve, forward, and archive the message.
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
import email
 | 
			
		||||
import email.parser
 | 
			
		||||
import email.policy
 | 
			
		||||
import logging
 | 
			
		||||
from collections.abc import Generator
 | 
			
		||||
@@ -69,10 +69,9 @@ def get_imap_messages() -> Generator[EmailMessage, None, None]:
 | 
			
		||||
                status, msg_data = mbox.fetch(message_id, "(RFC822)")
 | 
			
		||||
                assert isinstance(msg_data[0], tuple)
 | 
			
		||||
                msg_as_bytes = msg_data[0][1]
 | 
			
		||||
                message = email.message_from_bytes(msg_as_bytes, policy=email.policy.default)
 | 
			
		||||
                # https://github.com/python/typeshed/issues/2417
 | 
			
		||||
                assert isinstance(message, EmailMessage)
 | 
			
		||||
                yield message
 | 
			
		||||
                yield email.parser.BytesParser(
 | 
			
		||||
                    _class=EmailMessage, policy=email.policy.default
 | 
			
		||||
                ).parsebytes(msg_as_bytes)
 | 
			
		||||
                mbox.store(message_id, "+FLAGS", "\\Deleted")
 | 
			
		||||
            mbox.expunge()
 | 
			
		||||
        finally:
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
import base64
 | 
			
		||||
import email
 | 
			
		||||
import email.parser
 | 
			
		||||
import email.policy
 | 
			
		||||
import os
 | 
			
		||||
from email.message import EmailMessage
 | 
			
		||||
@@ -105,10 +105,9 @@ Example:
 | 
			
		||||
            return self._parse_email_json_fixture(fixture_path)
 | 
			
		||||
        else:
 | 
			
		||||
            with open(fixture_path, "rb") as fp:
 | 
			
		||||
                message = email.message_from_binary_file(fp, policy=email.policy.default)
 | 
			
		||||
                # https://github.com/python/typeshed/issues/2417
 | 
			
		||||
                assert isinstance(message, EmailMessage)
 | 
			
		||||
                return message
 | 
			
		||||
                return email.parser.BytesParser(
 | 
			
		||||
                    _class=EmailMessage, policy=email.policy.default
 | 
			
		||||
                ).parse(fp)
 | 
			
		||||
 | 
			
		||||
    def _prepare_message(self, message: EmailMessage, realm: Realm, stream_name: str) -> None:
 | 
			
		||||
        stream = get_stream(stream_name, realm)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
import base64
 | 
			
		||||
import email.parser
 | 
			
		||||
import email.policy
 | 
			
		||||
import os
 | 
			
		||||
import subprocess
 | 
			
		||||
from collections.abc import Callable, Mapping
 | 
			
		||||
from email import message_from_string
 | 
			
		||||
from email.headerregistry import Address
 | 
			
		||||
from email.message import EmailMessage, MIMEPart
 | 
			
		||||
from typing import TYPE_CHECKING, Any
 | 
			
		||||
@@ -1639,9 +1639,9 @@ class TestContentTypeUnspecifiedCharset(ZulipTestCase):
 | 
			
		||||
        message_as_string = message_as_string.replace(
 | 
			
		||||
            'Content-Type: text/plain; charset="us-ascii"', "Content-Type: text/plain"
 | 
			
		||||
        )
 | 
			
		||||
        incoming_message = message_from_string(message_as_string, policy=email.policy.default)
 | 
			
		||||
        # https://github.com/python/typeshed/issues/2417
 | 
			
		||||
        assert isinstance(incoming_message, EmailMessage)
 | 
			
		||||
        incoming_message = email.parser.Parser(
 | 
			
		||||
            _class=EmailMessage, policy=email.policy.default
 | 
			
		||||
        ).parsestr(message_as_string)
 | 
			
		||||
 | 
			
		||||
        user_profile = self.example_user("hamlet")
 | 
			
		||||
        self.login_user(user_profile)
 | 
			
		||||
@@ -1664,9 +1664,9 @@ class TestContentTypeInvalidCharset(ZulipTestCase):
 | 
			
		||||
            'Content-Type: text/plain; charset="us-ascii"',
 | 
			
		||||
            'Content-Type: text/plain; charset="bogus"',
 | 
			
		||||
        )
 | 
			
		||||
        incoming_message = message_from_string(message_as_string, policy=email.policy.default)
 | 
			
		||||
        # https://github.com/python/typeshed/issues/2417
 | 
			
		||||
        assert isinstance(incoming_message, EmailMessage)
 | 
			
		||||
        incoming_message = email.parser.Parser(
 | 
			
		||||
            _class=EmailMessage, policy=email.policy.default
 | 
			
		||||
        ).parsestr(message_as_string)
 | 
			
		||||
 | 
			
		||||
        user_profile = self.example_user("hamlet")
 | 
			
		||||
        self.login_user(user_profile)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
# Documented in https://zulip.readthedocs.io/en/latest/subsystems/queuing.html
 | 
			
		||||
import base64
 | 
			
		||||
import email
 | 
			
		||||
import email.parser
 | 
			
		||||
import email.policy
 | 
			
		||||
import logging
 | 
			
		||||
from collections.abc import Mapping
 | 
			
		||||
@@ -26,11 +26,9 @@ class MirrorWorker(QueueProcessingWorker):
 | 
			
		||||
    @override
 | 
			
		||||
    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,
 | 
			
		||||
        msg = email.parser.BytesParser(_class=EmailMessage, policy=email.policy.default).parsebytes(
 | 
			
		||||
            base64.b64decode(event["msg_base64"])
 | 
			
		||||
        )
 | 
			
		||||
        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.
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user