Replace Swift_message with PHPMailer

[MAILPOET-4142]
This commit is contained in:
Jan Lysý
2022-05-11 09:37:00 +02:00
committed by Veljko V
parent d7582ede37
commit 0186ddee35
3 changed files with 64 additions and 83 deletions

View File

@ -1,4 +1,4 @@
<?php <?php declare(strict_types = 1);
namespace MailPoet\Mailer\Methods; namespace MailPoet\Mailer\Methods;
@ -6,24 +6,34 @@ use MailPoet\Mailer\Mailer;
use MailPoet\Mailer\Methods\Common\BlacklistCheck; use MailPoet\Mailer\Methods\Common\BlacklistCheck;
use MailPoet\Mailer\Methods\ErrorMappers\AmazonSESMapper; use MailPoet\Mailer\Methods\ErrorMappers\AmazonSESMapper;
use MailPoet\WP\Functions as WPFunctions; use MailPoet\WP\Functions as WPFunctions;
use MailPoetVendor\Swift_Message; use PHPMailer\PHPMailer\PHPMailer;
class AmazonSES implements MailerMethod { class AmazonSES extends PHPMailerMethod {
/** @var string */
public $awsAccessKey; public $awsAccessKey;
/** @var string */
public $awsSecretKey; public $awsSecretKey;
/** @var string */
public $awsRegion; public $awsRegion;
/** @var string */
public $awsEndpoint; public $awsEndpoint;
/** @var string */
public $awsSigningAlgorithm; public $awsSigningAlgorithm;
/** @var string */
public $awsService; public $awsService;
/** @var string */
public $awsTerminationString; public $awsTerminationString;
/** @var string */
public $hashAlgorithm; public $hashAlgorithm;
/** @var string */
public $url; public $url;
public $sender; /** @var string */
public $replyTo; public $rawMessage;
public $returnPath; /** @var string */
public $message;
public $date; public $date;
/** @var string */
public $dateWithoutTime; public $dateWithoutTime;
/** @var string[] */
private $availableRegions = [ private $availableRegions = [
'US East (N. Virginia)' => 'us-east-1', 'US East (N. Virginia)' => 'us-east-1',
'US East (Ohio)' => 'us-east-2', 'US East (Ohio)' => 'us-east-2',
@ -51,14 +61,10 @@ class AmazonSES implements MailerMethod {
'South America (Sao Paulo)' => 'sa-east-1', 'South America (Sao Paulo)' => 'sa-east-1',
'AWS GovCloud (US)' => 'us-gov-west-1', 'AWS GovCloud (US)' => 'us-gov-west-1',
]; ];
/** @var AmazonSESMapper */ /** @var AmazonSESMapper */
private $errorMapper; protected $errorMapper;
/** @var WPFunctions */
/** @var BlacklistCheck */ protected $wp;
private $blacklist;
private $wp;
public function __construct( public function __construct(
$region, $region,
@ -89,6 +95,7 @@ class AmazonSES implements MailerMethod {
$this->errorMapper = $errorMapper; $this->errorMapper = $errorMapper;
$this->wp = new WPFunctions(); $this->wp = new WPFunctions();
$this->blacklist = new BlacklistCheck(); $this->blacklist = new BlacklistCheck();
$this->mailer = $this->buildMailer();
} }
public function send($newsletter, $subscriber, $extraParams = []): array { public function send($newsletter, $subscriber, $extraParams = []): array {
@ -117,57 +124,26 @@ class AmazonSES implements MailerMethod {
return Mailer::formatMailerSendSuccessResult(); return Mailer::formatMailerSendSuccessResult();
} }
public function buildMailer(): PHPMailer {
return new PHPMailer(true);
}
public function getBody($newsletter, $subscriber, $extraParams = []) { public function getBody($newsletter, $subscriber, $extraParams = []) {
$this->message = $this->createMessage($newsletter, $subscriber, $extraParams); /* Configure mailer and call preSend() method to prepare message */
$body = [ $mailer = $this->configureMailerWithMessage($newsletter, $subscriber, $extraParams);
$mailer->preSend();
/* When message is prepared, we can get the raw message */
$this->rawMessage = $mailer->getSentMIMEMessage();
return [
'Action' => 'SendRawEmail', 'Action' => 'SendRawEmail',
'Version' => '2010-12-01', 'Version' => '2010-12-01',
'Source' => $this->sender['from_name_email'], 'Source' => $this->sender['from_name_email'],
'RawMessage.Data' => $this->encodeMessage($this->message), 'RawMessage.Data' => $this->encodeMessage($this->rawMessage),
]; ];
return $body;
} }
public function createMessage($newsletter, $subscriber, $extraParams = []) { public function encodeMessage(string $message) {
$message = (new Swift_Message()) return base64_encode($message);
->setTo($this->processSubscriber($subscriber))
->setFrom([
$this->sender['from_email'] => $this->sender['from_name'],
])
->setSender($this->sender['from_email'])
->setReplyTo([
$this->replyTo['reply_to_email'] => $this->replyTo['reply_to_name'],
])
->setReturnPath($this->returnPath)
->setSubject($newsletter['subject']);
if (!empty($extraParams['unsubscribe_url'])) {
$headers = $message->getHeaders();
$headers->addTextHeader('List-Unsubscribe', '<' . $extraParams['unsubscribe_url'] . '>');
}
if (!empty($newsletter['body']['html'])) {
$message = $message->setBody($newsletter['body']['html'], 'text/html');
}
if (!empty($newsletter['body']['text'])) {
$message = $message->addPart($newsletter['body']['text'], 'text/plain');
}
return $message;
}
public function encodeMessage(Swift_Message $message) {
return base64_encode($message->toString());
}
public function processSubscriber($subscriber) {
preg_match('!(?P<name>.*?)\s<(?P<email>.*?)>!', $subscriber, $subscriberData);
if (!isset($subscriberData['email'])) {
$subscriberData = [
'email' => $subscriber,
];
}
return [
$subscriberData['email'] =>
(isset($subscriberData['name'])) ? $subscriberData['name'] : '',
];
} }
public function request($newsletter, $subscriber, $extraParams = []) { public function request($newsletter, $subscriber, $extraParams = []) {

View File

@ -1,4 +1,4 @@
<?php <?php declare(strict_types = 1);
namespace MailPoet\Mailer\Methods\ErrorMappers; namespace MailPoet\Mailer\Methods\ErrorMappers;
@ -6,7 +6,6 @@ use MailPoet\Mailer\Mailer;
use MailPoet\Mailer\MailerError; use MailPoet\Mailer\MailerError;
use MailPoet\Mailer\SubscriberError; use MailPoet\Mailer\SubscriberError;
use MailPoet\WP\Functions as WPFunctions; use MailPoet\WP\Functions as WPFunctions;
use MailPoetVendor\Swift_RfcComplianceException;
class AmazonSESMapper { class AmazonSESMapper {
use BlacklistErrorMapperTrait; use BlacklistErrorMapperTrait;
@ -16,7 +15,7 @@ class AmazonSESMapper {
public function getErrorFromException(\Exception $e, $subscriber) { public function getErrorFromException(\Exception $e, $subscriber) {
$level = MailerError::LEVEL_HARD; $level = MailerError::LEVEL_HARD;
if ($e instanceof Swift_RfcComplianceException) { if (strpos($e->getMessage(), 'Invalid address') !== false && strpos($e->getMessage(), '(to):') !== false) {
$level = MailerError::LEVEL_SOFT; $level = MailerError::LEVEL_SOFT;
} }
$subscriberErrors = [new SubscriberError($subscriber, null)]; $subscriberErrors = [new SubscriberError($subscriber, null)];

View File

@ -1,4 +1,4 @@
<?php <?php declare(strict_types = 1);
namespace MailPoet\Test\Mailer\Methods; namespace MailPoet\Test\Mailer\Methods;
@ -102,34 +102,40 @@ class AmazonSESTest extends \MailPoetTest {
expect($body['Version'])->equals('2010-12-01'); expect($body['Version'])->equals('2010-12-01');
expect($body['Source'])->equals($this->sender['from_name_email']); expect($body['Source'])->equals($this->sender['from_name_email']);
expect($body['RawMessage.Data']) expect($body['RawMessage.Data'])
->equals($this->mailer->encodeMessage($this->mailer->message)); ->equals($this->mailer->encodeMessage($this->mailer->rawMessage));
} }
public function testItCanCreateMessage() { public function testItCanCreateMessage() {
$message = $this->mailer $mailer = $this->mailer->configureMailerWithMessage($this->newsletter, $this->subscriber, $this->extraParams);
->createMessage($this->newsletter, $this->subscriber, $this->extraParams); expect($mailer->CharSet)->equals('UTF-8'); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
expect($message->getTo()) expect($mailer->getToAddresses())->equals([[
->equals(['blackhole@mailpoet.com' => 'Recipient']); 'blackhole@mailpoet.com',
expect($message->getFrom()) 'Recipient',
->equals([$this->sender['from_email'] => $this->sender['from_name']]); ]]);
expect($message->getSender()) expect($mailer->getAllRecipientAddresses())->equals(['blackhole@mailpoet.com' => true]);
->equals([$this->sender['from_email'] => null]); expect($mailer->From)->equals($this->sender['from_email']); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
expect($message->getReplyTo()) expect($mailer->FromName)->equals($this->sender['from_name']); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
->equals([$this->replyTo['reply_to_email'] => $this->replyTo['reply_to_name']]); expect($mailer->getReplyToAddresses())->equals([
expect($message->getSubject()) $this->replyTo['reply_to_email'] => [
->equals($this->newsletter['subject']); $this->replyTo['reply_to_email'],
expect($message->getBody()) $this->replyTo['reply_to_name'],
->equals($this->newsletter['body']['html']); ],
expect($message->getChildren()[0]->getContentType()) ]);
->equals('text/plain'); expect($mailer->Sender)->equals($this->returnPath); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
expect($message->getHeaders()->get('List-Unsubscribe')->getValue()) expect($mailer->ContentType)->equals('text/html'); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
->equals('<' . $this->extraParams['unsubscribe_url'] . '>'); expect($mailer->Subject)->equals($this->newsletter['subject']); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
expect($mailer->Body)->equals($this->newsletter['body']['html']); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
expect($mailer->AltBody)->equals($this->newsletter['body']['text']); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
expect($mailer->getCustomHeaders())->equals([[
'List-Unsubscribe',
'<http://www.mailpoet.com>',
]]);
} }
public function testItCanCreateRequest() { public function testItCanCreateRequest() {
$request = $this->mailer->request($this->newsletter, $this->subscriber); $request = $this->mailer->request($this->newsletter, $this->subscriber);
// preserve the original message // preserve the original message
$rawMessage = $this->mailer->encodeMessage($this->mailer->message); $rawMessage = $this->mailer->encodeMessage($this->mailer->rawMessage);
$body = $this->mailer->getBody($this->newsletter, $this->subscriber); $body = $this->mailer->getBody($this->newsletter, $this->subscriber);
// substitute the message to synchronize hashes // substitute the message to synchronize hashes
$body['RawMessage.Data'] = $rawMessage; $body['RawMessage.Data'] = $rawMessage;
@ -230,7 +236,7 @@ class AmazonSESTest extends \MailPoetTest {
); );
expect($result['response'])->false(); expect($result['response'])->false();
expect($result['error'])->isInstanceOf(MailerError::class); expect($result['error'])->isInstanceOf(MailerError::class);
expect($result['error']->getMessage())->stringContainsString('does not comply with RFC 2822'); expect($result['error']->getMessage())->stringContainsString('Invalid address');
} }
public function testItChecksBlacklistBeforeSending() { public function testItChecksBlacklistBeforeSending() {