Skip to content

Commit 50ac018

Browse files
author
Mickael GOETZ
committed
[Mailer][SendGrid] add support for scheduling delivery via send_at API parameter
1 parent 96120e6 commit 50ac018

File tree

4 files changed

+37
-1
lines changed

4 files changed

+37
-1
lines changed

src/Symfony/Component/Mailer/Bridge/Sendgrid/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
---
66

77
* Add support for webhooks
8+
* Add support for scheduling delivery with the `send_at` API parameter via a `Send-At` date-header.
89

910
5.4
1011
---

src/Symfony/Component/Mailer/Bridge/Sendgrid/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,20 @@ class SendGridConsumer implements ConsumerInterface
4444
}
4545
```
4646

47+
Scheduling
48+
----------
49+
50+
When using the **API transport** (with a `sendgrid+api` DSN), you can schedule
51+
email your emails by providing a `\DateTimeInterface` object in a
52+
`Symfony\Component\Mime\Header\DateHeader` named `Send-At`.
53+
54+
```php
55+
$email = new \Symfony\Component\Mime\Email();
56+
$email->getHeaders()->addDateHeader('Send-At', (new \DateTime())->modify('+3 hours'));
57+
```
58+
It will be mapped to the `send_at` parameter of the `[POST] /mail/send`
59+
[API endpoint](https://www.twilio.com/docs/sendgrid/api-reference/mail-send/mail-send#request-body)
60+
4761
Resources
4862
---------
4963

src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Transport/SendgridApiTransportTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,4 +286,18 @@ public function testInlineWithoutCustomContentId()
286286

287287
$this->assertSame('text.txt', $payload['attachments'][0]['content_id']);
288288
}
289+
290+
public function testSendAtHeader()
291+
{
292+
$email = new Email();
293+
$email->getHeaders()->addDateHeader('Send-At', new \DateTime('2025-05-07 16:00:00', new \DateTimeZone('Europe/Paris')));
294+
$envelope = new Envelope(new Address('alice@system.com'), [new Address('bob@system.com')]);
295+
296+
$transport = new SendgridApiTransport('ACCESS_KEY');
297+
$method = new \ReflectionMethod(SendgridApiTransport::class, 'getPayload');
298+
$payload = $method->invoke($transport, $email, $envelope);
299+
300+
$this->assertArrayHasKey('send_at', $payload);
301+
$this->assertEquals(1746626400, $payload['send_at']);
302+
}
289303
}

src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridApiTransport.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use Symfony\Component\Mailer\Transport\AbstractApiTransport;
2323
use Symfony\Component\Mime\Address;
2424
use Symfony\Component\Mime\Email;
25+
use Symfony\Component\Mime\Header\DateHeader;
2526
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
2627
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
2728
use Symfony\Contracts\HttpClient\HttpClientInterface;
@@ -125,7 +126,13 @@ private function getPayload(Email $email, Envelope $envelope): array
125126
continue;
126127
}
127128

128-
if ($header instanceof TagHeader) {
129+
if ($name === 'send-at') {
130+
if (!$header instanceof DateHeader) {
131+
throw new TransportException(sprintf('The Send-At header should be a "%s" instance to deduce the correct timestamp.', DateHeader::class));
132+
}
133+
// the documentation shows parameter names in camelCase but the expected JSON keys should be in snake_case
134+
$payload['send_at'] = $header->getDateTime()->getTimestamp();
135+
} elseif ($header instanceof TagHeader) {
129136
if (10 === \count($categories)) {
130137
throw new TransportException(sprintf('Too many "%s" instances present in the email headers. Sendgrid does not accept more than 10 categories on an email.', TagHeader::class));
131138
}

0 commit comments

Comments
 (0)