From 6006207a7861ecbb7830ac7221a2e1ca0d225535 Mon Sep 17 00:00:00 2001 From: yinheli Date: Fri, 31 Oct 2025 15:23:48 +0800 Subject: [PATCH] Fix DataPart API misuse in email embed methods - second parameter is filename, not cid --- src/Illuminate/Mail/Message.php | 33 ++++++++----------- .../Integration/Mail/Fixtures/embed.blade.php | 2 ++ .../Mail/SendingMarkdownMailTest.php | 18 ++++++---- .../Notifications/Fixtures/markdown.blade.php | 1 + .../SendingMailableNotificationsTest.php | 16 ++++++--- tests/Mail/MailMessageTest.php | 23 ++++++++----- 6 files changed, 54 insertions(+), 39 deletions(-) diff --git a/src/Illuminate/Mail/Message.php b/src/Illuminate/Mail/Message.php index b9a4eb5352ca..e3eb8e1a8d1b 100755 --- a/src/Illuminate/Mail/Message.php +++ b/src/Illuminate/Mail/Message.php @@ -4,7 +4,6 @@ use Illuminate\Contracts\Mail\Attachable; use Illuminate\Support\Collection; -use Illuminate\Support\Str; use Illuminate\Support\Traits\ForwardsCalls; use Symfony\Component\Mime\Address; use Symfony\Component\Mime\Email; @@ -344,31 +343,27 @@ public function embed($file) if ($file instanceof Attachment) { return $file->attachWith( function ($path) use ($file) { - $cid = $file->as ?? Str::random(); + $part = (new DataPart(new File($path), $file->as, $file->mime))->asInline(); - $this->message->addPart( - (new DataPart(new File($path), $cid, $file->mime))->asInline() - ); + $this->message->addPart($part); - return "cid:{$cid}"; + return "cid:{$part->getContentId()}"; }, function ($data) use ($file) { - $this->message->addPart( - (new DataPart($data(), $file->as, $file->mime))->asInline() - ); + $part = (new DataPart($data(), $file->as, $file->mime))->asInline(); + $this->message->addPart($part); - return "cid:{$file->as}"; + return "cid:{$part->getContentId()}"; } ); } - $cid = Str::random(10); + $fileObject = new File($file); + $part = (new DataPart($fileObject, $fileObject->getFilename()))->asInline(); - $this->message->addPart( - (new DataPart(new File($file), $cid))->asInline() - ); + $this->message->addPart($part); - return "cid:$cid"; + return "cid:{$part->getContentId()}"; } /** @@ -381,11 +376,11 @@ function ($data) use ($file) { */ public function embedData($data, $name, $contentType = null) { - $this->message->addPart( - (new DataPart($data, $name, $contentType))->asInline() - ); + $part = (new DataPart($data, $name, $contentType))->asInline(); + + $this->message->addPart($part); - return "cid:$name"; + return "cid:{$part->getContentId()}"; } /** diff --git a/tests/Integration/Mail/Fixtures/embed.blade.php b/tests/Integration/Mail/Fixtures/embed.blade.php index 4a19e330d84e..7b3839aa472d 100644 --- a/tests/Integration/Mail/Fixtures/embed.blade.php +++ b/tests/Integration/Mail/Fixtures/embed.blade.php @@ -1 +1,3 @@ +Embed file: {{ basename(__FILE__) }} + Embed content: {{ $message->embed(__FILE__) }} diff --git a/tests/Integration/Mail/SendingMarkdownMailTest.php b/tests/Integration/Mail/SendingMarkdownMailTest.php index 712fe0b7cecb..388eceaa93c9 100644 --- a/tests/Integration/Mail/SendingMarkdownMailTest.php +++ b/tests/Integration/Mail/SendingMarkdownMailTest.php @@ -52,13 +52,19 @@ public function testEmbed() $email = app('mailer')->getSymfonyTransport()->messages()[0]->getOriginalMessage()->toString(); $cid = explode(' cid:', (new Stringable($email))->explode("\r\n") - ->filter(fn ($line) => str_contains($line, 'Embed content: cid:')) + ->filter(fn ($line) => str_contains($line, ' content: cid:')) + ->first())[1]; + + $filename = explode('Embed file: ', (new Stringable($email))->explode("\r\n") + ->filter(fn ($line) => str_contains($line, ' file:')) ->first())[1]; $this->assertStringContainsString(<<\r EOT, $email); } @@ -66,9 +72,8 @@ public function testEmbedData() { Mail::to('test@mail.com')->send($mailable = new EmbedDataMailable()); - $mailable->assertSeeInHtml('Embed data content: cid:foo.jpg'); $mailable->assertSeeInText('Embed data content: '); - $mailable->assertDontSeeInText('Embed data content: cid:foo.jpg'); + $mailable->assertSeeInHtml('Embed data content: cid:'); $email = app('mailer')->getSymfonyTransport()->messages()[0]->getOriginalMessage()->toString(); @@ -87,8 +92,7 @@ public function testEmbedMultilineImage() $this->assertStringContainsString('Embed multiline content: assertStringContainsString('alt="multiline image"', $html); - $this->assertStringContainsString('data:image/png;base64', $html); - $this->assertStringNotContainsString('cid:foo.jpg', $html); + $this->assertStringContainsString('explode("\n") ->filter(fn ($line) => str_contains($line, 'Embed content: cid:')) ->first())[1]; + $filename = explode(' file: ', (new Stringable($textBody))->explode("\n") + ->filter(fn ($line) => str_contains($line, 'Embed file: ')) + ->first())[1]; + $this->assertStringContainsString(<<\r EOT, $email); } diff --git a/tests/Mail/MailMessageTest.php b/tests/Mail/MailMessageTest.php index 330777cd674a..eff028ddadfe 100755 --- a/tests/Mail/MailMessageTest.php +++ b/tests/Mail/MailMessageTest.php @@ -165,13 +165,14 @@ public function testEmbedPath(): void $cid = $this->message->embed($path); $this->assertStringStartsWith('cid:', $cid); - $name = Str::after($cid, 'cid:'); + $contentId = Str::after($cid, 'cid:'); $attachment = $this->message->getSymfonyMessage()->getAttachments()[0]; $headers = $attachment->getPreparedHeaders()->toArray(); $this->assertSame('bar', $attachment->getBody()); - $this->assertSame("Content-Type: image/jpeg; name={$name}", $headers[0]); + $this->assertSame($contentId, $attachment->getContentId()); + $this->assertStringContainsString('Content-Type: image/jpeg', $headers[0]); $this->assertSame('Content-Transfer-Encoding: base64', $headers[1]); - $this->assertSame("Content-Disposition: inline; name={$name}; filename={$name}", $headers[2]); + $this->assertStringContainsString('Content-Disposition: inline', $headers[2]); unlink($path); } @@ -182,7 +183,9 @@ public function testDataEmbed(): void $attachment = $this->message->getSymfonyMessage()->getAttachments()[0]; $headers = $attachment->getPreparedHeaders()->toArray(); - $this->assertSame('cid:foo.jpg', $cid); + $this->assertStringStartsWith('cid:', $cid); + $contentId = Str::after($cid, 'cid:'); + $this->assertSame($contentId, $attachment->getContentId()); $this->assertSame('bar', $attachment->getBody()); $this->assertSame('Content-Type: image/png; name=foo.jpg', $headers[0]); $this->assertSame('Content-Transfer-Encoding: base64', $headers[1]); @@ -201,9 +204,11 @@ public function toMailAttachment() } }); - $this->assertSame('cid:baz', $cid); + $this->assertStringStartsWith('cid:', $cid); + $contentId = Str::after($cid, 'cid:'); $attachment = $this->message->getSymfonyMessage()->getAttachments()[0]; $headers = $attachment->getPreparedHeaders()->toArray(); + $this->assertSame($contentId, $attachment->getContentId()); $this->assertSame('bar', $attachment->getBody()); $this->assertSame('Content-Type: image/png; name=baz', $headers[0]); $this->assertSame('Content-Transfer-Encoding: base64', $headers[1]); @@ -225,14 +230,14 @@ public function toMailAttachment() }); $this->assertStringStartsWith('cid:', $cid); - $name = Str::after($cid, 'cid:'); - $this->assertSame(16, mb_strlen($name)); + $contentId = Str::after($cid, 'cid:'); $attachment = $this->message->getSymfonyMessage()->getAttachments()[0]; + $this->assertSame($contentId, $attachment->getContentId()); $headers = $attachment->getPreparedHeaders()->toArray(); $this->assertSame('bar', $attachment->getBody()); - $this->assertSame("Content-Type: image/jpeg; name={$name}", $headers[0]); + $this->assertStringContainsString('Content-Type: image/jpeg', $headers[0]); $this->assertSame('Content-Transfer-Encoding: base64', $headers[1]); - $this->assertSame("Content-Disposition: inline; name={$name};\r\n filename={$name}", $headers[2]); + $this->assertStringContainsString('Content-Disposition: inline', $headers[2]); unlink($path); }