* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Mailer\Bridge\Mailgun\RemoteEvent; use Symfony\Component\RemoteEvent\Event\Mailer\AbstractMailerEvent; use Symfony\Component\RemoteEvent\Event\Mailer\MailerDeliveryEvent; use Symfony\Component\RemoteEvent\Event\Mailer\MailerEngagementEvent; use Symfony\Component\RemoteEvent\Exception\ParseException; use Symfony\Component\RemoteEvent\PayloadConverterInterface; final class MailgunPayloadConverter implements PayloadConverterInterface { private const MAILGUN_SPECIFIC_DROPPED_CODES = [ 605, // Not delivering to previously bounced address 606, // Not delivering to unsubscribed address 607, // Not delivering to a user who marked your messages as spam 625, // Poor mailing list quality ]; public function convert(array $payload): AbstractMailerEvent { if (\in_array($payload['event'], ['accepted', 'rejected', 'delivered', 'failed', 'blocked'], true)) { $name = match ($payload['event']) { 'accepted' => MailerDeliveryEvent::RECEIVED, 'rejected' => MailerDeliveryEvent::DROPPED, 'delivered' => MailerDeliveryEvent::DELIVERED, 'blocked' => MailerDeliveryEvent::DROPPED, 'failed' => $this->matchFailedEvent($payload), }; $event = new MailerDeliveryEvent($name, $payload['id'], $payload); // reason is only available on failed messages $event->setReason($this->getReason($payload)); } else { $name = match ($payload['event']) { 'clicked' => MailerEngagementEvent::CLICK, 'unsubscribed' => MailerEngagementEvent::UNSUBSCRIBE, 'opened' => MailerEngagementEvent::OPEN, 'complained' => MailerEngagementEvent::SPAM, default => throw new ParseException(\sprintf('Unsupported event "%s".', $payload['event'])), }; $event = new MailerEngagementEvent($name, $payload['id'], $payload); } if (!$date = \DateTimeImmutable::createFromFormat('U.u', \sprintf('%.6F', $payload['timestamp']))) { throw new ParseException(\sprintf('Invalid date "%s".', \sprintf('%.6F', $payload['timestamp']))); } $event->setDate($date); $event->setRecipientEmail($payload['recipient']); $event->setMetadata($payload['user-variables'] ?? []); $event->setTags($payload['tags'] ?? []); return $event; } private function matchFailedEvent(array $payload): string { if ('temporary' === $payload['severity']) { return MailerDeliveryEvent::DEFERRED; } if (\in_array($payload['delivery-status']['code'], self::MAILGUN_SPECIFIC_DROPPED_CODES, true)) { return MailerDeliveryEvent::DROPPED; } return MailerDeliveryEvent::BOUNCE; } private function getReason(array $payload): string { if ('' !== ($payload['delivery-status']['description'] ?? '')) { return $payload['delivery-status']['description']; } if ('' !== ($payload['delivery-status']['message'] ?? '')) { return $payload['delivery-status']['message']; } if ('' !== ($payload['reason'] ?? '')) { return $payload['reason']; } return ''; } }