fix(sendmail): respect inline_images parameter in sendmail

This commit is contained in:
prathameshkurunkar7 2026-02-19 14:53:32 +05:30
parent aee0295275
commit a252e7e265
2 changed files with 62 additions and 3 deletions

View file

@ -210,7 +210,18 @@ class EMail:
if has_inline_images:
# process inline images
message, _inline_images = replace_filename_with_cid(message)
provided_images = {}
if inline_images:
for img in inline_images:
if img.get("filename") and img.get("filecontent"):
# index by full path and basename for flexible matching
provided_images[img["filename"]] = img["filecontent"]
basename = img["filename"].rsplit("/", 1)[-1]
if basename not in provided_images:
provided_images[basename] = img["filecontent"]
# process inline images while preferring provided_images over disk reads
message, _inline_images = replace_filename_with_cid(message, provided_images)
# prepare parts
msg_related = MIMEMultipart("related", policy=policy.SMTP)
@ -552,11 +563,22 @@ def get_footer(email_account, footer=None):
return footer
def replace_filename_with_cid(message):
def replace_filename_with_cid(message, provided_images=None):
"""Replaces <img embed="assets/frappe/images/filename.jpg" ...> with
<img src="cid:content_id" ...> and return the modified message and
a list of inline_images with {filename, filecontent, content_id}
Args:
message: The HTML message to process
provided_images: A dictionary of images to use instead of reading from disk
Example:
{
"assets/frappe/images/filename.jpg": filecontent,
"filename.jpg": filecontent,
}
"""
if provided_images is None:
provided_images = {}
inline_images = []
@ -571,7 +593,11 @@ def replace_filename_with_cid(message):
img_path_escaped = frappe.utils.html_utils.unescape_html(img_path)
filename = img_path_escaped.rsplit("/")[-1]
# check if the image is provided in the provided_images(by checking full path and basename)
filecontent = provided_images.get(img_path_escaped) or provided_images.get(filename)
if not filecontent:
filecontent = get_filecontent_from_path(img_path_escaped)
if not filecontent:
message = re.sub(f"""embed=['"]{re.escape(img_path)}['"]""", "", message)
continue

View file

@ -137,6 +137,39 @@ w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
""".format(inline_images[0].get("content_id"))
self.assertEqual(message, processed_message)
def test_sendmail_inline_images_parameter_respected(self):
"""Test that inline_images parameter works through sendmail."""
test_image_content = b"FAKE_PNG_BINARY_CONTENT_FOR_TESTING"
html_content = '<div><img embed="files/nonexistent_test_image.png" alt="Logo"></div>'
inline_images = [
{
"filename": "files/nonexistent_test_image.png",
"filecontent": test_image_content,
}
]
# Use QueueBuilder directly (what sendmail uses internally)
from frappe.email.doctype.email_queue.email_queue import QueueBuilder
builder = QueueBuilder(
recipients=["test@example.com"],
sender="me@example.com",
subject="Test Inline Images",
message=html_content,
inline_images=inline_images,
)
# Get the email content that would be sent
mail = builder.prepare_email_content()
email_string = mail.as_string()
# Assertions
self.assertIn("cid:", email_string)
self.assertNotIn('embed="files/nonexistent_test_image.png"', email_string)
def test_inline_styling(self):
html = """
<h3>Hi John</h3>