diff --git a/README.md b/README.md index 5451ab9..dbee50a 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,8 @@ The `save_to_sent_items` option in Microsoft Graph refers to a parameter that de By default, the save_to_sent_items option is set to false, which means that emails sent through Microsoft Graph won't be saved in the sender's "Sent Items" folder unless explicitly specified otherwise. This behavior can be useful in scenarios where you might want more control over which emails are saved as sent items, perhaps to reduce clutter or ensure confidentiality. +This can be overridden by setting the `Mailable` or `Envelope` metadata field `saveToSentItems` to `true` or `false`. + Now you can switch your default mail driver to the new `microsoft-graph` driver by setting the env variable: ```dotenv diff --git a/src/MicrosoftGraphTransport.php b/src/MicrosoftGraphTransport.php index aac89be..cbc8a20 100644 --- a/src/MicrosoftGraphTransport.php +++ b/src/MicrosoftGraphTransport.php @@ -8,6 +8,7 @@ use Psr\EventDispatcher\EventDispatcherInterface; use Psr\Log\LoggerInterface; use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\Header\MetadataHeader; use Symfony\Component\Mailer\SentMessage; use Symfony\Component\Mailer\Transport\AbstractTransport; use Symfony\Component\Mime\Address; @@ -56,7 +57,7 @@ protected function doSend(SentMessage $message): void 'sender' => $this->transformEmailAddress($envelope->getSender()), 'attachments' => $attachments, ], - 'saveToSentItems' => config('mail.mailers.microsoft-graph.save_to_sent_items', false) ?? false, + 'saveToSentItems' => $this->getSaveToSentItems($email), ]; if (filled($headers = $this->getInternetMessageHeaders($email))) { @@ -126,9 +127,21 @@ protected function getRecipients(Email $email, Envelope $envelope): Collection protected function getInternetMessageHeaders(Email $email): ?array { return collect($email->getHeaders()->all()) - ->filter(fn (HeaderInterface $header) => str_starts_with($header->getName(), 'X-')) + ->filter(fn (HeaderInterface $header) => ! $header instanceof MetadataHeader && str_starts_with($header->getName(), 'X-')) ->map(fn (HeaderInterface $header) => ['name' => $header->getName(), 'value' => $header->getBodyAsString()]) ->values() ->all() ?: null; } + + protected function getSaveToSentItems(Email $email): bool + { + foreach ($email->getHeaders()->all() as $header) { + if ($header instanceof MetadataHeader && $header->getKey() === 'saveToSentItems') { + return filter_var($header->getValue(), FILTER_VALIDATE_BOOLEAN); + } + } + + // @phpstan-ignore return.type + return config('mail.mailers.microsoft-graph.save_to_sent_items', false) ?? false; + } } diff --git a/tests/MicrosoftGraphTransportTest.php b/tests/MicrosoftGraphTransportTest.php index 5a3f54e..7427070 100644 --- a/tests/MicrosoftGraphTransportTest.php +++ b/tests/MicrosoftGraphTransportTest.php @@ -611,3 +611,90 @@ return true; }); }); + +it('sends saves to sent items from mailable', function () { + Config::set('mail.mailers.microsoft-graph', [ + 'transport' => 'microsoft-graph', + 'client_id' => 'foo_client_id', + 'client_secret' => 'foo_client_secret', + 'tenant_id' => 'foo_tenant_id', + 'from' => [ + 'address' => 'taylor@laravel.com', + 'name' => 'Taylor Otwell', + ], + 'save_to_sent_items' => null, + ]); + Config::set('mail.default', 'microsoft-graph'); + + Cache::set('microsoft-graph-api-access-token', 'foo_access_token', 3600); + + Http::fake(); + + Mail::to('caleb@livewire.com') + ->bcc('tim@innoge.de') + ->cc('nuno@laravel.com') + ->send(new TestMail(saveToSentItems: true)); + + Http::assertSent(function (Request $value) { + expect($value) + ->url()->toBe('https://graph.microsoft.com/v1.0/users/taylor@laravel.com/sendMail') + ->hasHeader('Authorization', 'Bearer foo_access_token')->toBeTrue() + ->body()->json()->toBe([ + 'message' => [ + 'subject' => 'Dev Test', + 'body' => [ + 'contentType' => 'HTML', + 'content' => 'Test'.PHP_EOL, + ], + 'toRecipients' => [ + [ + 'emailAddress' => [ + 'address' => 'caleb@livewire.com', + ], + ], + ], + 'ccRecipients' => [ + [ + 'emailAddress' => [ + 'address' => 'nuno@laravel.com', + ], + ], + ], + 'bccRecipients' => [ + [ + 'emailAddress' => [ + 'address' => 'tim@innoge.de', + ], + ], + ], + 'replyTo' => [], + 'sender' => [ + 'emailAddress' => [ + 'address' => 'taylor@laravel.com', + ], + ], + 'attachments' => [ + [ + '@odata.type' => '#microsoft.graph.fileAttachment', + 'name' => 'test-file-1.txt', + 'contentType' => 'text', + 'contentBytes' => 'Zm9vCg==', + 'contentId' => 'test-file-1.txt', + 'isInline' => false, + ], + [ + '@odata.type' => '#microsoft.graph.fileAttachment', + 'name' => 'test-file-2.txt', + 'contentType' => 'text', + 'contentBytes' => 'Zm9vCg==', + 'contentId' => 'test-file-2.txt', + 'isInline' => false, + ], + ], + ], + 'saveToSentItems' => true, + ]); + + return true; + }); +}); diff --git a/tests/Stubs/TestMail.php b/tests/Stubs/TestMail.php index b511344..a0de8b0 100644 --- a/tests/Stubs/TestMail.php +++ b/tests/Stubs/TestMail.php @@ -19,7 +19,7 @@ class TestMail extends Mailable * * @return void */ - public function __construct(private readonly bool $isHtml = true, private readonly bool $includeHeaders = false) {} + public function __construct(private readonly bool $isHtml = true, private readonly bool $includeHeaders = false, private readonly ?bool $saveToSentItems = null) {} /** * Get the message envelope. @@ -30,6 +30,9 @@ public function envelope() { return new Envelope( subject: 'Dev Test', + metadata: isset($this->saveToSentItems) ? [ + 'saveToSentItems' => $this->saveToSentItems, + ] : [], ); }