Make SMTP notify send images as attachments if html is disabled (#93562)

smtp notify: send images without html as attachments

update smtp test to detect content_type for plain txt + image
This commit is contained in:
aptalca 2023-11-23 07:51:51 -05:00 committed by GitHub
parent 6b138a276a
commit a1f7f899c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 27 additions and 22 deletions

View File

@ -185,9 +185,8 @@ class MailNotificationService(BaseNotificationService):
def send_message(self, message="", **kwargs): def send_message(self, message="", **kwargs):
"""Build and send a message to a user. """Build and send a message to a user.
Will send plain text normally, or will build a multipart HTML message Will send plain text normally, with pictures as attachments if images config is
with inline image attachments if images config is defined, or will defined, or will build a multipart HTML if html config is defined.
build a multipart HTML if html config is defined.
""" """
subject = kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT) subject = kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT)
@ -242,8 +241,12 @@ def _build_text_msg(message):
return MIMEText(message) return MIMEText(message)
def _attach_file(atch_name, content_id): def _attach_file(atch_name, content_id=""):
"""Create a message attachment.""" """Create a message attachment.
If MIMEImage is successful and content_id is passed (HTML), add images in-line.
Otherwise add them as attachments.
"""
try: try:
with open(atch_name, "rb") as attachment_file: with open(atch_name, "rb") as attachment_file:
file_bytes = attachment_file.read() file_bytes = attachment_file.read()
@ -258,32 +261,34 @@ def _attach_file(atch_name, content_id):
"Attachment %s has an unknown MIME type. Falling back to file", "Attachment %s has an unknown MIME type. Falling back to file",
atch_name, atch_name,
) )
attachment = MIMEApplication(file_bytes, Name=atch_name) attachment = MIMEApplication(file_bytes, Name=os.path.basename(atch_name))
attachment["Content-Disposition"] = f'attachment; filename="{atch_name}"' attachment[
"Content-Disposition"
] = f'attachment; filename="{os.path.basename(atch_name)}"'
else:
if content_id:
attachment.add_header("Content-ID", f"<{content_id}>")
else:
attachment.add_header(
"Content-Disposition",
f"attachment; filename={os.path.basename(atch_name)}",
)
attachment.add_header("Content-ID", f"<{content_id}>")
return attachment return attachment
def _build_multipart_msg(message, images): def _build_multipart_msg(message, images):
"""Build Multipart message with in-line images.""" """Build Multipart message with images as attachments."""
_LOGGER.debug("Building multipart email with embedded attachment(s)") _LOGGER.debug("Building multipart email with image attachment(s)")
msg = MIMEMultipart("related") msg = MIMEMultipart()
msg_alt = MIMEMultipart("alternative")
msg.attach(msg_alt)
body_txt = MIMEText(message) body_txt = MIMEText(message)
msg_alt.attach(body_txt) msg.attach(body_txt)
body_text = [f"<p>{message}</p><br>"]
for atch_num, atch_name in enumerate(images): for atch_name in images:
cid = f"image{atch_num}" attachment = _attach_file(atch_name)
body_text.append(f'<img src="cid:{cid}"><br>')
attachment = _attach_file(atch_name, cid)
if attachment: if attachment:
msg.attach(attachment) msg.attach(attachment)
body_html = MIMEText("".join(body_text), "html")
msg_alt.attach(body_html)
return msg return msg

View File

@ -101,7 +101,7 @@ EMAIL_DATA = [
( (
"Test msg", "Test msg",
{"images": ["tests/testing_config/notify/test.jpg"]}, {"images": ["tests/testing_config/notify/test.jpg"]},
"Content-Type: multipart/related", "Content-Type: multipart/mixed",
), ),
( (
"Test msg", "Test msg",