feature #32583 [Mailer] Logger vs debug mailer (fabpot)
This PR was squashed before being merged into the 4.4 branch (closes #32583). Discussion ---------- [Mailer] Logger vs debug mailer | Q | A | ------------- | --- | Branch? | 4.4 | Bug fix? | no | New feature? | yes | BC breaks? | no <!-- see https://symfony.com/bc --> | Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Tests pass? | yes <!-- please add some, will be required by reviewers --> | Fixed tickets | n/a | License | MIT | Doc PR | n/a Currently, there is no way to get the network data for the HTTP calls done by the HTTP transports (which makes debugging harder). For SMTP, we do have the network data, but as logs (each SMTP command/response is its own log line which means that the logs are "polluted" and the data is not tied with the sent message). This pull request adds a `getDebug()` method on `SentMessage`. That allows to get the debug data conveniently in a standardized way (for both SMTP and HTTP transports). I have moved the SMTP logs to this new mechanism and added support for HTTP transports. Commits -------fded3cd68c
[Mailer] added support ffor debug info when using SMTPd2f33d2cfe
[Mailer] added debug info for HTTP mailers
This commit is contained in:
commit
3849e1c238
@ -12,12 +12,13 @@
|
|||||||
namespace Symfony\Component\Mailer\Bridge\Amazon\Http\Api;
|
namespace Symfony\Component\Mailer\Bridge\Amazon\Http\Api;
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Component\Mailer\Exception\TransportException;
|
use Symfony\Component\Mailer\Exception\HttpTransportException;
|
||||||
use Symfony\Component\Mailer\SmtpEnvelope;
|
use Symfony\Component\Mailer\SmtpEnvelope;
|
||||||
use Symfony\Component\Mailer\Transport\Http\Api\AbstractApiTransport;
|
use Symfony\Component\Mailer\Transport\Http\Api\AbstractApiTransport;
|
||||||
use Symfony\Component\Mime\Email;
|
use Symfony\Component\Mime\Email;
|
||||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Kevin Verschaeve
|
* @author Kevin Verschaeve
|
||||||
@ -42,7 +43,7 @@ class SesTransport extends AbstractApiTransport
|
|||||||
parent::__construct($client, $dispatcher, $logger);
|
parent::__construct($client, $dispatcher, $logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function doSendEmail(Email $email, SmtpEnvelope $envelope): void
|
protected function doSendApi(Email $email, SmtpEnvelope $envelope): ResponseInterface
|
||||||
{
|
{
|
||||||
$date = gmdate('D, d M Y H:i:s e');
|
$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));
|
$auth = sprintf('AWS3-HTTPS AWSAccessKeyId=%s,Algorithm=HmacSHA256,Signature=%s', $this->accessKey, $this->getSignature($date));
|
||||||
@ -60,8 +61,10 @@ class SesTransport extends AbstractApiTransport
|
|||||||
if (200 !== $response->getStatusCode()) {
|
if (200 !== $response->getStatusCode()) {
|
||||||
$error = new \SimpleXMLElement($response->getContent(false));
|
$error = new \SimpleXMLElement($response->getContent(false));
|
||||||
|
|
||||||
throw new TransportException(sprintf('Unable to send an email: %s (code %s).', $error->Error->Message, $error->Error->Code));
|
throw new HttpTransportException(sprintf('Unable to send an email: %s (code %s).', $error->Error->Message, $error->Error->Code), $response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getSignature(string $string): string
|
private function getSignature(string $string): string
|
||||||
|
@ -12,11 +12,12 @@
|
|||||||
namespace Symfony\Component\Mailer\Bridge\Amazon\Http;
|
namespace Symfony\Component\Mailer\Bridge\Amazon\Http;
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Component\Mailer\Exception\TransportException;
|
use Symfony\Component\Mailer\Exception\HttpTransportException;
|
||||||
use Symfony\Component\Mailer\SentMessage;
|
use Symfony\Component\Mailer\SentMessage;
|
||||||
use Symfony\Component\Mailer\Transport\Http\AbstractHttpTransport;
|
use Symfony\Component\Mailer\Transport\Http\AbstractHttpTransport;
|
||||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Kevin Verschaeve
|
* @author Kevin Verschaeve
|
||||||
@ -41,7 +42,7 @@ class SesTransport extends AbstractHttpTransport
|
|||||||
parent::__construct($client, $dispatcher, $logger);
|
parent::__construct($client, $dispatcher, $logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function doSend(SentMessage $message): void
|
protected function doSendHttp(SentMessage $message): ResponseInterface
|
||||||
{
|
{
|
||||||
$date = gmdate('D, d M Y H:i:s e');
|
$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));
|
$auth = sprintf('AWS3-HTTPS AWSAccessKeyId=%s,Algorithm=HmacSHA256,Signature=%s', $this->accessKey, $this->getSignature($date));
|
||||||
@ -61,8 +62,10 @@ class SesTransport extends AbstractHttpTransport
|
|||||||
if (200 !== $response->getStatusCode()) {
|
if (200 !== $response->getStatusCode()) {
|
||||||
$error = new \SimpleXMLElement($response->getContent(false));
|
$error = new \SimpleXMLElement($response->getContent(false));
|
||||||
|
|
||||||
throw new TransportException(sprintf('Unable to send an email: %s (code %s).', $error->Error->Message, $error->Error->Code));
|
throw new HttpTransportException(sprintf('Unable to send an email: %s (code %s).', $error->Error->Message, $error->Error->Code), $response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getSignature(string $string): string
|
private function getSignature(string $string): string
|
||||||
|
@ -12,12 +12,13 @@
|
|||||||
namespace Symfony\Component\Mailer\Bridge\Mailchimp\Http\Api;
|
namespace Symfony\Component\Mailer\Bridge\Mailchimp\Http\Api;
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Component\Mailer\Exception\TransportException;
|
use Symfony\Component\Mailer\Exception\HttpTransportException;
|
||||||
use Symfony\Component\Mailer\SmtpEnvelope;
|
use Symfony\Component\Mailer\SmtpEnvelope;
|
||||||
use Symfony\Component\Mailer\Transport\Http\Api\AbstractApiTransport;
|
use Symfony\Component\Mailer\Transport\Http\Api\AbstractApiTransport;
|
||||||
use Symfony\Component\Mime\Email;
|
use Symfony\Component\Mime\Email;
|
||||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Kevin Verschaeve
|
* @author Kevin Verschaeve
|
||||||
@ -35,7 +36,7 @@ class MandrillTransport extends AbstractApiTransport
|
|||||||
parent::__construct($client, $dispatcher, $logger);
|
parent::__construct($client, $dispatcher, $logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function doSendEmail(Email $email, SmtpEnvelope $envelope): void
|
protected function doSendApi(Email $email, SmtpEnvelope $envelope): ResponseInterface
|
||||||
{
|
{
|
||||||
$response = $this->client->request('POST', self::ENDPOINT, [
|
$response = $this->client->request('POST', self::ENDPOINT, [
|
||||||
'json' => $this->getPayload($email, $envelope),
|
'json' => $this->getPayload($email, $envelope),
|
||||||
@ -44,11 +45,13 @@ class MandrillTransport extends AbstractApiTransport
|
|||||||
if (200 !== $response->getStatusCode()) {
|
if (200 !== $response->getStatusCode()) {
|
||||||
$result = $response->toArray(false);
|
$result = $response->toArray(false);
|
||||||
if ('error' === ($result['status'] ?? false)) {
|
if ('error' === ($result['status'] ?? false)) {
|
||||||
throw new TransportException(sprintf('Unable to send an email: %s (code %s).', $result['message'], $result['code']));
|
throw new HttpTransportException(sprintf('Unable to send an email: %s (code %s).', $result['message'], $result['code']), $response);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new TransportException(sprintf('Unable to send an email (code %s).', $result['code']));
|
throw new HttpTransportException(sprintf('Unable to send an email (code %s).', $result['code']), $response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getPayload(Email $email, SmtpEnvelope $envelope): array
|
private function getPayload(Email $email, SmtpEnvelope $envelope): array
|
||||||
|
@ -12,11 +12,12 @@
|
|||||||
namespace Symfony\Component\Mailer\Bridge\Mailchimp\Http;
|
namespace Symfony\Component\Mailer\Bridge\Mailchimp\Http;
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Component\Mailer\Exception\TransportException;
|
use Symfony\Component\Mailer\Exception\HttpTransportException;
|
||||||
use Symfony\Component\Mailer\SentMessage;
|
use Symfony\Component\Mailer\SentMessage;
|
||||||
use Symfony\Component\Mailer\Transport\Http\AbstractHttpTransport;
|
use Symfony\Component\Mailer\Transport\Http\AbstractHttpTransport;
|
||||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Kevin Verschaeve
|
* @author Kevin Verschaeve
|
||||||
@ -33,7 +34,7 @@ class MandrillTransport extends AbstractHttpTransport
|
|||||||
parent::__construct($client, $dispatcher, $logger);
|
parent::__construct($client, $dispatcher, $logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function doSend(SentMessage $message): void
|
protected function doSendHttp(SentMessage $message): ResponseInterface
|
||||||
{
|
{
|
||||||
$envelope = $message->getEnvelope();
|
$envelope = $message->getEnvelope();
|
||||||
$response = $this->client->request('POST', self::ENDPOINT, [
|
$response = $this->client->request('POST', self::ENDPOINT, [
|
||||||
@ -48,10 +49,12 @@ class MandrillTransport extends AbstractHttpTransport
|
|||||||
if (200 !== $response->getStatusCode()) {
|
if (200 !== $response->getStatusCode()) {
|
||||||
$result = $response->toArray(false);
|
$result = $response->toArray(false);
|
||||||
if ('error' === ($result['status'] ?? false)) {
|
if ('error' === ($result['status'] ?? false)) {
|
||||||
throw new TransportException(sprintf('Unable to send an email: %s (code %s).', $result['message'], $result['code']));
|
throw new HttpTransportException(sprintf('Unable to send an email: %s (code %s).', $result['message'], $result['code']), $response);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new TransportException(sprintf('Unable to send an email (code %s).', $result['code']));
|
throw new HttpTransportException(sprintf('Unable to send an email (code %s).', $result['code']), $response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,13 +12,14 @@
|
|||||||
namespace Symfony\Component\Mailer\Bridge\Mailgun\Http\Api;
|
namespace Symfony\Component\Mailer\Bridge\Mailgun\Http\Api;
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Component\Mailer\Exception\TransportException;
|
use Symfony\Component\Mailer\Exception\HttpTransportException;
|
||||||
use Symfony\Component\Mailer\SmtpEnvelope;
|
use Symfony\Component\Mailer\SmtpEnvelope;
|
||||||
use Symfony\Component\Mailer\Transport\Http\Api\AbstractApiTransport;
|
use Symfony\Component\Mailer\Transport\Http\Api\AbstractApiTransport;
|
||||||
use Symfony\Component\Mime\Email;
|
use Symfony\Component\Mime\Email;
|
||||||
use Symfony\Component\Mime\Part\Multipart\FormDataPart;
|
use Symfony\Component\Mime\Part\Multipart\FormDataPart;
|
||||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Kevin Verschaeve
|
* @author Kevin Verschaeve
|
||||||
@ -40,7 +41,7 @@ class MailgunTransport extends AbstractApiTransport
|
|||||||
parent::__construct($client, $dispatcher, $logger);
|
parent::__construct($client, $dispatcher, $logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function doSendEmail(Email $email, SmtpEnvelope $envelope): void
|
protected function doSendApi(Email $email, SmtpEnvelope $envelope): ResponseInterface
|
||||||
{
|
{
|
||||||
$body = new FormDataPart($this->getPayload($email, $envelope));
|
$body = new FormDataPart($this->getPayload($email, $envelope));
|
||||||
$headers = [];
|
$headers = [];
|
||||||
@ -58,8 +59,10 @@ class MailgunTransport extends AbstractApiTransport
|
|||||||
if (200 !== $response->getStatusCode()) {
|
if (200 !== $response->getStatusCode()) {
|
||||||
$error = $response->toArray(false);
|
$error = $response->toArray(false);
|
||||||
|
|
||||||
throw new TransportException(sprintf('Unable to send an email: %s (code %s).', $error['message'], $response->getStatusCode()));
|
throw new HttpTransportException(sprintf('Unable to send an email: %s (code %s).', $error['message'], $response->getStatusCode()), $response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getPayload(Email $email, SmtpEnvelope $envelope): array
|
private function getPayload(Email $email, SmtpEnvelope $envelope): array
|
||||||
|
@ -12,13 +12,14 @@
|
|||||||
namespace Symfony\Component\Mailer\Bridge\Mailgun\Http;
|
namespace Symfony\Component\Mailer\Bridge\Mailgun\Http;
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Component\Mailer\Exception\TransportException;
|
use Symfony\Component\Mailer\Exception\HttpTransportException;
|
||||||
use Symfony\Component\Mailer\SentMessage;
|
use Symfony\Component\Mailer\SentMessage;
|
||||||
use Symfony\Component\Mailer\Transport\Http\AbstractHttpTransport;
|
use Symfony\Component\Mailer\Transport\Http\AbstractHttpTransport;
|
||||||
use Symfony\Component\Mime\Part\DataPart;
|
use Symfony\Component\Mime\Part\DataPart;
|
||||||
use Symfony\Component\Mime\Part\Multipart\FormDataPart;
|
use Symfony\Component\Mime\Part\Multipart\FormDataPart;
|
||||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Kevin Verschaeve
|
* @author Kevin Verschaeve
|
||||||
@ -39,7 +40,7 @@ class MailgunTransport extends AbstractHttpTransport
|
|||||||
parent::__construct($client, $dispatcher, $logger);
|
parent::__construct($client, $dispatcher, $logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function doSend(SentMessage $message): void
|
protected function doSendHttp(SentMessage $message): ResponseInterface
|
||||||
{
|
{
|
||||||
$body = new FormDataPart([
|
$body = new FormDataPart([
|
||||||
'to' => implode(',', $this->stringifyAddresses($message->getEnvelope()->getRecipients())),
|
'to' => implode(',', $this->stringifyAddresses($message->getEnvelope()->getRecipients())),
|
||||||
@ -59,7 +60,9 @@ class MailgunTransport extends AbstractHttpTransport
|
|||||||
if (200 !== $response->getStatusCode()) {
|
if (200 !== $response->getStatusCode()) {
|
||||||
$error = $response->toArray(false);
|
$error = $response->toArray(false);
|
||||||
|
|
||||||
throw new TransportException(sprintf('Unable to send an email: %s (code %s).', $error['message'], $response->getStatusCode()));
|
throw new HttpTransportException(sprintf('Unable to send an email: %s (code %s).', $error['message'], $response->getStatusCode()), $response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,12 +12,13 @@
|
|||||||
namespace Symfony\Component\Mailer\Bridge\Postmark\Http\Api;
|
namespace Symfony\Component\Mailer\Bridge\Postmark\Http\Api;
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Component\Mailer\Exception\TransportException;
|
use Symfony\Component\Mailer\Exception\HttpTransportException;
|
||||||
use Symfony\Component\Mailer\SmtpEnvelope;
|
use Symfony\Component\Mailer\SmtpEnvelope;
|
||||||
use Symfony\Component\Mailer\Transport\Http\Api\AbstractApiTransport;
|
use Symfony\Component\Mailer\Transport\Http\Api\AbstractApiTransport;
|
||||||
use Symfony\Component\Mime\Email;
|
use Symfony\Component\Mime\Email;
|
||||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Kevin Verschaeve
|
* @author Kevin Verschaeve
|
||||||
@ -35,7 +36,7 @@ class PostmarkTransport extends AbstractApiTransport
|
|||||||
parent::__construct($client, $dispatcher, $logger);
|
parent::__construct($client, $dispatcher, $logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function doSendEmail(Email $email, SmtpEnvelope $envelope): void
|
protected function doSendApi(Email $email, SmtpEnvelope $envelope): ResponseInterface
|
||||||
{
|
{
|
||||||
$response = $this->client->request('POST', self::ENDPOINT, [
|
$response = $this->client->request('POST', self::ENDPOINT, [
|
||||||
'headers' => [
|
'headers' => [
|
||||||
@ -48,8 +49,10 @@ class PostmarkTransport extends AbstractApiTransport
|
|||||||
if (200 !== $response->getStatusCode()) {
|
if (200 !== $response->getStatusCode()) {
|
||||||
$error = $response->toArray(false);
|
$error = $response->toArray(false);
|
||||||
|
|
||||||
throw new TransportException(sprintf('Unable to send an email: %s (code %s).', $error['Message'], $error['ErrorCode']));
|
throw new HttpTransportException(sprintf('Unable to send an email: %s (code %s).', $error['Message'], $error['ErrorCode']), $response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getPayload(Email $email, SmtpEnvelope $envelope): array
|
private function getPayload(Email $email, SmtpEnvelope $envelope): array
|
||||||
|
@ -12,13 +12,14 @@
|
|||||||
namespace Symfony\Component\Mailer\Bridge\Sendgrid\Http\Api;
|
namespace Symfony\Component\Mailer\Bridge\Sendgrid\Http\Api;
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Component\Mailer\Exception\TransportException;
|
use Symfony\Component\Mailer\Exception\HttpTransportException;
|
||||||
use Symfony\Component\Mailer\SmtpEnvelope;
|
use Symfony\Component\Mailer\SmtpEnvelope;
|
||||||
use Symfony\Component\Mailer\Transport\Http\Api\AbstractApiTransport;
|
use Symfony\Component\Mailer\Transport\Http\Api\AbstractApiTransport;
|
||||||
use Symfony\Component\Mime\Address;
|
use Symfony\Component\Mime\Address;
|
||||||
use Symfony\Component\Mime\Email;
|
use Symfony\Component\Mime\Email;
|
||||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Kevin Verschaeve
|
* @author Kevin Verschaeve
|
||||||
@ -36,7 +37,7 @@ class SendgridTransport extends AbstractApiTransport
|
|||||||
parent::__construct($client, $dispatcher, $logger);
|
parent::__construct($client, $dispatcher, $logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function doSendEmail(Email $email, SmtpEnvelope $envelope): void
|
protected function doSendApi(Email $email, SmtpEnvelope $envelope): ResponseInterface
|
||||||
{
|
{
|
||||||
$response = $this->client->request('POST', self::ENDPOINT, [
|
$response = $this->client->request('POST', self::ENDPOINT, [
|
||||||
'json' => $this->getPayload($email, $envelope),
|
'json' => $this->getPayload($email, $envelope),
|
||||||
@ -46,8 +47,10 @@ class SendgridTransport extends AbstractApiTransport
|
|||||||
if (202 !== $response->getStatusCode()) {
|
if (202 !== $response->getStatusCode()) {
|
||||||
$errors = $response->toArray(false);
|
$errors = $response->toArray(false);
|
||||||
|
|
||||||
throw new TransportException(sprintf('Unable to send an email: %s (code %s).', implode('; ', array_column($errors['errors'], 'message')), $response->getStatusCode()));
|
throw new HttpTransportException(sprintf('Unable to send an email: %s (code %s).', implode('; ', array_column($errors['errors'], 'message')), $response->getStatusCode()), $response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getPayload(Email $email, SmtpEnvelope $envelope): array
|
private function getPayload(Email $email, SmtpEnvelope $envelope): array
|
||||||
|
@ -11,9 +11,24 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\Mailer\Exception;
|
namespace Symfony\Component\Mailer\Exception;
|
||||||
|
|
||||||
|
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Fabien Potencier <fabien@symfony.com>
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
*/
|
*/
|
||||||
class HttpTransportException extends TransportException
|
class HttpTransportException extends TransportException
|
||||||
{
|
{
|
||||||
|
private $response;
|
||||||
|
|
||||||
|
public function __construct(string $message = null, ResponseInterface $response, int $code = 0, \Exception $previous = null)
|
||||||
|
{
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
|
||||||
|
$this->response = $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResponse(): ResponseInterface
|
||||||
|
{
|
||||||
|
return $this->response;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ class SentMessage
|
|||||||
private $original;
|
private $original;
|
||||||
private $raw;
|
private $raw;
|
||||||
private $envelope;
|
private $envelope;
|
||||||
|
private $debug = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
@ -48,6 +49,16 @@ class SentMessage
|
|||||||
return $this->envelope;
|
return $this->envelope;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDebug(): string
|
||||||
|
{
|
||||||
|
return $this->debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function appendDebug(string $debug): void
|
||||||
|
{
|
||||||
|
$this->debug .= $debug;
|
||||||
|
}
|
||||||
|
|
||||||
public function toString(): string
|
public function toString(): string
|
||||||
{
|
{
|
||||||
return $this->raw->toString();
|
return $this->raw->toString();
|
||||||
|
@ -13,9 +13,12 @@ namespace Symfony\Component\Mailer\Transport\Http;
|
|||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Component\HttpClient\HttpClient;
|
use Symfony\Component\HttpClient\HttpClient;
|
||||||
|
use Symfony\Component\Mailer\Exception\HttpTransportException;
|
||||||
|
use Symfony\Component\Mailer\SentMessage;
|
||||||
use Symfony\Component\Mailer\Transport\AbstractTransport;
|
use Symfony\Component\Mailer\Transport\AbstractTransport;
|
||||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Victor Bocharsky <victor@symfonycasts.com>
|
* @author Victor Bocharsky <victor@symfonycasts.com>
|
||||||
@ -37,4 +40,22 @@ abstract class AbstractHttpTransport extends AbstractTransport
|
|||||||
|
|
||||||
parent::__construct($dispatcher, $logger);
|
parent::__construct($dispatcher, $logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract protected function doSendHttp(SentMessage $message): ResponseInterface;
|
||||||
|
|
||||||
|
protected function doSend(SentMessage $message): void
|
||||||
|
{
|
||||||
|
$response = null;
|
||||||
|
try {
|
||||||
|
$response = $this->doSendHttp($message);
|
||||||
|
} catch (HttpTransportException $e) {
|
||||||
|
$response = $e->getResponse();
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
} finally {
|
||||||
|
if (null !== $response) {
|
||||||
|
$message->appendDebug($response->getInfo('debug'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,42 +11,23 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\Mailer\Transport\Http\Api;
|
namespace Symfony\Component\Mailer\Transport\Http\Api;
|
||||||
|
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use Symfony\Component\HttpClient\HttpClient;
|
|
||||||
use Symfony\Component\Mailer\Exception\RuntimeException;
|
use Symfony\Component\Mailer\Exception\RuntimeException;
|
||||||
use Symfony\Component\Mailer\SentMessage;
|
use Symfony\Component\Mailer\SentMessage;
|
||||||
use Symfony\Component\Mailer\SmtpEnvelope;
|
use Symfony\Component\Mailer\SmtpEnvelope;
|
||||||
use Symfony\Component\Mailer\Transport\AbstractTransport;
|
use Symfony\Component\Mailer\Transport\Http\AbstractHttpTransport;
|
||||||
use Symfony\Component\Mime\Address;
|
use Symfony\Component\Mime\Address;
|
||||||
use Symfony\Component\Mime\Email;
|
use Symfony\Component\Mime\Email;
|
||||||
use Symfony\Component\Mime\MessageConverter;
|
use Symfony\Component\Mime\MessageConverter;
|
||||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Fabien Potencier <fabien@symfony.com>
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
*/
|
*/
|
||||||
abstract class AbstractApiTransport extends AbstractTransport
|
abstract class AbstractApiTransport extends AbstractHttpTransport
|
||||||
{
|
{
|
||||||
protected $client;
|
abstract protected function doSendApi(Email $email, SmtpEnvelope $envelope): ResponseInterface;
|
||||||
|
|
||||||
public function __construct(HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null)
|
protected function doSendHttp(SentMessage $message): ResponseInterface
|
||||||
{
|
|
||||||
$this->client = $client;
|
|
||||||
if (null === $client) {
|
|
||||||
if (!class_exists(HttpClient::class)) {
|
|
||||||
throw new \LogicException(sprintf('You cannot use "%s" as the HttpClient component is not installed. Try running "composer require symfony/http-client".', __CLASS__));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->client = HttpClient::create();
|
|
||||||
}
|
|
||||||
|
|
||||||
parent::__construct($dispatcher, $logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract protected function doSendEmail(Email $email, SmtpEnvelope $envelope): void;
|
|
||||||
|
|
||||||
protected function doSend(SentMessage $message): void
|
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$email = MessageConverter::toEmail($message->getOriginalMessage());
|
$email = MessageConverter::toEmail($message->getOriginalMessage());
|
||||||
@ -54,7 +35,7 @@ abstract class AbstractApiTransport extends AbstractTransport
|
|||||||
throw new RuntimeException(sprintf('Unable to send message with the "%s" transport: %s', __CLASS__, $e->getMessage()), 0, $e);
|
throw new RuntimeException(sprintf('Unable to send message with the "%s" transport: %s', __CLASS__, $e->getMessage()), 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->doSendEmail($email, $message->getEnvelope());
|
return $this->doSendApi($email, $message->getEnvelope());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getRecipients(Email $email, SmtpEnvelope $envelope): array
|
protected function getRecipients(Email $email, SmtpEnvelope $envelope): array
|
||||||
|
@ -135,7 +135,6 @@ class SmtpTransport extends AbstractTransport
|
|||||||
*/
|
*/
|
||||||
public function executeCommand(string $command, array $codes): string
|
public function executeCommand(string $command, array $codes): string
|
||||||
{
|
{
|
||||||
$this->getLogger()->debug(sprintf('Email transport "%s" sent command "%s"', __CLASS__, trim($command)));
|
|
||||||
$this->stream->write($command);
|
$this->stream->write($command);
|
||||||
$response = $this->getFullResponse();
|
$response = $this->getFullResponse();
|
||||||
$this->assertResponseCode($response, $codes);
|
$this->assertResponseCode($response, $codes);
|
||||||
@ -145,6 +144,7 @@ class SmtpTransport extends AbstractTransport
|
|||||||
|
|
||||||
protected function doSend(SentMessage $message): void
|
protected function doSend(SentMessage $message): void
|
||||||
{
|
{
|
||||||
|
try {
|
||||||
$envelope = $message->getEnvelope();
|
$envelope = $message->getEnvelope();
|
||||||
$this->doMailFromCommand($envelope->getSender()->toString());
|
$this->doMailFromCommand($envelope->getSender()->toString());
|
||||||
foreach ($envelope->getRecipients() as $recipient) {
|
foreach ($envelope->getRecipients() as $recipient) {
|
||||||
@ -153,10 +153,13 @@ class SmtpTransport extends AbstractTransport
|
|||||||
|
|
||||||
$this->executeCommand("DATA\r\n", [354]);
|
$this->executeCommand("DATA\r\n", [354]);
|
||||||
foreach (AbstractStream::replace("\r\n.", "\r\n..", $message->toIterable()) as $chunk) {
|
foreach (AbstractStream::replace("\r\n.", "\r\n..", $message->toIterable()) as $chunk) {
|
||||||
$this->stream->write($chunk);
|
$this->stream->write($chunk, false);
|
||||||
}
|
}
|
||||||
$this->stream->flush();
|
$this->stream->flush();
|
||||||
$this->executeCommand("\r\n.\r\n", [250]);
|
$this->executeCommand("\r\n.\r\n", [250]);
|
||||||
|
} finally {
|
||||||
|
$message->appendDebug($this->stream->getDebug());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function doHeloCommand(): void
|
protected function doHeloCommand(): void
|
||||||
@ -237,8 +240,6 @@ class SmtpTransport extends AbstractTransport
|
|||||||
list($code) = sscanf($response, '%3d');
|
list($code) = sscanf($response, '%3d');
|
||||||
$valid = \in_array($code, $codes);
|
$valid = \in_array($code, $codes);
|
||||||
|
|
||||||
$this->getLogger()->debug(sprintf('Email transport "%s" received response "%s" (%s).', __CLASS__, trim($response), $valid ? 'ok' : 'error'));
|
|
||||||
|
|
||||||
if (!$valid) {
|
if (!$valid) {
|
||||||
throw new TransportException(sprintf('Expected response code "%s" but got code "%s", with message "%s".', implode('/', $codes), $code, trim($response)), $code);
|
throw new TransportException(sprintf('Expected response code "%s" but got code "%s", with message "%s".', implode('/', $codes), $code, trim($response)), $code);
|
||||||
}
|
}
|
||||||
|
@ -28,8 +28,16 @@ abstract class AbstractStream
|
|||||||
protected $in;
|
protected $in;
|
||||||
protected $out;
|
protected $out;
|
||||||
|
|
||||||
public function write(string $bytes): void
|
private $debug = '';
|
||||||
|
|
||||||
|
public function write(string $bytes, $debug = true): void
|
||||||
{
|
{
|
||||||
|
if ($debug) {
|
||||||
|
foreach (explode("\n", trim($bytes)) as $line) {
|
||||||
|
$this->debug .= sprintf("> %s\n", $line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$bytesToWrite = \strlen($bytes);
|
$bytesToWrite = \strlen($bytes);
|
||||||
$totalBytesWritten = 0;
|
$totalBytesWritten = 0;
|
||||||
while ($totalBytesWritten < $bytesToWrite) {
|
while ($totalBytesWritten < $bytesToWrite) {
|
||||||
@ -74,9 +82,19 @@ abstract class AbstractStream
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->debug .= sprintf('< %s', $line);
|
||||||
|
|
||||||
return $line;
|
return $line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDebug(): string
|
||||||
|
{
|
||||||
|
$debug = $this->debug;
|
||||||
|
$this->debug = '';
|
||||||
|
|
||||||
|
return $debug;
|
||||||
|
}
|
||||||
|
|
||||||
public static function replace(string $from, string $to, iterable $chunks): \Generator
|
public static function replace(string $from, string $to, iterable $chunks): \Generator
|
||||||
{
|
{
|
||||||
if ('' === $from) {
|
if ('' === $from) {
|
||||||
|
Reference in New Issue
Block a user