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:
Anders Kaseorg
2024-12-20 13:56:36 -08:00
committed by Tim Abbott
parent 4431bd3018
commit 729d1f078b
5 changed files with 20 additions and 23 deletions

View File

@@ -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}"

View File

@@ -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:

View File

@@ -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)

View File

@@ -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)

View File

@@ -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.