diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesApiTransport.php b/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesApiTransport.php index bb58be6de3948..425154ccfd95d 100644 --- a/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesApiTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesApiTransport.php @@ -14,6 +14,7 @@ use Psr\Log\LoggerInterface; use Symfony\Component\Mailer\Envelope; use Symfony\Component\Mailer\Exception\HttpTransportException; +use Symfony\Component\Mailer\SentMessage; use Symfony\Component\Mailer\Transport\AbstractApiTransport; use Symfony\Component\Mime\Email; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; @@ -48,7 +49,7 @@ public function __toString(): string return sprintf('ses+api://%s@%s', $this->accessKey, $this->getEndpoint()); } - protected function doSendApi(Email $email, Envelope $envelope): ResponseInterface + protected function doSendApi(SentMessage $sentMessage, Email $email, Envelope $envelope): ResponseInterface { $date = gmdate('D, d M Y H:i:s e'); $auth = sprintf('AWS3-HTTPS AWSAccessKeyId=%s,Algorithm=HmacSHA256,Signature=%s', $this->accessKey, $this->getSignature($date)); @@ -62,12 +63,13 @@ protected function doSendApi(Email $email, Envelope $envelope): ResponseInterfac 'body' => $this->getPayload($email, $envelope), ]); + $result = new \SimpleXMLElement($response->getContent(false)); if (200 !== $response->getStatusCode()) { - $error = new \SimpleXMLElement($response->getContent(false)); - - throw new HttpTransportException(sprintf('Unable to send an email: %s (code %s).', $error->Error->Message, $error->Error->Code), $response); + throw new HttpTransportException(sprintf('Unable to send an email: %s (code %s).', $result->Error->Message, $result->Error->Code), $response); } + $sentMessage->setMessageId($result->SendEmailResult->MessageId); + return $response; } diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesHttpTransport.php b/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesHttpTransport.php index be828b0dfc9e8..3e89a7ee918a9 100644 --- a/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesHttpTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesHttpTransport.php @@ -63,12 +63,13 @@ protected function doSendHttp(SentMessage $message): ResponseInterface ], ]); + $result = new \SimpleXMLElement($response->getContent(false)); if (200 !== $response->getStatusCode()) { - $error = new \SimpleXMLElement($response->getContent(false)); - - throw new HttpTransportException(sprintf('Unable to send an email: %s (code %s).', $error->Error->Message, $error->Error->Code), $response); + throw new HttpTransportException(sprintf('Unable to send an email: %s (code %s).', $result->Error->Message, $result->Error->Code), $response); } + $message->setMessageId($result->SendEmailResult->MessageId); + return $response; } diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillApiTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillApiTransport.php index fac041e43e3fb..f28be018be90f 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillApiTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillApiTransport.php @@ -14,6 +14,7 @@ use Psr\Log\LoggerInterface; use Symfony\Component\Mailer\Envelope; use Symfony\Component\Mailer\Exception\HttpTransportException; +use Symfony\Component\Mailer\SentMessage; use Symfony\Component\Mailer\Transport\AbstractApiTransport; use Symfony\Component\Mime\Email; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; @@ -41,14 +42,14 @@ public function __toString(): string return sprintf('mandrill+api://%s', $this->getEndpoint()); } - protected function doSendApi(Email $email, Envelope $envelope): ResponseInterface + protected function doSendApi(SentMessage $sentMessage, Email $email, Envelope $envelope): ResponseInterface { $response = $this->client->request('POST', 'https://'.$this->getEndpoint().'/api/1.0/messages/send.json', [ 'json' => $this->getPayload($email, $envelope), ]); + $result = $response->toArray(false); if (200 !== $response->getStatusCode()) { - $result = $response->toArray(false); if ('error' === ($result['status'] ?? false)) { throw new HttpTransportException(sprintf('Unable to send an email: %s (code %s).', $result['message'], $result['code']), $response); } @@ -56,6 +57,8 @@ protected function doSendApi(Email $email, Envelope $envelope): ResponseInterfac throw new HttpTransportException(sprintf('Unable to send an email (code %s).', $result['code']), $response); } + $sentMessage->setMessageId($result['_id']); + return $response; } diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillHttpTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillHttpTransport.php index cec26aaf03d0b..2c90472fc6dc6 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillHttpTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillHttpTransport.php @@ -51,8 +51,8 @@ protected function doSendHttp(SentMessage $message): ResponseInterface ], ]); + $result = $response->toArray(false); if (200 !== $response->getStatusCode()) { - $result = $response->toArray(false); if ('error' === ($result['status'] ?? false)) { throw new HttpTransportException(sprintf('Unable to send an email: %s (code %s).', $result['message'], $result['code']), $response); } @@ -60,6 +60,8 @@ protected function doSendHttp(SentMessage $message): ResponseInterface throw new HttpTransportException(sprintf('Unable to send an email (code %s).', $result['code']), $response); } + $message->setMessageId($result['_id']); + return $response; } diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunApiTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunApiTransport.php index 0dd6f247f231d..8d7b5cc7e28be 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunApiTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunApiTransport.php @@ -14,6 +14,7 @@ use Psr\Log\LoggerInterface; use Symfony\Component\Mailer\Envelope; use Symfony\Component\Mailer\Exception\HttpTransportException; +use Symfony\Component\Mailer\SentMessage; use Symfony\Component\Mailer\Transport\AbstractApiTransport; use Symfony\Component\Mime\Email; use Symfony\Component\Mime\Part\Multipart\FormDataPart; @@ -46,7 +47,7 @@ public function __toString(): string return sprintf('mailgun+api://%s?domain=%s', $this->getEndpoint(), $this->domain); } - protected function doSendApi(Email $email, Envelope $envelope): ResponseInterface + protected function doSendApi(SentMessage $sentMessage, Email $email, Envelope $envelope): ResponseInterface { $body = new FormDataPart($this->getPayload($email, $envelope)); $headers = []; @@ -61,14 +62,17 @@ protected function doSendApi(Email $email, Envelope $envelope): ResponseInterfac 'body' => $body->bodyToIterable(), ]); + $result = $response->toArray(false); if (200 !== $response->getStatusCode()) { if ('application/json' === $response->getHeaders(false)['content-type'][0]) { - throw new HttpTransportException(sprintf('Unable to send an email: %s (code %s).', $response->toArray(false)['message'], $response->getStatusCode()), $response); + throw new HttpTransportException(sprintf('Unable to send an email: %s (code %s).', $result['message'], $response->getStatusCode()), $response); } throw new HttpTransportException(sprintf('Unable to send an email: %s (code %s).', $response->getContent(false), $response->getStatusCode()), $response); } + $sentMessage->setMessageId($result['id']); + return $response; } diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunHttpTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunHttpTransport.php index b9b35fade5259..a42598a0b54ce 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunHttpTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunHttpTransport.php @@ -64,14 +64,17 @@ protected function doSendHttp(SentMessage $message): ResponseInterface 'body' => $body->bodyToIterable(), ]); + $result = $response->toArray(false); if (200 !== $response->getStatusCode()) { if ('application/json' === $response->getHeaders(false)['content-type'][0]) { - throw new HttpTransportException(sprintf('Unable to send an email: %s (code %s).', $response->toArray(false)['message'], $response->getStatusCode()), $response); + throw new HttpTransportException(sprintf('Unable to send an email: %s (code %s).', $result['message'], $response->getStatusCode()), $response); } throw new HttpTransportException(sprintf('Unable to send an email: %s (code %s).', $response->getContent(false), $response->getStatusCode()), $response); } + $message->setMessageId($result['id']); + return $response; } diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkApiTransport.php b/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkApiTransport.php index 79d0c6c87dc6b..96dd8d4a65f3f 100644 --- a/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkApiTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkApiTransport.php @@ -14,6 +14,7 @@ use Psr\Log\LoggerInterface; use Symfony\Component\Mailer\Envelope; use Symfony\Component\Mailer\Exception\HttpTransportException; +use Symfony\Component\Mailer\SentMessage; use Symfony\Component\Mailer\Transport\AbstractApiTransport; use Symfony\Component\Mime\Email; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; @@ -41,7 +42,7 @@ public function __toString(): string return sprintf('postmark+api://%s', $this->getEndpoint()); } - protected function doSendApi(Email $email, Envelope $envelope): ResponseInterface + protected function doSendApi(SentMessage $sentMessage, Email $email, Envelope $envelope): ResponseInterface { $response = $this->client->request('POST', 'https://'.$this->getEndpoint().'/email', [ 'headers' => [ @@ -51,12 +52,13 @@ protected function doSendApi(Email $email, Envelope $envelope): ResponseInterfac 'json' => $this->getPayload($email, $envelope), ]); + $result = $response->toArray(false); if (200 !== $response->getStatusCode()) { - $error = $response->toArray(false); - - throw new HttpTransportException(sprintf('Unable to send an email: %s (code %s).', $error['Message'], $error['ErrorCode']), $response); + throw new HttpTransportException(sprintf('Unable to send an email: %s (code %s).', $result['Message'], $result['ErrorCode']), $response); } + $sentMessage->setMessageId($result['MessageID']); + return $response; } diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkSmtpTransport.php b/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkSmtpTransport.php index 395b638c569ca..b6d9ba2827501 100644 --- a/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkSmtpTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkSmtpTransport.php @@ -12,7 +12,11 @@ namespace Symfony\Component\Mailer\Bridge\Postmark\Transport; use Psr\Log\LoggerInterface; +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\SentMessage; use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\RawMessage; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** @@ -27,4 +31,13 @@ public function __construct(string $id, EventDispatcherInterface $dispatcher = n $this->setUsername($id); $this->setPassword($id); } + + public function send(RawMessage $message, Envelope $envelope = null): ?SentMessage + { + if ($message instanceof Message) { + $message->getHeaders()->addTextHeader('X-PM-KeepID', 'true'); + } + + return parent::send($message, $envelope); + } } diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Transport/SendgridApiTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Transport/SendgridApiTransportTest.php index 301824684ba93..9ad5c280ecbad 100644 --- a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Transport/SendgridApiTransportTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Transport/SendgridApiTransportTest.php @@ -59,6 +59,10 @@ public function testSend() ->expects($this->once()) ->method('getStatusCode') ->willReturn(202); + $response + ->expects($this->once()) + ->method('getHeaders') + ->willReturn(['x-message-id' => '1']); $httpClient = $this->createMock(HttpClientInterface::class); diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridApiTransport.php b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridApiTransport.php index 1c722094ccd98..262983afd73fd 100644 --- a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridApiTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridApiTransport.php @@ -14,6 +14,7 @@ use Psr\Log\LoggerInterface; use Symfony\Component\Mailer\Envelope; use Symfony\Component\Mailer\Exception\HttpTransportException; +use Symfony\Component\Mailer\SentMessage; use Symfony\Component\Mailer\Transport\AbstractApiTransport; use Symfony\Component\Mime\Address; use Symfony\Component\Mime\Email; @@ -42,7 +43,7 @@ public function __toString(): string return sprintf('sendgrid+api://%s', $this->getEndpoint()); } - protected function doSendApi(Email $email, Envelope $envelope): ResponseInterface + protected function doSendApi(SentMessage $sentMessage, Email $email, Envelope $envelope): ResponseInterface { $response = $this->client->request('POST', 'https://'.$this->getEndpoint().'/v3/mail/send', [ 'json' => $this->getPayload($email, $envelope), @@ -55,6 +56,8 @@ protected function doSendApi(Email $email, Envelope $envelope): ResponseInterfac throw new HttpTransportException(sprintf('Unable to send an email: %s (code %s).', implode('; ', array_column($errors['errors'], 'message')), $response->getStatusCode()), $response); } + $sentMessage->setMessageId($response->getHeaders(false)['x-message-id'][0]); + return $response; } diff --git a/src/Symfony/Component/Mailer/SentMessage.php b/src/Symfony/Component/Mailer/SentMessage.php index 94354f944df5d..1a12d078e726f 100644 --- a/src/Symfony/Component/Mailer/SentMessage.php +++ b/src/Symfony/Component/Mailer/SentMessage.php @@ -22,6 +22,7 @@ class SentMessage private $original; private $raw; private $envelope; + private $messageId; private $debug = ''; /** @@ -31,9 +32,20 @@ public function __construct(RawMessage $message, Envelope $envelope) { $message->ensureValidity(); - $this->raw = $message instanceof Message ? new RawMessage($message->toIterable()) : $message; $this->original = $message; $this->envelope = $envelope; + + if ($message instanceof Message) { + $message = clone $message; + $headers = $message->getHeaders(); + if (!$headers->has('Message-ID')) { + $headers->addIdHeader('Message-ID', $message->generateMessageId()); + } + $this->messageId = $headers->get('Message-ID')->getId(); + $this->raw = new RawMessage($message->toIterable()); + } else { + $this->raw = $message; + } } public function getMessage(): RawMessage @@ -51,6 +63,16 @@ public function getEnvelope(): Envelope return $this->envelope; } + public function setMessageId(string $id): void + { + $this->messageId = $id; + } + + public function getMessageId(): string + { + return $this->messageId; + } + public function getDebug(): string { return $this->debug; diff --git a/src/Symfony/Component/Mailer/Transport/AbstractApiTransport.php b/src/Symfony/Component/Mailer/Transport/AbstractApiTransport.php index 25cc61e7c6100..03810e51b1de2 100644 --- a/src/Symfony/Component/Mailer/Transport/AbstractApiTransport.php +++ b/src/Symfony/Component/Mailer/Transport/AbstractApiTransport.php @@ -24,7 +24,7 @@ */ abstract class AbstractApiTransport extends AbstractHttpTransport { - abstract protected function doSendApi(Email $email, Envelope $envelope): ResponseInterface; + abstract protected function doSendApi(SentMessage $sentMessage, Email $email, Envelope $envelope): ResponseInterface; protected function doSendHttp(SentMessage $message): ResponseInterface { @@ -34,7 +34,7 @@ protected function doSendHttp(SentMessage $message): ResponseInterface throw new RuntimeException(sprintf('Unable to send message with the "%s" transport: %s', __CLASS__, $e->getMessage()), 0, $e); } - return $this->doSendApi($email, $message->getEnvelope()); + return $this->doSendApi($message, $email, $message->getEnvelope()); } protected function getRecipients(Email $email, Envelope $envelope): array diff --git a/src/Symfony/Component/Mime/Message.php b/src/Symfony/Component/Mime/Message.php index d92717730290a..5b4e67f1dbc5b 100644 --- a/src/Symfony/Component/Mime/Message.php +++ b/src/Symfony/Component/Mime/Message.php @@ -32,9 +32,7 @@ public function __construct(Headers $headers = null, AbstractPart $body = null) public function __clone() { - if (null !== $this->headers) { - $this->headers = clone $this->headers; - } + $this->headers = clone $this->headers; if (null !== $this->body) { $this->body = clone $this->body; @@ -86,16 +84,12 @@ public function getPreparedHeaders(): Headers } // determine the "real" sender - $senders = $headers->get('From')->getAddresses(); - $sender = $senders[0]; - if ($headers->has('Sender')) { - $sender = $headers->get('Sender')->getAddress(); - } elseif (\count($senders) > 1) { - $headers->addMailboxHeader('Sender', $sender); + if (!$headers->has('Sender') && \count($froms = $headers->get('From')->getAddresses()) > 1) { + $headers->addMailboxHeader('Sender', $froms[0]); } if (!$headers->has('Message-ID')) { - $headers->addIdHeader('Message-ID', $this->generateMessageId($sender->getAddress())); + $headers->addIdHeader('Message-ID', $this->generateMessageId()); } // remove the Bcc field which should NOT be part of the sent message @@ -132,9 +126,17 @@ public function ensureValidity() parent::ensureValidity(); } - private function generateMessageId(string $email): string + public function generateMessageId(): string { - return bin2hex(random_bytes(16)).strstr($email, '@'); + if ($this->headers->has('Sender')) { + $sender = $this->headers->get('Sender')->getAddress(); + } elseif ($this->headers->has('From')) { + $sender = $this->headers->get('From')->getAddresses()[0]; + } else { + throw new LogicException('An email must have a "From" or a "Sender" header to compute a Messsage ID.'); + } + + return bin2hex(random_bytes(16)).strstr($sender->getAddress(), '@'); } public function __serialize(): array
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: