Skip to content

Navigation Menu

Sign in
Appearance settings
Sign up
Appearance settings
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions 5 UPGRADE-8.2.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ SecurityBundle

* Deprecate the `remember_me` option of the `form_login`, `json_login`, `login_link`, and `access_token` authenticators, as it has no effect

Mailer
------

* Deprecate the "templateid" and "params" email headers in the Brevo bridge, use a `RemoteTemplateEmail` instead

Serializer
----------

Expand Down
5 changes: 5 additions & 0 deletions 5 src/Symfony/Component/Mailer/Bridge/Brevo/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

8.2
---

* Deprecate the "templateid" and "params" email headers, use a `RemoteTemplateEmail` instead

6.4
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
namespace Symfony\Component\Mailer\Bridge\Brevo\Tests\Transport;

use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\Attributes\IgnoreDeprecations;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\PhpUnit\ExpectUserDeprecationMessageTrait;
use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\Response\JsonMockResponse;
use Symfony\Component\Mailer\Bridge\Brevo\Transport\BrevoApiTransport;
Expand All @@ -21,13 +24,16 @@
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
use Symfony\Component\Mailer\Header\MetadataHeader;
use Symfony\Component\Mailer\Header\TagHeader;
use Symfony\Component\Mailer\RemoteTemplateEmail;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use Symfony\Component\Mime\Part\DataPart;
use Symfony\Contracts\HttpClient\ResponseInterface;

class BrevoApiTransportTest extends TestCase
{
use ExpectUserDeprecationMessageTrait;

#[DataProvider('getTransportData')]
public function testToString(BrevoApiTransport $transport, string $expected)
{
Expand All @@ -54,15 +60,12 @@ public static function getTransportData(): \Generator

public function testCustomHeader()
{
$params = ['param1' => 'foo', 'param2' => 'bar'];
$json = json_encode(['"custom_header_1' => 'custom_value_1']);

$email = new Email();
$email->getHeaders()
->add(new MetadataHeader('custom', $json))
->add(new TagHeader('TagInHeaders'))
->addTextHeader('templateId', 1)
->addParameterizedHeader('params', 'params', $params)
->addTextHeader('foo', 'bar');
$envelope = new Envelope(new Address('alice@system.com', 'Alice'), [new Address('bob@system.com', 'Bob')]);

Expand All @@ -75,15 +78,48 @@ public function testCustomHeader()

$this->assertArrayHasKey('tags', $payload);
$this->assertEquals('TagInHeaders', current($payload['tags']));
$this->assertArrayHasKey('templateId', $payload);
$this->assertEquals(1, $payload['templateId']);
$this->assertArrayHasKey('params', $payload);
$this->assertEquals('foo', $payload['params']['param1']);
$this->assertEquals('bar', $payload['params']['param2']);
$this->assertArrayHasKey('foo', $payload['headers']);
$this->assertEquals('bar', $payload['headers']['foo']);
}

public function testRemoteTemplate()
{
$email = (new RemoteTemplateEmail())
->template('42', ['param1' => 'foo', 'param2' => 'bar']);
$envelope = new Envelope(new Address('alice@system.com', 'Alice'), [new Address('bob@system.com', 'Bob')]);

$transport = new BrevoApiTransport('ACCESS_KEY');
$method = new \ReflectionMethod(BrevoApiTransport::class, 'getPayload');
$payload = $method->invoke($transport, $email, $envelope);

$this->assertSame(42, $payload['templateId']);
$this->assertSame(['param1' => 'foo', 'param2' => 'bar'], $payload['params']);
$this->assertArrayNotHasKey('subject', $payload);
$this->assertArrayNotHasKey('textContent', $payload);
$this->assertArrayNotHasKey('htmlContent', $payload);
}

#[IgnoreDeprecations]
#[Group('legacy')]
public function testDeprecatedTemplateHeaders()
{
$this->expectUserDeprecationMessage(\sprintf('Since symfony/brevo-mailer 8.2: Using the "templateid" email header to select a Brevo template is deprecated, use a "%s" instead.', RemoteTemplateEmail::class));
$this->expectUserDeprecationMessage(\sprintf('Since symfony/brevo-mailer 8.2: Using the "params" email header to define the variables of a Brevo template is deprecated, use a "%s" instead.', RemoteTemplateEmail::class));

$email = new Email();
$email->getHeaders()
->addTextHeader('templateId', 1)
->addParameterizedHeader('params', 'params', ['param1' => 'foo', 'param2' => 'bar']);
$envelope = new Envelope(new Address('alice@system.com', 'Alice'), [new Address('bob@system.com', 'Bob')]);

$transport = new BrevoApiTransport('ACCESS_KEY');
$method = new \ReflectionMethod(BrevoApiTransport::class, 'getPayload');
$payload = $method->invoke($transport, $email, $envelope);

$this->assertSame(1, $payload['templateId']);
$this->assertSame(['param1' => 'foo', 'param2' => 'bar'], $payload['params']);
}

public function testSendThrowsForErrorResponse()
{
$client = new MockHttpClient(function (string $method, string $url, array $options): ResponseInterface {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
use Symfony\Component\Mailer\Exception\HttpTransportException;
use Symfony\Component\Mailer\Header\MetadataHeader;
use Symfony\Component\Mailer\Header\TagHeader;
use Symfony\Component\Mailer\RemoteTemplateEmail;
use Symfony\Component\Mailer\SentMessage;
use Symfony\Component\Mailer\Transport\AbstractApiTransport;
use Symfony\Component\Mailer\Transport\RemoteTemplateTransportInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use Symfony\Component\Mime\Header\Headers;
Expand All @@ -30,7 +32,7 @@
/**
* @author Pierre TANGUY
*/
final class BrevoApiTransport extends AbstractApiTransport
final class BrevoApiTransport extends AbstractApiTransport implements RemoteTemplateTransportInterface
{
public function __construct(
#[\SensitiveParameter] private string $key,
Expand Down Expand Up @@ -88,11 +90,21 @@ private function formatAddresses(array $addresses): array

private function getPayload(Email $email, Envelope $envelope): array
{
$template = $email instanceof RemoteTemplateEmail ? $email->getRemoteTemplate() : null;

$payload = [
'sender' => $this->formatAddress($envelope->getSender()),
'to' => $this->formatAddresses($this->getRecipients($email, $envelope)),
'subject' => $email->getSubject(),
];
if (null === $template || null !== $email->getSubject()) {
$payload['subject'] = $email->getSubject();
}
if (null !== $template) {
$payload['templateId'] = (int) $template->getReference();
if ($template->getVariables()) {
$payload['params'] = $template->getVariables();
}
}
if ($attachments = $this->prepareAttachments($email)) {
$payload['attachment'] = $attachments;
}
Expand Down Expand Up @@ -154,11 +166,13 @@ private function prepareHeadersAndTags(Headers $headers): array
continue;
}
if ('templateid' === $name) {
trigger_deprecation('symfony/brevo-mailer', '8.2', 'Using the "templateid" email header to select a Brevo template is deprecated, use a "%s" instead.', RemoteTemplateEmail::class);
$headersAndTags[$header->getName()] = (int) $header->getValue();

continue;
}
if ('params' === $name) {
trigger_deprecation('symfony/brevo-mailer', '8.2', 'Using the "params" email header to define the variables of a Brevo template is deprecated, use a "%s" instead.', RemoteTemplateEmail::class);
$headersAndTags[$header->getName()] = $header->getParameters();

continue;
Expand Down
3 changes: 2 additions & 1 deletion 3 src/Symfony/Component/Mailer/Bridge/Brevo/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
],
"require": {
"php": ">=8.4.1",
"symfony/mailer": "^7.4|^8.0"
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/mailer": "^8.2"
},
"require-dev": {
"symfony/http-client": "^7.4|^8.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use Symfony\Component\Mailer\Exception\HttpTransportException;
use Symfony\Component\Mailer\Header\MetadataHeader;
use Symfony\Component\Mailer\Header\TagHeader;
use Symfony\Component\Mailer\RemoteTemplateEmail;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use Symfony\Component\Mime\Part\DataPart;
Expand Down Expand Up @@ -81,6 +82,37 @@ public function testCustomHeader()
$this->assertEquals('bar', $payload['headers']['foo']);
}

public function testRemoteTemplate()
{
$email = (new RemoteTemplateEmail())
->template('tpl_123', ['firstName' => 'Fabien']);
$envelope = new Envelope(new Address('alice@system.com', 'Alice'), [new Address('bob@system.com', 'Bob')]);

$transport = new ResendApiTransport('ACCESS_KEY');
$method = new \ReflectionMethod(ResendApiTransport::class, 'getPayload');
$payload = $method->invoke($transport, $email, $envelope);

$this->assertSame(['id' => 'tpl_123', 'variables' => ['firstName' => 'Fabien']], $payload['template']);
$this->assertArrayNotHasKey('subject', $payload);
$this->assertArrayNotHasKey('text', $payload);
$this->assertArrayNotHasKey('html', $payload);
}

public function testRemoteTemplateWithSubject()
{
$email = (new RemoteTemplateEmail())
->subject('Hello!')
->template('tpl_123');
$envelope = new Envelope(new Address('alice@system.com', 'Alice'), [new Address('bob@system.com', 'Bob')]);

$transport = new ResendApiTransport('ACCESS_KEY');
$method = new \ReflectionMethod(ResendApiTransport::class, 'getPayload');
$payload = $method->invoke($transport, $email, $envelope);

$this->assertSame('Hello!', $payload['subject']);
$this->assertSame(['id' => 'tpl_123'], $payload['template']);
}

public function testSendThrowsForErrorResponse()
{
$client = new MockHttpClient(function (string $method, string $url, array $options): ResponseInterface {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
use Symfony\Component\Mailer\Exception\HttpTransportException;
use Symfony\Component\Mailer\Exception\InvalidArgumentException;
use Symfony\Component\Mailer\Header\TagHeader;
use Symfony\Component\Mailer\RemoteTemplateEmail;
use Symfony\Component\Mailer\SentMessage;
use Symfony\Component\Mailer\Transport\AbstractApiTransport;
use Symfony\Component\Mailer\Transport\RemoteTemplateTransportInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use Symfony\Component\Mime\Header\Headers;
Expand All @@ -30,7 +32,7 @@
/**
* @author Mathieu Santostefano <msantostefano@proton.me>
*/
final class ResendApiTransport extends AbstractApiTransport
final class ResendApiTransport extends AbstractApiTransport implements RemoteTemplateTransportInterface
{
public function __construct(
#[\SensitiveParameter] private readonly string $apiKey,
Expand Down Expand Up @@ -94,11 +96,21 @@ private function formatAddresses(array $addresses): array

private function getPayload(Email $email, Envelope $envelope): array
{
$template = $email instanceof RemoteTemplateEmail ? $email->getRemoteTemplate() : null;

$payload = [
'from' => $this->formatAddress($envelope->getSender()),
'to' => $this->formatAddresses($this->getRecipients($email, $envelope)),
'subject' => $email->getSubject(),
];
if (null === $template || null !== $email->getSubject()) {
$payload['subject'] = $email->getSubject();
}
if (null !== $template) {
$payload['template'] = ['id' => $template->getReference()];
if ($template->getVariables()) {
$payload['template']['variables'] = $template->getVariables();
}
}
if ($attachments = $this->prepareAttachments($email)) {
$payload['attachments'] = $attachments;
}
Expand Down
2 changes: 1 addition & 1 deletion 2 src/Symfony/Component/Mailer/Bridge/Resend/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
],
"require": {
"php": ">=8.4.1",
"symfony/mailer": "^7.4|^8.0"
"symfony/mailer": "^8.2"
},
"require-dev": {
"symfony/http-client": "^7.4|^8.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Symfony\Component\Mailer\Envelope;
use Symfony\Component\Mailer\Header\MetadataHeader;
use Symfony\Component\Mailer\Header\TagHeader;
use Symfony\Component\Mailer\RemoteTemplateEmail;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use Symfony\Component\Mime\Part\DataPart;
Expand Down Expand Up @@ -177,6 +178,22 @@ public function testCustomHeader()
$this->assertEquals('bar', $payload['headers']['foo']);
}

public function testRemoteTemplate()
{
$email = (new RemoteTemplateEmail())
->template('d-12345', ['firstName' => 'Fabien']);
$envelope = new Envelope(new Address('alice@system.com'), [new Address('bob@system.com')]);

$transport = new SendgridApiTransport('ACCESS_KEY');
$method = new \ReflectionMethod(SendgridApiTransport::class, 'getPayload');
$payload = $method->invoke($transport, $email, $envelope);

$this->assertSame('d-12345', $payload['template_id']);
$this->assertSame(['firstName' => 'Fabien'], $payload['personalizations'][0]['dynamic_template_data']);
$this->assertArrayNotHasKey('content', $payload);
$this->assertArrayNotHasKey('subject', $payload['personalizations'][0]);
}

public function testReplyTo()
{
$from = 'from@example.com';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
use Symfony\Component\Mailer\Exception\TransportException;
use Symfony\Component\Mailer\Header\MetadataHeader;
use Symfony\Component\Mailer\Header\TagHeader;
use Symfony\Component\Mailer\RemoteTemplateEmail;
use Symfony\Component\Mailer\SentMessage;
use Symfony\Component\Mailer\Transport\AbstractApiTransport;
use Symfony\Component\Mailer\Transport\RemoteTemplateTransportInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use Symfony\Component\Mime\Header\DateHeader;
Expand All @@ -32,7 +34,7 @@
/**
* @author Kevin Verschaeve
*/
class SendgridApiTransport extends AbstractApiTransport
class SendgridApiTransport extends AbstractApiTransport implements RemoteTemplateTransportInterface
{
private const HOST = 'api.%region_dot%sendgrid.com';

Expand Down Expand Up @@ -91,20 +93,32 @@ private function getPayload(Email $email, Envelope $envelope): array
return $stringified;
};

$template = $email instanceof RemoteTemplateEmail ? $email->getRemoteTemplate() : null;

$payload = [
'personalizations' => [],
'from' => $addressStringifier($envelope->getSender()),
'content' => $this->getContent($email),
];

if (null !== $template) {
$payload['template_id'] = $template->getReference();
} else {
$payload['content'] = $this->getContent($email);
}

if ($email->getAttachments()) {
$payload['attachments'] = $this->getAttachments($email);
}

$personalization = [
'to' => array_map($addressStringifier, $this->getRecipients($email, $envelope)),
'subject' => $email->getSubject(),
];
if (null === $template || null !== $email->getSubject()) {
$personalization['subject'] = $email->getSubject();
}
if (null !== $template && $template->getVariables()) {
$personalization['dynamic_template_data'] = $template->getVariables();
}
if ($emails = array_map($addressStringifier, $email->getCc())) {
$personalization['cc'] = $emails;
}
Expand Down
2 changes: 1 addition & 1 deletion 2 src/Symfony/Component/Mailer/Bridge/Sendgrid/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
],
"require": {
"php": ">=8.4.1",
"symfony/mailer": "^7.4|^8.0"
"symfony/mailer": "^8.2"
},
"require-dev": {
"symfony/http-client": "^7.4|^8.0",
Expand Down
1 change: 1 addition & 0 deletions 1 src/Symfony/Component/Mailer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ CHANGELOG
8.2
---

* Add `RemoteTemplateEmail`, `RemoteTemplate` and `RemoteTemplateTransportInterface` to send emails rendered by the mail provider from a template hosted on its side
* Reorder EsmtpTransport authenticators to prefer PLAIN over obsolete LOGIN

8.0
Expand Down
Loading
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.