Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 1 commit into from Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
47 changes: 26 additions & 21 deletions homeassistant/components/smtp/notify.py
Expand Up @@ -185,9 +185,8 @@ def connection_is_valid(self):
def send_message(self, message="", **kwargs):
"""Build and send a message to a user.

Will send plain text normally, or will build a multipart HTML message
with inline image attachments if images config is defined, or will
build a multipart HTML if html config is defined.
Will send plain text normally, with pictures as attachments if images config is
defined, or will build a multipart HTML if html config is defined.
"""
subject = kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT)

Expand Down Expand Up @@ -242,8 +241,12 @@ def _build_text_msg(message):
return MIMEText(message)


def _attach_file(atch_name, content_id):
"""Create a message attachment."""
def _attach_file(atch_name, content_id=""):
"""Create a message attachment.

If MIMEImage is successful and content_id is passed (HTML), add images in-line.
Otherwise add them as attachments.
"""
try:
with open(atch_name, "rb") as attachment_file:
file_bytes = attachment_file.read()
Expand All @@ -258,32 +261,34 @@ def _attach_file(atch_name, content_id):
"Attachment %s has an unknown MIME type. Falling back to file",
atch_name,
)
attachment = MIMEApplication(file_bytes, Name=atch_name)
attachment["Content-Disposition"] = f'attachment; filename="{atch_name}"'
attachment = MIMEApplication(file_bytes, Name=os.path.basename(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


def _build_multipart_msg(message, images):
"""Build Multipart message with in-line images."""
_LOGGER.debug("Building multipart email with embedded attachment(s)")
msg = MIMEMultipart("related")
msg_alt = MIMEMultipart("alternative")
msg.attach(msg_alt)
"""Build Multipart message with images as attachments."""
_LOGGER.debug("Building multipart email with image attachment(s)")
msg = MIMEMultipart()
body_txt = MIMEText(message)
msg_alt.attach(body_txt)
body_text = [f"<p>{message}</p><br>"]
msg.attach(body_txt)

for atch_num, atch_name in enumerate(images):
cid = f"image{atch_num}"
body_text.append(f'<img src="cid:{cid}"><br>')
attachment = _attach_file(atch_name, cid)
for atch_name in images:
attachment = _attach_file(atch_name)
if attachment:
msg.attach(attachment)

body_html = MIMEText("".join(body_text), "html")
msg_alt.attach(body_html)
return msg


Expand Down
2 changes: 1 addition & 1 deletion tests/components/smtp/test_notify.py
Expand Up @@ -101,7 +101,7 @@ def message():
(
"Test msg",
{"images": ["tests/testing_config/notify/test.jpg"]},
"Content-Type: multipart/related",
"Content-Type: multipart/mixed",
),
(
"Test msg",
Expand Down