Skip to content

Commit be97af4

Browse files
committed
[Mime] Fix email rendering when having inlined parts that are not related to the content
1 parent fc1c9be commit be97af4

File tree

2 files changed

+46
-15
lines changed

2 files changed

+46
-15
lines changed

src/Symfony/Component/Mime/Email.php

+17-15
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ private function generateBody(): AbstractPart
463463

464464
$this->ensureValidity();
465465

466-
[$htmlPart, $attachmentParts, $inlineParts] = $this->prepareParts();
466+
[$htmlPart, $otherParts, $relatedParts] = $this->prepareParts();
467467

468468
$part = null === $this->text ? null : new TextPart($this->text, $this->textCharset);
469469
if (null !== $htmlPart) {
@@ -474,15 +474,15 @@ private function generateBody(): AbstractPart
474474
}
475475
}
476476

477-
if ($inlineParts) {
478-
$part = new RelatedPart($part, ...$inlineParts);
477+
if ($relatedParts) {
478+
$part = new RelatedPart($part, ...$relatedParts);
479479
}
480480

481-
if ($attachmentParts) {
481+
if ($otherParts) {
482482
if ($part) {
483-
$part = new MixedPart($part, ...$attachmentParts);
483+
$part = new MixedPart($part, ...$otherParts);
484484
} else {
485-
$part = new MixedPart(...$attachmentParts);
485+
$part = new MixedPart(...$otherParts);
486486
}
487487
}
488488

@@ -508,42 +508,44 @@ private function prepareParts(): ?array
508508
}
509509

510510
// usage of reflection is a temporary workaround for missing getters that will be added in 6.2
511-
$dispositionRef = new \ReflectionProperty(TextPart::class, 'disposition');
512-
$dispositionRef->setAccessible(true);
513511
$nameRef = new \ReflectionProperty(TextPart::class, 'name');
514512
$nameRef->setAccessible(true);
515-
$attachmentParts = $inlineParts = [];
513+
$otherParts = $relatedParts = [];
516514
foreach ($this->attachments as $attachment) {
517515
$part = $this->createDataPart($attachment);
518516
if (isset($attachment['part'])) {
519517
$attachment['name'] = $nameRef->getValue($part);
520518
}
521519

520+
$related = false;
522521
foreach ($names as $name) {
523522
if ($name !== $attachment['name']) {
524523
continue;
525524
}
526-
if (isset($inlineParts[$name])) {
525+
if (isset($relatedParts[$name])) {
527526
continue 2;
528527
}
529528
$part->setDisposition('inline');
530-
$html = str_replace('cid:'.$name, 'cid:'.$part->getContentId(), $html);
529+
$html = str_replace('cid:'.$name, 'cid:'.$part->getContentId(), $html, $count);
530+
if ($count) {
531+
$related = true;
532+
}
531533
$part->setName($part->getContentId());
532534

533535
break;
534536
}
535537

536-
if ('inline' === $dispositionRef->getValue($part)) {
537-
$inlineParts[$attachment['name']] = $part;
538+
if ($related) {
539+
$relatedParts[$attachment['name']] = $part;
538540
} else {
539-
$attachmentParts[] = $part;
541+
$otherParts[] = $part;
540542
}
541543
}
542544
if (null !== $htmlPart) {
543545
$htmlPart = new TextPart($html, $this->htmlCharset, 'html');
544546
}
545547

546-
return [$htmlPart, $attachmentParts, array_values($inlineParts)];
548+
return [$htmlPart, $otherParts, array_values($relatedParts)];
547549
}
548550

549551
private function createDataPart(array $attachment): DataPart

src/Symfony/Component/Mime/Tests/EmailTest.php

+29
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,17 @@ public function testGenerateBodyWithHtmlContentAndAttachedFile()
302302
$this->assertEquals(new MixedPart($html, $filePart), $e->getBody());
303303
}
304304

305+
public function testGenerateBodyWithHtmlContentAndInlineImageNotreferenced()
306+
{
307+
[$text, $html, $filePart, $file, $imagePart, $image] = $this->generateSomeParts();
308+
$imagePart = new DataPart($image = fopen(__DIR__.'/Fixtures/mimetypes/test.gif', 'r'));
309+
$imagePart->asInline();
310+
$e = (new Email())->from('me@example.com')->to('you@example.com');
311+
$e->embed($image);
312+
$e->html('html content');
313+
$this->assertEquals(new MixedPart($html, $imagePart), $e->getBody());
314+
}
315+
305316
public function testGenerateBodyWithAttachedFileOnly()
306317
{
307318
[$text, $html, $filePart, $file, $imagePart, $image] = $this->generateSomeParts();
@@ -310,6 +321,24 @@ public function testGenerateBodyWithAttachedFileOnly()
310321
$this->assertEquals(new MixedPart($filePart), $e->getBody());
311322
}
312323

324+
public function testGenerateBodyWithInlineImageOnly()
325+
{
326+
$imagePart = new DataPart($image = fopen(__DIR__.'/Fixtures/mimetypes/test.gif', 'r'));
327+
$imagePart->asInline();
328+
$e = (new Email())->from('me@example.com')->to('you@example.com');
329+
$e->embed($image);
330+
$this->assertEquals(new MixedPart($imagePart), $e->getBody());
331+
}
332+
333+
public function testGenerateBodyWithEmbeddedImageOnly()
334+
{
335+
$imagePart = new DataPart($image = fopen(__DIR__.'/Fixtures/mimetypes/test.gif', 'r'));
336+
$e = (new Email())->from('me@example.com')->to('you@example.com');
337+
$e->embed($image);
338+
$imagePart->asInline();
339+
$this->assertEquals(new MixedPart($imagePart), $e->getBody());
340+
}
341+
313342
public function testGenerateBodyWithTextAndHtmlContentAndAttachedFile()
314343
{
315344
[$text, $html, $filePart, $file, $imagePart, $image] = $this->generateSomeParts();

0 commit comments

Comments
 (0)