| | |
| | | |
| | | namespace JVBase\integrations\services; |
| | | use JVBase\integrations\Admin; |
| | | use JVBase\integrations\Instance; |
| | | use JVBase\Instance; |
| | | use JVBase\integrations\Integrations; |
| | | use JVBase\integrations\Requests; |
| | | use JVBase\meta\Meta; |
| | | use WP_Error; |
| | | |
| | | if (!defined('ABSPATH')) { |
| | |
| | | return $this->response(false, 'Rate limit exceeded'); |
| | | } |
| | | $endpoint = str_replace($this->apiBase, '', $endpoint); |
| | | $checkErrors = $this->checkErrors($response); |
| | | if (!empty($checkErrors)) { |
| | | return $checkErrors; |
| | | } |
| | | |
| | | return match ($endpoint) { |
| | | '/email' => $this->handleEmailResponse($response, $method), |
| | | '/email/bulk' => $this->handleBulkEmailResponse($response, $method), |
| | | '/email/batch' => $this->handleBatchEmailResponse($response, $method), |
| | | default => $this->response(false, 'Unhandled Response for '. $endpoint . ' endpoint, with method: '. $method), |
| | | }; |
| | | } |
| | | |
| | | protected function checkErrors(WP_Error|array $response):array|false |
| | | { |
| | | $error = $response['ErrorCode'] ?? false; |
| | | if ($error) { |
| | | switch ($error) { |
| | | case '0': |
| | | //Do nothing, no error found |
| | | break; |
| | | return false; |
| | | //Bad or missing API Token |
| | | case '10': |
| | | //Multiple errors |
| | |
| | | case '13': |
| | | //Maintenance; PostMark API down for a sec |
| | | case '100': |
| | | //Maybe schedule a retry? |
| | | //Invalid Email Request |
| | | case '300': |
| | | //Sender Signature not found |
| | |
| | | case '409': |
| | | //Too many requests (500 max) |
| | | case '410': |
| | | //Maybe schedule a retry? |
| | | //Forbidden Attachment type |
| | | case '411': |
| | | //Account is pending |
| | | case '412': |
| | | //Account may not exist |
| | | case '413': |
| | | //Some errors in bulk request |
| | | case '422': |
| | | //Invalid query string parameter |
| | | case '500': |
| | | default: |
| | |
| | | return $this->response(false, 'Something went wrong: '.$response['Message']??''); |
| | | } |
| | | } |
| | | return match ($endpoint) { |
| | | '/email' => $this->handleEmailResponse($response, $method), |
| | | '/email/bulk' => $this->handleBulkEmailResponse($response, $method), |
| | | default => $this->response(false, 'Unhandled Response for '. $endpoint . ' endpoint, with method: '. $method), |
| | | }; |
| | | return false; |
| | | } |
| | | |
| | | /********************************************************** |
| | |
| | | |
| | | $payload = $this->buildPayload($to, $subject, $message, $is_html, $headers, $attachments); |
| | | |
| | | $response = $this->postRequest( |
| | | return $this->postRequest( |
| | | sprintf('%s/email', $this->apiBase), |
| | | $payload |
| | | ); |
| | | } |
| | | protected function handleEmailResponse(WP_Error|array $response, string $method):array |
| | | { |
| | | |
| | | return $this->response(true, 'Successfully sent request to PostMark', $response); |
| | | } |
| | | protected function buildPayload(string|array $to, string $subject, string $message, bool $is_html = true, array $headers = [], array $attachments = []):array |
| | | public function buildPayload(string|array $to, string $subject, string $message, bool $is_html = true, array $headers = [], array $attachments = []):array |
| | | { |
| | | $to = is_array($to) ? implode(',',$to) : $to; |
| | | |
| | |
| | | |
| | | if (!empty($headers['reply-to'])) { |
| | | $payload['ReplyTo'] = $headers['reply-to']; |
| | | } else { |
| | | $payload['ReplyTo'] = $this->getFromEmail(); |
| | | } |
| | | |
| | | if (!empty($attachments)) { |
| | |
| | | |
| | | return $payload; |
| | | } |
| | | |
| | | /** |
| | | * Sends the same message to multiple emails. Can use templates |
| | | * @param array<int> $userIDs |
| | | * @param string $subject |
| | | * @param string $message |
| | | * @param bool $is_html |
| | | * @param array $headers |
| | | * @param array $attachments |
| | | * @return array |
| | | */ |
| | | public function sendMessageToMany(array $userIDs, string $subject, string $message, bool $is_html = true, array $headers = [], array $attachments = []):array |
| | | { |
| | | if (!$this->isSetUp()) { |
| | | return $this->response(false, 'Not set up'); |
| | | } |
| | | |
| | | $tags = []; |
| | | $pattern = '/\{\{(.*?)\}\}/'; |
| | | |
| | | if (str_contains($subject, '{{')){ |
| | | preg_match_all($pattern, $subject, $tags); |
| | | } |
| | | if (str_contains($message, '{{')) { |
| | | preg_match_all($pattern, $message, $tags); |
| | | } |
| | | |
| | | $tags = array_unique($tags); |
| | | foreach ($tags as $tag) { |
| | | $t = implode( |
| | | array_map(function($word) { |
| | | return ucfirst($word); |
| | | }, explode('_', $tag) |
| | | )); |
| | | str_replace('{{'.$tag.'}}', '{{'.$t.'}}', $subject); |
| | | str_replace('{{'.$tag.'}}', '{{'.$t.'}}', $message); |
| | | } |
| | | |
| | | |
| | | $to = array_map(function ($userID) use ($tags, $subject, $message) { |
| | | $meta = Meta::forUser($userID); |
| | | $email = $meta->get('user_email'); |
| | | $out = []; |
| | | if (!empty($email) && filter_var($email, FILTER_VALIDATE_EMAIL)) { |
| | | $out['To'] = $email; |
| | | } |
| | | |
| | | if (empty($out)) { |
| | | $this->logError('sendMessageToMany', 'User does not have an email address',['user' => $userID]); |
| | | return []; |
| | | } |
| | | |
| | | $tmp = []; |
| | | foreach ($tags as $tag) { |
| | | $v = $meta->get($tag); |
| | | |
| | | if (!empty($v)) { |
| | | $tag = implode( |
| | | array_map(function($word) { |
| | | return ucfirst($word); |
| | | }, explode('_', $tag) |
| | | )); |
| | | $tmp[$tag] = $v; |
| | | } |
| | | } |
| | | if (!empty($tmp)) { |
| | | $out['TemplateModel'] = $tmp; |
| | | } |
| | | return $out; |
| | | }, $userIDs); |
| | | $to = array_filter($to, function($result) { |
| | | return array_key_exists('To', $result) && !empty($result['To']); |
| | | }); |
| | | |
| | | if (empty($to)) { |
| | | $this->logError('sendMessageToMany', 'No users set',['users' => $userIDs]); |
| | | } |
| | | |
| | | //Onward! |
| | | $payload = [ |
| | | 'From' => sprintf( |
| | | '%s <%s>', |
| | | $headers['from-name'] ?? $this->getFromName(), |
| | | $headers['from'] ?? $this->getFromEmail() |
| | | ), |
| | | 'Subject' => sanitize_text_field($subject), |
| | | 'TrackOpens' => $this->getTrackOpens() === 'true', |
| | | 'TrackLinks' => $this->getTrackLinks(), |
| | | 'MessageStream' => 'broadcast' |
| | | ]; |
| | | |
| | | if ($is_html) { |
| | | $payload['HtmlBody'] = $message; |
| | | $payload['TextBody'] = $this->textFromHtml($message); |
| | | } else { |
| | | $payload['TextBody'] = $message; |
| | | } |
| | | |
| | | if (!empty($headers['reply-to'])) { |
| | | $payload['ReplyTo'] = $headers['reply-to']; |
| | | } else { |
| | | $payload['ReplyTo'] = $this->getFromEmail(); |
| | | } |
| | | if (!empty($attachments)) { |
| | | $payload['Attachments'] = $this->processAttachments($attachments); |
| | | } |
| | | if (!empty($headers['x-headers'])) { |
| | | $payload['Headers'] = $headers['x-headers']; |
| | | } |
| | | $payload['Tag'] = $this->determineEmailTag($subject, $headers); |
| | | |
| | | $payload['Messages'] = $to; |
| | | |
| | | return $this->postRequest( |
| | | sprintf('%s/email/bulk', $this->apiBase), |
| | | $payload |
| | | ); |
| | | } |
| | | protected function handleBulkEmailResponse(WP_Error|array $response, string $method):array |
| | | { |
| | | return $this->response($response['Status']??'' === 'Accepted', 'Successfully sent request to Postmark', $response); |
| | | } |
| | | |
| | | /** |
| | | * @param array $emails An array of results from buildPayload, ready to batch send to Postmark. Limit of 500 at a time |
| | | * @return array |
| | | */ |
| | | public function sendMany(array $emails):array |
| | | { |
| | | if (!$this->isSetUp()) { |
| | | return $this->response(false, 'Not set up'); |
| | | } |
| | | $emails = array_filter($emails, function ($email) { |
| | | if (!array_key_exists('To', $email) || !filter_var($email['To'], FILTER_VALIDATE_EMAIL)) { |
| | | $this->logError('sendMany', 'Email does not have a To email address', $email); |
| | | return false; |
| | | } |
| | | //This shouldn't happen, but if it does, we'll just remove it for now. |
| | | if (!array_key_exists('From', $email)) { |
| | | $this->logError('sendMany', 'Email does not have a From email address', $email); |
| | | return false; |
| | | } |
| | | |
| | | return true; |
| | | }); |
| | | |
| | | if (empty($emails)) { |
| | | $this->logError('sendMany', 'No emails have been sent', $emails); |
| | | return $this->response(false, 'No emails have been sent', $emails); |
| | | } |
| | | |
| | | return $this->postRequest( |
| | | sprintf( |
| | | '%s/email/batch', |
| | | $this->apiBase |
| | | ), |
| | | $emails |
| | | ); |
| | | } |
| | | protected function handleBatchEmailResponse(WP_Error|array $response, string $method):array |
| | | { |
| | | $main = $response[0]; |
| | | $checkErrors = $this->checkErrors($main); |
| | | if (!empty($checkErrors)) { |
| | | return $checkErrors; |
| | | } |
| | | if (count($response) > 1) { |
| | | $errors = $response; |
| | | unset($errors[0]); |
| | | foreach ($errors as $error) { |
| | | $this->checkErrors($error); |
| | | } |
| | | } |
| | | return $this->response($main['Message']??'' === 'OK', 'Successfully sent request to Postmark', $response); |
| | | } |
| | | } |