| 1 |
<?php |
| 2 |
|
| 3 |
use AcyMailerPhp\Mailer; |
| 4 |
use AcyMailing\Classes\CampaignClass; |
| 5 |
use AcyMailing\Classes\MailClass; |
| 6 |
use AcyMailing\Helpers\MailerHelper; |
| 7 |
use AcyMailing\Core\AcymPlugin; |
| 8 |
|
| 9 |
class plgAcymElasticemail extends AcymPlugin |
| 10 |
{ |
| 11 |
const SENDING_METHOD_ID = 'elasticemail'; |
| 12 |
const SENDING_METHOD_NAME = 'Elastic Email'; |
| 13 |
const SENDING_METHOD_API_URL = 'https://api.elasticemail.com/v4/'; |
| 14 |
|
| 15 |
private $mailClass; |
| 16 |
private $campaignClass; |
| 17 |
private $attachmentsFetched = false; |
| 18 |
private $uploadedAttachments = []; |
| 19 |
|
| 20 |
public function __construct() |
| 21 |
{ |
| 22 |
parent::__construct(); |
| 23 |
$this->pluginDescription->name = self::SENDING_METHOD_NAME; |
| 24 |
} |
| 25 |
|
| 26 |
public function onAcymGetSendingMethods(&$data, $isMailer = false) |
| 27 |
{ |
| 28 |
$data['sendingMethods'][self::SENDING_METHOD_ID] = [ |
| 29 |
'name' => $this->pluginDescription->name, |
| 30 |
'image' => ACYM_IMAGES.'mailers/elasticemail.png', |
| 31 |
]; |
| 32 |
} |
| 33 |
|
| 34 |
public function onAcymGetSendingMethodsHtmlSetting(&$data) |
| 35 |
{ |
| 36 |
ob_start(); |
| 37 |
?> |
| 38 |
<div class="send_settings grid-x cell" id="<?php echo esc_attr(self::SENDING_METHOD_ID); ?>_settings"> |
| 39 |
<div class="cell grid-x acym_vcenter acym__sending__methods__one__settings"> |
| 40 |
<label for="<?php echo esc_attr(self::SENDING_METHOD_ID); ?>_password" class="cell shrink margin-right-1"> |
| 41 |
<?php echo esc_html(acym_translation('ACYM_API_KEY')); ?> |
| 42 |
</label> |
| 43 |
<?php |
| 44 |
$this->getLinks( |
| 45 |
'https://elasticemail.com/referral-reward?r=7b884a0b-b979-4473-8803-06ae39d76599', |
| 46 |
'https://elasticemail.com/email-api-pricing?r=7b884a0b-b979-4473-8803-06ae39d76599' |
| 47 |
); |
| 48 |
?> |
| 49 |
<input id="<?php echo esc_attr(self::SENDING_METHOD_ID); ?>_password" |
| 50 |
class="cell" |
| 51 |
type="text" |
| 52 |
name="config[<?php echo esc_attr(self::SENDING_METHOD_ID); ?>_password]" |
| 53 |
value="<?php echo esc_attr(str_repeat('*', strlen($this->config->get(self::SENDING_METHOD_ID.'_password')))); ?>"> |
| 54 |
<?php $this->getTestCredentialsSendingMethodButton(self::SENDING_METHOD_ID); ?> |
| 55 |
</div> |
| 56 |
</div> |
| 57 |
<?php |
| 58 |
$data['sendingMethodsHtmlSettings'][self::SENDING_METHOD_ID] = ob_get_clean(); |
| 59 |
} |
| 60 |
|
| 61 |
public function onAcymTestCredentialSendingMethod($sendingMethod, $credentials) |
| 62 |
{ |
| 63 |
if ($sendingMethod !== self::SENDING_METHOD_ID) { |
| 64 |
return; |
| 65 |
} |
| 66 |
|
| 67 |
$response = $this->callApiSendingMethod( |
| 68 |
self::SENDING_METHOD_API_URL.'files?limit=1', |
| 69 |
[], |
| 70 |
$this->getAuthenticationHeaders($credentials), |
| 71 |
); |
| 72 |
|
| 73 |
if (!empty($response['error_curl'])) { |
| 74 |
acym_sendAjaxResponse(acym_translationSprintf('ACYM_ERROR_OCCURRED_WHILE_CALLING_API', $response['error_curl']), [], false); |
| 75 |
} elseif (!empty($response['Error'])) { |
| 76 |
$message = $response['Error'] === 'APIKey Expired' |
| 77 |
? acym_translation('ACYM_AUTHENTICATION_FAILS_WITH_API_KEY') |
| 78 |
: acym_translationSprintf( |
| 79 |
'ACYM_API_RETURN_THIS_ERROR', |
| 80 |
$response['Error'] |
| 81 |
); |
| 82 |
acym_sendAjaxResponse($message, [], false); |
| 83 |
} else { |
| 84 |
acym_sendAjaxResponse(acym_translation('ACYM_API_KEY_CORRECT')); |
| 85 |
} |
| 86 |
} |
| 87 |
|
| 88 |
public function onAcymSendEmail( |
| 89 |
array &$response, |
| 90 |
MailerHelper $mailerHelper, |
| 91 |
array $to, |
| 92 |
array $from, |
| 93 |
array $reply_to, |
| 94 |
array $bcc = [], |
| 95 |
array $attachments = [], |
| 96 |
$sendingMethodListParams = [] |
| 97 |
): void { |
| 98 |
// https://elasticemail.com/developers/api-documentation/rest-api#operation/emailsTransactionalPost |
| 99 |
if ($mailerHelper->externalMailer !== self::SENDING_METHOD_ID) { |
| 100 |
return; |
| 101 |
} |
| 102 |
|
| 103 |
$data = [ |
| 104 |
'recipients' => new stdClass(), |
| 105 |
'content' => new stdClass(), |
| 106 |
]; |
| 107 |
|
| 108 |
$this->handleAddresses($data, $mailerHelper, $from, $reply_to, $to, $bcc); |
| 109 |
$this->handleEmailContent($data, $mailerHelper); |
| 110 |
$this->handleAttachments($data, $attachments); |
| 111 |
$this->handleHeaders($data, $mailerHelper); |
| 112 |
$this->handleGA($data, $mailerHelper); |
| 113 |
|
| 114 |
$responseMailer = $this->callApiSendingMethod( |
| 115 |
self::SENDING_METHOD_API_URL.'emails/transactional', |
| 116 |
$data, |
| 117 |
$this->getAuthenticationHeaders(), |
| 118 |
'POST' |
| 119 |
); |
| 120 |
|
| 121 |
if (!empty($responseMailer['Error'])) { |
| 122 |
$response['error'] = true; |
| 123 |
$response['message'] = $responseMailer['Error']; |
| 124 |
} else { |
| 125 |
$response['error'] = false; |
| 126 |
} |
| 127 |
} |
| 128 |
|
| 129 |
public function onAcymSendingMethodOptions(&$data) |
| 130 |
{ |
| 131 |
$data['embedImage'][self::SENDING_METHOD_ID] = false; |
| 132 |
} |
| 133 |
|
| 134 |
private function handleAddresses(array &$data, MailerHelper $mailerHelper, array $from, array $reply_to, array $to, array $bcc): void |
| 135 |
{ |
| 136 |
$data['recipients']->to = [$to['email']]; |
| 137 |
|
| 138 |
if (!empty($bcc)) { |
| 139 |
$data['recipients']->bcc = [$bcc[0][0]]; |
| 140 |
} |
| 141 |
|
| 142 |
$data['content']->From = empty($from['name']) ? $from['email'] : $from['name'].' <'.$from['email'].'>'; |
| 143 |
$data['content']->ReplyTo = empty($reply_to['name']) ? $reply_to['email'] : $reply_to['name'].' <'.$reply_to['email'].'>'; |
| 144 |
|
| 145 |
$bounceAddress = $this->getBounceAddress($mailerHelper); |
| 146 |
if (!empty($bounceAddress)) { |
| 147 |
$data['content']->EnvelopeFrom = $bounceAddress; |
| 148 |
} |
| 149 |
} |
| 150 |
|
| 151 |
private function handleEmailContent(array &$data, MailerHelper $mailerHelper): void |
| 152 |
{ |
| 153 |
$data['content']->Subject = $mailerHelper->Subject; |
| 154 |
$data['content']->Body = [ |
| 155 |
(object)[ |
| 156 |
'ContentType' => 'HTML', |
| 157 |
'Content' => $mailerHelper->Body, |
| 158 |
'Charset' => 'utf-8', |
| 159 |
], |
| 160 |
]; |
| 161 |
|
| 162 |
if (!empty($mailerHelper->AltBody)) { |
| 163 |
$data['content']->Body[] = (object)[ |
| 164 |
'ContentType' => 'PlainText', |
| 165 |
'Content' => $mailerHelper->AltBody, |
| 166 |
'Charset' => 'utf-8', |
| 167 |
]; |
| 168 |
} |
| 169 |
} |
| 170 |
|
| 171 |
private function handleAttachments(array &$data, array $attachments): void |
| 172 |
{ |
| 173 |
if (empty($attachments)) { |
| 174 |
return; |
| 175 |
} |
| 176 |
|
| 177 |
if (!$this->attachmentsFetched) { |
| 178 |
$this->attachmentsFetched = true; |
| 179 |
|
| 180 |
// Uploaded attachments expire after 35 days by default, so 1000 should be more than enough |
| 181 |
$uploadedAttachments = $this->callApiSendingMethod( |
| 182 |
self::SENDING_METHOD_API_URL.'files?limit=1000', |
| 183 |
[], |
| 184 |
$this->getAuthenticationHeaders() |
| 185 |
); |
| 186 |
|
| 187 |
if (empty($uploadedAttachments['Error'])) { |
| 188 |
foreach ($uploadedAttachments as $oneAttachment) { |
| 189 |
$this->uploadedAttachments[] = $oneAttachment['FileName']; |
| 190 |
} |
| 191 |
} |
| 192 |
} |
| 193 |
|
| 194 |
$data['content']->AttachFiles = []; |
| 195 |
foreach ($attachments as $attachment) { |
| 196 |
$fileName = $this->cleanFileName($attachment[1]); |
| 197 |
|
| 198 |
if (!in_array($fileName, $this->uploadedAttachments)) { |
| 199 |
$uploadedAttachment = $this->callApiSendingMethod( |
| 200 |
self::SENDING_METHOD_API_URL.'files', |
| 201 |
[ |
| 202 |
'BinaryContent' => $attachment['contentEncoded'], |
| 203 |
'Name' => $fileName, |
| 204 |
'ContentType' => $attachment[4], |
| 205 |
], |
| 206 |
$this->getAuthenticationHeaders(), |
| 207 |
'POST' |
| 208 |
); |
| 209 |
|
| 210 |
if (empty($uploadedAttachment['FileName'])) { |
| 211 |
continue; |
| 212 |
} |
| 213 |
|
| 214 |
$this->uploadedAttachments[] = $fileName; |
| 215 |
} |
| 216 |
|
| 217 |
$data['content']->AttachFiles[] = $fileName; |
| 218 |
} |
| 219 |
} |
| 220 |
|
| 221 |
private function handleHeaders(array &$data, MailerHelper $mailerHelper): void |
| 222 |
{ |
| 223 |
$data['content']->Headers = new stdClass(); |
| 224 |
$data['content']->Headers->Date = Mailer::rfcDate(); |
| 225 |
|
| 226 |
if (empty($mailerHelper->CustomHeader)) { |
| 227 |
return; |
| 228 |
} |
| 229 |
|
| 230 |
foreach ($mailerHelper->CustomHeader as $oneHeader) { |
| 231 |
$data['content']->Headers->{$oneHeader[0]} = $oneHeader[1]; |
| 232 |
} |
| 233 |
} |
| 234 |
|
| 235 |
private function handleGA(array &$data, MailerHelper $mailerHelper): void |
| 236 |
{ |
| 237 |
$trackingSystem = $this->config->get('trackingsystem', 'acymailing'); |
| 238 |
if (strpos($trackingSystem, 'google') === false || empty($mailerHelper->mailId)) { |
| 239 |
return; |
| 240 |
} |
| 241 |
$data['content']->Utm = new stdClass(); |
| 242 |
$data['content']->Utm->Source = 'newsletter'; |
| 243 |
$data['content']->Utm->Medium = 'email'; |
| 244 |
$data['content']->Utm->Campaign = acym_getAlias($data['content']->Subject); |
| 245 |
|
| 246 |
if (empty($this->mailClass)) { |
| 247 |
$this->mailClass = new MailClass(); |
| 248 |
} |
| 249 |
$campaignId = $this->mailClass->getCampaignIdByMailId($mailerHelper->mailId); |
| 250 |
|
| 251 |
if (empty($campaignId)) { |
| 252 |
$data['content']->Utm->Source .= '_'.$mailerHelper->mailId; |
| 253 |
} else { |
| 254 |
if (empty($this->campaignClass)) { |
| 255 |
$this->campaignClass = new CampaignClass(); |
| 256 |
} |
| 257 |
$campaign = $this->campaignClass->getOneById($campaignId); |
| 258 |
|
| 259 |
if (empty($campaign)) { |
| 260 |
return; |
| 261 |
} |
| 262 |
|
| 263 |
$data['content']->Utm->Source .= '_'.$campaignId; |
| 264 |
|
| 265 |
if (!empty($campaign->sending_params['utm_source'])) { |
| 266 |
$data['content']->Utm->Source = $campaign->sending_params['utm_source']; |
| 267 |
} |
| 268 |
|
| 269 |
if (!empty($campaign->sending_params['utm_medium'])) { |
| 270 |
$data['content']->Utm->Medium = $campaign->sending_params['utm_medium']; |
| 271 |
} |
| 272 |
|
| 273 |
if (!empty($campaign->sending_params['utm_campaign'])) { |
| 274 |
$data['content']->Utm->Campaign = $campaign->sending_params['utm_campaign']; |
| 275 |
} |
| 276 |
} |
| 277 |
} |
| 278 |
|
| 279 |
private function getAuthenticationHeaders(array $credentials = []): array |
| 280 |
{ |
| 281 |
if ( |
| 282 |
!isset($credentials[self::SENDING_METHOD_ID.'_password']) |
| 283 |
|| ( |
| 284 |
!empty($credentials[self::SENDING_METHOD_ID.'_password']) |
| 285 |
&& empty(trim($credentials[self::SENDING_METHOD_ID.'_password'], '*')) |
| 286 |
) |
| 287 |
) { |
| 288 |
return [ |
| 289 |
'X-ElasticEmail-ApiKey: '.$this->config->get(self::SENDING_METHOD_ID.'_password'), |
| 290 |
'Content-Type: application/json', |
| 291 |
]; |
| 292 |
} |
| 293 |
|
| 294 |
return [ |
| 295 |
'X-ElasticEmail-ApiKey: '.$credentials[self::SENDING_METHOD_ID.'_password'], |
| 296 |
'Content-Type: application/json', |
| 297 |
]; |
| 298 |
} |
| 299 |
|
| 300 |
private function cleanFileName(string $fileName): string |
| 301 |
{ |
| 302 |
// Replace accents with their non-accented equivalent |
| 303 |
if (function_exists('iconv')) { |
| 304 |
$fileName = iconv('UTF-8', 'ASCII//TRANSLIT', $fileName); |
| 305 |
} |
| 306 |
|
| 307 |
return preg_replace('#[^a-z0-9\.\-\_]#i', '_', $fileName); |
| 308 |
} |
| 309 |
} |
| 310 |
|