Common
1 year ago
ErrorMappers
1 year ago
AmazonSES.php
1 year ago
MailPoet.php
2 years ago
MailerMethod.php
3 years ago
PHPMail.php
4 years ago
PHPMailerMethod.php
1 year ago
SMTP.php
3 weeks ago
SendGrid.php
1 year ago
index.php
3 years ago
MailPoet.php
187 lines
| 1 | <?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing |
| 2 | |
| 3 | namespace MailPoet\Mailer\Methods; |
| 4 | |
| 5 | if (!defined('ABSPATH')) exit; |
| 6 | |
| 7 | |
| 8 | use MailPoet\Config\ServicesChecker; |
| 9 | use MailPoet\Mailer\Mailer; |
| 10 | use MailPoet\Mailer\Methods\Common\BlacklistCheck; |
| 11 | use MailPoet\Mailer\Methods\ErrorMappers\MailPoetMapper; |
| 12 | use MailPoet\Services\AuthorizedEmailsController; |
| 13 | use MailPoet\Services\Bridge; |
| 14 | use MailPoet\Services\Bridge\API; |
| 15 | use MailPoet\Util\Url; |
| 16 | |
| 17 | class MailPoet implements MailerMethod { |
| 18 | public $api; |
| 19 | public $sender; |
| 20 | public $replyTo; |
| 21 | public $servicesChecker; |
| 22 | |
| 23 | /** @var AuthorizedEmailsController */ |
| 24 | private $authorizedEmailsController; |
| 25 | |
| 26 | /** @var MailPoetMapper */ |
| 27 | private $errorMapper; |
| 28 | |
| 29 | /** @var BlacklistCheck */ |
| 30 | private $blacklist; |
| 31 | |
| 32 | /*** @var Url */ |
| 33 | private $url; |
| 34 | |
| 35 | /** @var Bridge */ |
| 36 | private $bridge; |
| 37 | |
| 38 | public function __construct( |
| 39 | $apiKey, |
| 40 | $sender, |
| 41 | $replyTo, |
| 42 | MailPoetMapper $errorMapper, |
| 43 | AuthorizedEmailsController $authorizedEmailsController, |
| 44 | Bridge $bridge, |
| 45 | Url $url |
| 46 | ) { |
| 47 | $this->api = new API($apiKey); |
| 48 | $this->sender = $sender; |
| 49 | $this->replyTo = $replyTo; |
| 50 | $this->servicesChecker = new ServicesChecker(); |
| 51 | $this->errorMapper = $errorMapper; |
| 52 | $this->bridge = $bridge; |
| 53 | $this->authorizedEmailsController = $authorizedEmailsController; |
| 54 | $this->blacklist = new BlacklistCheck(); |
| 55 | $this->url = $url; |
| 56 | } |
| 57 | |
| 58 | public function send($newsletter, $subscriber, $extraParams = []): array { |
| 59 | if ($this->servicesChecker->isMailPoetAPIKeyValid() === false) { |
| 60 | return Mailer::formatMailerErrorResult($this->errorMapper->getInvalidApiKeyError()); |
| 61 | } |
| 62 | |
| 63 | $subscribersForBlacklistCheck = is_array($subscriber) ? $subscriber : [$subscriber]; |
| 64 | foreach ($subscribersForBlacklistCheck as $sub) { |
| 65 | if ($this->blacklist->isBlacklisted($sub)) { |
| 66 | $error = $this->errorMapper->getBlacklistError($sub); |
| 67 | return Mailer::formatMailerErrorResult($error); |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | $messageBody = $this->getBody($newsletter, $subscriber, $extraParams); |
| 72 | $result = $this->api->sendMessages($messageBody); |
| 73 | |
| 74 | switch ($result['status']) { |
| 75 | case API::SENDING_STATUS_CONNECTION_ERROR: |
| 76 | $error = $this->errorMapper->getConnectionError($result['message']); |
| 77 | return Mailer::formatMailerErrorResult($error); |
| 78 | case API::SENDING_STATUS_SEND_ERROR: |
| 79 | $error = $this->processSendError($result, $subscriber, $newsletter); |
| 80 | return Mailer::formatMailerErrorResult($error); |
| 81 | case API::RESPONSE_STATUS_OK: |
| 82 | default: |
| 83 | return Mailer::formatMailerSendSuccessResult(); |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | public function processSendError($result, $subscriber, $newsletter) { |
| 88 | if (empty($result['code'])) { |
| 89 | return $this->errorMapper->getErrorForResult($result, $subscriber, $this->sender, $newsletter); |
| 90 | } |
| 91 | |
| 92 | switch ($result['code']) { |
| 93 | case API::RESPONSE_CODE_KEY_INVALID: |
| 94 | $this->bridge->invalidateMssKey(); |
| 95 | break; |
| 96 | |
| 97 | case API::RESPONSE_CODE_CAN_NOT_SEND: |
| 98 | if ($result['error'] === API::ERROR_MESSAGE_INVALID_FROM) { |
| 99 | $this->authorizedEmailsController->checkAuthorizedEmailAddresses(); |
| 100 | } |
| 101 | break; |
| 102 | |
| 103 | case API::RESPONSE_CODE_PAYLOAD_ERROR: |
| 104 | if (!empty($result['error']) && $result['error'] === API::ERROR_MESSAGE_BULK_EMAIL_FORBIDDEN) { |
| 105 | $this->authorizedEmailsController->checkAuthorizedEmailAddresses(); |
| 106 | } |
| 107 | break; |
| 108 | } |
| 109 | |
| 110 | return $this->errorMapper->getErrorForResult($result, $subscriber, $this->sender, $newsletter); |
| 111 | } |
| 112 | |
| 113 | public function processSubscriber($subscriber) { |
| 114 | preg_match('!(?P<name>.*?)\s<(?P<email>.*?)>!', $subscriber, $subscriberData); |
| 115 | if (!isset($subscriberData['email'])) { |
| 116 | $subscriberData = [ |
| 117 | 'email' => $subscriber, |
| 118 | ]; |
| 119 | } |
| 120 | return [ |
| 121 | 'email' => $subscriberData['email'], |
| 122 | 'name' => (isset($subscriberData['name'])) ? $subscriberData['name'] : '', |
| 123 | ]; |
| 124 | } |
| 125 | |
| 126 | public function getBody($newsletter, $subscriber, $extraParams = []) { |
| 127 | if (is_array($newsletter) && is_array($subscriber)) { |
| 128 | $body = []; |
| 129 | for ($record = 0; $record < count($newsletter); $record++) { |
| 130 | $body[] = $this->composeBody( |
| 131 | $newsletter[$record], |
| 132 | $this->processSubscriber($subscriber[$record]), |
| 133 | (!empty($extraParams['unsubscribe_url'][$record])) ? $extraParams['unsubscribe_url'][$record] : false, |
| 134 | (!empty($extraParams['one_click_unsubscribe'][$record])) ? $extraParams['one_click_unsubscribe'][$record] : false, |
| 135 | (!empty($extraParams['meta'][$record])) ? $extraParams['meta'][$record] : false |
| 136 | ); |
| 137 | } |
| 138 | } else { |
| 139 | $body[] = $this->composeBody( |
| 140 | $newsletter, |
| 141 | $this->processSubscriber($subscriber), |
| 142 | (!empty($extraParams['unsubscribe_url'])) ? $extraParams['unsubscribe_url'] : false, |
| 143 | (!empty($extraParams['one_click_unsubscribe'])) ? $extraParams['one_click_unsubscribe'] : false, |
| 144 | (!empty($extraParams['meta'])) ? $extraParams['meta'] : false |
| 145 | ); |
| 146 | } |
| 147 | return $body; |
| 148 | } |
| 149 | |
| 150 | private function composeBody($newsletter, $subscriber, $unsubscribeUrl, $oneClickUnsubscribeUrl, $meta): array { |
| 151 | $body = [ |
| 152 | 'to' => ([ |
| 153 | 'address' => $subscriber['email'], |
| 154 | 'name' => $subscriber['name'], |
| 155 | ]), |
| 156 | 'from' => ([ |
| 157 | 'address' => $this->sender['from_email'], |
| 158 | 'name' => $this->sender['from_name'], |
| 159 | ]), |
| 160 | 'reply_to' => ([ |
| 161 | 'address' => $this->replyTo['reply_to_email'], |
| 162 | ]), |
| 163 | 'subject' => $newsletter['subject'], |
| 164 | ]; |
| 165 | if (!empty($this->replyTo['reply_to_name'])) { |
| 166 | $body['reply_to']['name'] = $this->replyTo['reply_to_name']; |
| 167 | } |
| 168 | if (!empty($newsletter['body']['html'])) { |
| 169 | $body['html'] = $newsletter['body']['html']; |
| 170 | } |
| 171 | if (!empty($newsletter['body']['text'])) { |
| 172 | $body['text'] = $newsletter['body']['text']; |
| 173 | } |
| 174 | if ($unsubscribeUrl) { |
| 175 | $isHttps = $this->url->isUsingHttps($unsubscribeUrl); |
| 176 | $body['unsubscribe'] = [ |
| 177 | 'url' => $isHttps && $oneClickUnsubscribeUrl ? $oneClickUnsubscribeUrl : $unsubscribeUrl, |
| 178 | 'post' => $isHttps, |
| 179 | ]; |
| 180 | } |
| 181 | if ($meta) { |
| 182 | $body['meta'] = $meta; |
| 183 | } |
| 184 | return $body; |
| 185 | } |
| 186 | } |
| 187 |