File: /home/deshuvsd/www/wp-content/plugins/suremails/inc/emails/providers/aws/simple-email-service.php
<?php
// phpcs:ignoreFile
namespace SureMails\Inc\Emails\Providers\AWS;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Copyright (c) 2014, Daniel Zahariev.
* Copyright (c) 2011, Dan Myers.
* Parts copyright (c) 2008, Donovan Schonknecht.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* This is a modified BSD license (the third clause has been removed).
* The BSD license may be found here:
* http://www.opensource.org/licenses/bsd-license.php
*
* Amazon Simple Email Service is a trademark of Amazon.com, Inc. or its affiliates.
*
* SimpleEmailService is based on Donovan Schonknecht's Amazon S3 PHP class, found here:
* http://undesigned.org.za/2007/10/22/amazon-s3-php-class
*
* @copyright 2014 Daniel Zahariev
* @copyright 2011 Dan Myers
* @copyright 2008 Donovan Schonknecht
*/
/**
* SimpleEmailService PHP class
*
* @link https://github.com/daniel-zahariev/php-aws-ses
* @package AmazonSimpleEmailService
* @version v0.9.1
*/
class SimpleEmailService {
/**
* @link(AWS SES regions, http://docs.aws.amazon.com/ses/latest/DeveloperGuide/regions.html)
*/
public const AWS_US_EAST_1 = 'email.us-east-1.amazonaws.com';
public const AWS_US_WEST_2 = 'email.us-west-2.amazonaws.com';
public const AWS_EU_WEST1 = 'email.eu-west-1.amazonaws.com';
public const REQUEST_SIGNATURE_V3 = 'v3';
public const REQUEST_SIGNATURE_V4 = 'v4';
/**
* AWS SES Target host of region
*/
protected $__host;
/**
* AWS SES Access key
*/
protected $__accessKey;
/**
* AWS Secret key
*/
protected $__secretKey;
/**
* Enable/disable
*/
protected $__trigger_errors;
/**
* Controls the reuse of CURL hander for sending a bulk of messages
*
* @deprecated
*/
protected $__bulk_sending_mode = false;
/**
* Optionally reusable SimpleEmailServiceRequest instance
*/
protected $__ses_request = null;
/**
* Controls CURLOPT_SSL_VERIFYHOST setting for SimpleEmailServiceRequest's curl handler
*/
protected $__verifyHost = true;
/**
* Controls CURLOPT_SSL_VERIFYPEER setting for SimpleEmailServiceRequest's curl handler
*/
protected $__verifyPeer = true;
/**
* @var string HTTP Request signature version
*/
protected $__requestSignatureVersion;
/**
* Constructor
*
* @param string $accessKey Access key
* @param string $secretKey Secret key
* @param string $host Amazon Host through which to send the emails
* @param bool $trigger_errors Trigger PHP errors when AWS SES API returns an error
* @param string $requestSignatureVersion Version of the request signature
*/
public function __construct( $accessKey = null, $secretKey = null, $host = self::AWS_US_EAST_1, $trigger_errors = true, $requestSignatureVersion = self::REQUEST_SIGNATURE_V4 ) {
if ( $accessKey !== null && $secretKey !== null ) {
$this->setAuth( $accessKey, $secretKey );
}
$this->__host = $host;
$this->__trigger_errors = $trigger_errors;
$this->__requestSignatureVersion = $requestSignatureVersion;
}
/**
* Trigger an error message
*
* {@internal Used by member functions to output errors}
*
* @param string $functionname The name of the function that failed
* @param array $error Array containing error information
* @return void
*/
public function __triggerError( $functionname, $error ) {
trigger_error( $this->getErrorMessage( $functionname, $error ), E_USER_WARNING );
}
/**
* Set the request signature version
*
* @param string $requestSignatureVersion
* @return SimpleEmailService $this
*/
public function setRequestSignatureVersion( $requestSignatureVersion ) {
$this->__requestSignatureVersion = $requestSignatureVersion;
return $this;
}
/**
* @return string
*/
public function getRequestSignatureVersion() {
return $this->__requestSignatureVersion;
}
/**
* Set AWS access key and secret key
*
* @param string $accessKey Access key
* @param string $secretKey Secret key
* @return SimpleEmailService $this
*/
public function setAuth( $accessKey, $secretKey ) {
$this->__accessKey = $accessKey;
$this->__secretKey = $secretKey;
return $this;
}
/**
* Set AWS Host
*
* @param string $host AWS Host
*/
public function setHost( $host = self::AWS_US_EAST_1 ) {
$this->__host = $host;
return $this;
}
/**
* @deprecated
*/
public function enableVerifyHost( $enable = true ) {
$this->__verifyHost = (bool) $enable;
return $this;
}
/**
* @deprecated
*/
public function enableVerifyPeer( $enable = true ) {
$this->__verifyPeer = (bool) $enable;
return $this;
}
/**
* @deprecated
*/
public function verifyHost() {
return $this->__verifyHost;
}
/**
* @deprecated
*/
public function verifyPeer() {
return $this->__verifyPeer;
}
/**
* Get AWS target host
*
* @return bool
*/
public function getHost() {
return $this->__host;
}
/**
* Get AWS SES auth access key
*
* @return string
*/
public function getAccessKey() {
return $this->__accessKey;
}
/**
* Get AWS SES auth secret key
*
* @return string
*/
public function getSecretKey() {
return $this->__secretKey;
}
/**
* Get the verify peer CURL mode
*
* @return bool
*/
public function getVerifyPeer() {
return $this->__verifyPeer;
}
/**
* Get the verify host CURL mode
*
* @return bool
*/
public function getVerifyHost() {
return $this->__verifyHost;
}
/**
* Get bulk email sending mode
*
* @return bool
* @deprecated
*/
public function getBulkMode() {
return $this->__bulk_sending_mode;
}
/**
* Enable/disable CURLOPT_SSL_VERIFYHOST for SimpleEmailServiceRequest's curl handler
* verifyHost and verifyPeer determine whether curl verifies ssl certificates.
* It may be necessary to disable these checks on certain systems.
* These only have an effect if SSL is enabled.
*
* @param bool $enable New status for the mode
* @return SimpleEmailService $this
*/
public function setVerifyHost( $enable = true ) {
$this->__verifyHost = (bool) $enable;
return $this;
}
/**
* Enable/disable CURLOPT_SSL_VERIFYPEER for SimpleEmailServiceRequest's curl handler
* verifyHost and verifyPeer determine whether curl verifies ssl certificates.
* It may be necessary to disable these checks on certain systems.
* These only have an effect if SSL is enabled.
*
* @param bool $enable New status for the mode
* @return SimpleEmailService $this
*/
public function setVerifyPeer( $enable = true ) {
$this->__verifyPeer = (bool) $enable;
return $this;
}
/**
* Enable/disable bulk email sending mode
*
* @param bool $enable New status for the mode
* @return SimpleEmailService $this
* @deprecated
*/
public function setBulkMode( $enable = true ) {
$this->__bulk_sending_mode = (bool) $enable;
return $this;
}
/**
* Lists the email addresses that have been verified and can be used as the 'From' address
*
* @return array|\WP_Error An array containing two items: a list of verified email addresses, and the request id.
*/
public function listVerifiedEmailAddresses() {
$ses_request = $this->getRequestHandler( 'GET' );
$ses_request->setParameter( 'Action', 'ListIdentities' );
$ses_response = $ses_request->getResponse();
if ( $ses_response->error === false && $ses_response->code !== 200 ) {
$ses_response->error = [
'code' => $ses_response->code,
'message' => 'Unexpected HTTP status',
];
}
if ( $ses_response->error !== false ) {
return new \WP_Error( $ses_response->code, $this->getErrorMessage( 'ListIdentities', $ses_response->error ), $ses_response->error );
}
$response = [];
if ( ! isset( $ses_response->body ) ) {
return $response;
}
$domains = [];
$addresses = [];
foreach ( $ses_response->body->ListIdentitiesResult->Identities->member as $address ) {
if ( is_email( $address ) ) {
$addresses[] = (string) $address;
} else {
$domains[] = (string) $address;
}
}
$response['Addresses'] = $addresses;
$response['domains'] = $domains;
$response['RequestId'] = (string) $ses_response->body->ResponseMetadata->RequestId;
return $response;
}
/**
* Requests verification of the provided email address, so it can be used
* as the 'From' address when sending emails through SimpleEmailService.
*
* After submitting this request, you should receive a verification email
* from Amazon at the specified address containing instructions to follow.
*
* @param string $email The email address to get verified
* @return array The request id for this request.
*/
public function verifyEmailAddress( $email ) {
$ses_request = $this->getRequestHandler( 'POST' );
$ses_request->setParameter( 'Action', 'VerifyEmailAddress' );
$ses_request->setParameter( 'EmailAddress', $email );
$ses_response = $ses_request->getResponse();
if ( $ses_response->error === false && $ses_response->code !== 200 ) {
$ses_response->error = [
'code' => $ses_response->code,
'message' => 'Unexpected HTTP status',
];
}
if ( $ses_response->error !== false ) {
$this->__triggerError( 'verifyEmailAddress', $ses_response->error );
return false;
}
$response['RequestId'] = (string) $ses_response->body->ResponseMetadata->RequestId;
return $response;
}
/**
* Removes the specified email address from the list of verified addresses.
*
* @param string $email The email address to remove
* @return array The request id for this request.
*/
public function deleteVerifiedEmailAddress( $email ) {
$ses_request = $this->getRequestHandler( 'DELETE' );
$ses_request->setParameter( 'Action', 'DeleteVerifiedEmailAddress' );
$ses_request->setParameter( 'EmailAddress', $email );
$ses_response = $ses_request->getResponse();
if ( $ses_response->error === false && $ses_response->code !== 200 ) {
$ses_response->error = [
'code' => $ses_response->code,
'message' => 'Unexpected HTTP status',
];
}
if ( $ses_response->error !== false ) {
$this->__triggerError( 'deleteVerifiedEmailAddress', $ses_response->error );
return false;
}
$response['RequestId'] = (string) $ses_response->body->ResponseMetadata->RequestId;
return $response;
}
/**
* Retrieves information on the current activity limits for this account.
* See http://docs.amazonwebservices.com/ses/latest/APIReference/API_GetSendQuota.html
*
* @return array|\WP_Error An array containing information on this account's activity limits.
*/
public function getSendQuota() {
$ses_request = $this->getRequestHandler( 'GET' );
$ses_request->setParameter( 'Action', 'GetSendQuota' );
$ses_response = $ses_request->getResponse();
if ( $ses_response->error === false && $ses_response->code !== 200 ) {
$ses_response->error = [
'code' => $ses_response->code,
'message' => 'Unexpected HTTP status',
];
}
if ( $ses_response->error !== false ) {
return new \WP_Error( $ses_response->code, $this->getErrorMessage( 'getSendQuota', $ses_response->error ), $ses_response->error );
}
$response = [];
if ( ! isset( $ses_response->body ) ) {
return $response;
}
$response['Max24HourSend'] = (string) $ses_response->body->GetSendQuotaResult->Max24HourSend;
$response['MaxSendRate'] = (string) $ses_response->body->GetSendQuotaResult->MaxSendRate;
$response['SentLast24Hours'] = (string) $ses_response->body->GetSendQuotaResult->SentLast24Hours;
$response['RequestId'] = (string) $ses_response->body->ResponseMetadata->RequestId;
return $response;
}
/**
* Retrieves statistics for the last two weeks of activity on this account.
* See http://docs.amazonwebservices.com/ses/latest/APIReference/API_GetSendStatistics.html
*
* @return array An array of activity statistics. Each array item covers a 15-minute period.
*/
public function getSendStatistics() {
$ses_request = $this->getRequestHandler( 'GET' );
$ses_request->setParameter( 'Action', 'GetSendStatistics' );
$ses_response = $ses_request->getResponse();
if ( $ses_response->error === false && $ses_response->code !== 200 ) {
$ses_response->error = [
'code' => $ses_response->code,
'message' => 'Unexpected HTTP status',
];
}
if ( $ses_response->error !== false ) {
$this->__triggerError( 'getSendStatistics', $ses_response->error );
return false;
}
$response = [];
if ( ! isset( $ses_response->body ) ) {
return $response;
}
$datapoints = [];
foreach ( $ses_response->body->GetSendStatisticsResult->SendDataPoints->member as $datapoint ) {
$p = [];
$p['Bounces'] = (string) $datapoint->Bounces;
$p['Complaints'] = (string) $datapoint->Complaints;
$p['DeliveryAttempts'] = (string) $datapoint->DeliveryAttempts;
$p['Rejects'] = (string) $datapoint->Rejects;
$p['Timestamp'] = (string) $datapoint->Timestamp;
$datapoints[] = $p;
}
$response['SendDataPoints'] = $datapoints;
$response['RequestId'] = (string) $ses_response->body->ResponseMetadata->RequestId;
return $response;
}
/**
* Given a SimpleEmailServiceMessage object, submits the message to the service for sending.
*
* @param SimpleEmailServiceMessage $sesMessage An instance of the message class
* @param bool $use_raw_request If this is true or there are attachments to the email `SendRawEmail` call will be used
* @param bool $trigger_error Optionally overwrite the class setting for triggering an error (with type check to true/false)
* @return array An array containing the unique identifier for this message and a separate request id.
* Returns false if the provided message is missing any required fields.
* @link(AWS SES Response formats, http://docs.aws.amazon.com/ses/latest/DeveloperGuide/query-interface-responses.html)
*/
public function sendEmail( $sesMessage, $use_raw_request = false, $trigger_error = null ) {
if ( ! $sesMessage->validate() ) {
$this->__triggerError( 'sendEmail', 'Message failed validation.' );
return false;
}
$ses_request = $this->getRequestHandler( 'POST' );
$action = ! empty( $sesMessage->attachments ) || $use_raw_request ? 'SendRawEmail' : 'SendEmail';
$ses_request->setParameter( 'Action', $action );
// Works with both calls
if ( ! is_null( $sesMessage->configuration_set ) ) {
$ses_request->setParameter( 'ConfigurationSetName', $sesMessage->configuration_set );
}
if ( $action === 'SendRawEmail' ) {
// https://docs.aws.amazon.com/ses/latest/APIReference/API_SendRawEmail.html
$ses_request->setParameter( 'RawMessage.Data', $sesMessage->mime );
} else {
$i = 1;
foreach ( $sesMessage->to as $to ) {
$ses_request->setParameter( 'Destination.ToAddresses.member.' . $i, $sesMessage->encodeRecipients( $to ) );
$i++;
}
if ( is_array( $sesMessage->cc ) ) {
$i = 1;
foreach ( $sesMessage->cc as $cc ) {
$ses_request->setParameter( 'Destination.CcAddresses.member.' . $i, $sesMessage->encodeRecipients( $cc ) );
$i++;
}
}
if ( is_array( $sesMessage->bcc ) ) {
$i = 1;
foreach ( $sesMessage->bcc as $bcc ) {
$ses_request->setParameter( 'Destination.BccAddresses.member.' . $i, $sesMessage->encodeRecipients( $bcc ) );
$i++;
}
}
if ( is_array( $sesMessage->replyto ) ) {
$i = 1;
foreach ( $sesMessage->replyto as $replyto ) {
$ses_request->setParameter( 'ReplyToAddresses.member.' . $i, $sesMessage->encodeRecipients( $replyto ) );
$i++;
}
}
$ses_request->setParameter( 'Source', $sesMessage->encodeRecipients( $sesMessage->from ) );
if ( $sesMessage->returnpath !== null ) {
$ses_request->setParameter( 'ReturnPath', $sesMessage->returnpath );
}
if ( $sesMessage->subject !== null && strlen( $sesMessage->subject ) > 0 ) {
$ses_request->setParameter( 'Message.Subject.Data', $sesMessage->subject );
if ( $sesMessage->subjectCharset !== null && strlen( $sesMessage->subjectCharset ) > 0 ) {
$ses_request->setParameter( 'Message.Subject.Charset', $sesMessage->subjectCharset );
}
}
if ( $sesMessage->messagetext !== null && strlen( $sesMessage->messagetext ) > 0 ) {
$ses_request->setParameter( 'Message.Body.Text.Data', $sesMessage->messagetext );
if ( $sesMessage->messageTextCharset !== null && strlen( $sesMessage->messageTextCharset ) > 0 ) {
$ses_request->setParameter( 'Message.Body.Text.Charset', $sesMessage->messageTextCharset );
}
}
if ( $sesMessage->messagehtml !== null && strlen( $sesMessage->messagehtml ) > 0 ) {
$ses_request->setParameter( 'Message.Body.Html.Data', $sesMessage->messagehtml );
if ( $sesMessage->messageHtmlCharset !== null && strlen( $sesMessage->messageHtmlCharset ) > 0 ) {
$ses_request->setParameter( 'Message.Body.Html.Charset', $sesMessage->messageHtmlCharset );
}
}
$i = 1;
foreach ( $sesMessage->message_tags as $key => $value ) {
$ses_request->setParameter( 'Tags.member.' . $i . '.Name', $key );
$ses_request->setParameter( 'Tags.member.' . $i . '.Value', $value );
$i++;
}
}
$ses_response = $ses_request->getResponse();
if ( $ses_response->error === false && $ses_response->code !== 200 ) {
return [
'code' => $ses_response->code,
'error' => [ 'Error' => [ 'message' => 'Unexpected HTTP status' ] ],
];
}
if ( $ses_response->error !== false ) {
if ( ( $this->__trigger_errors && ( $trigger_error !== false ) ) || $trigger_error === true ) {
$this->__triggerError( 'sendEmail', $ses_response->error );
return false;
}
return $ses_response;
}
return [
'MessageId' => (string) $ses_response->body->{"{$action}Result"}->MessageId,
'RequestId' => (string) $ses_response->body->ResponseMetadata->RequestId,
];
}
public function sendRawEmail( $sesMessage ) {
$ses_request = $this->getRequestHandler( 'POST' );
$ses_request->setParameter( 'Action', 'SendRawEmail' );
// https://docs.aws.amazon.com/ses/latest/APIReference/API_SendRawEmail.html
$ses_request->setParameter( 'RawMessage.Data', $sesMessage );
$ses_response = $ses_request->getResponse();
if ( ( $ses_response->error === false && $ses_response->code !== 200 ) || $ses_response->error !== false ) {
return new \WP_Error( $ses_response->code, $this->getErrorMessage( 'sendRawEmail', $ses_response->error ), $ses_response->error );
}
return [
'MessageId' => (string) $ses_response->body->SendRawEmailResult->MessageId,
'RequestId' => (string) $ses_response->body->ResponseMetadata->RequestId,
];
}
public function getErrorMessage( $functionname, $error ) {
if ( $error === false ) {
return sprintf( 'SimpleEmailService::%s(): Encountered an error, but no description given', $functionname );
}
if ( isset( $error['curl'] ) && $error['curl'] ) {
return sprintf( 'SimpleEmailService::%s(): %s %s', $functionname, $error['code'], $error['message'] );
}
if ( isset( $error['Error'] ) ) {
$e = $error['Error'];
return sprintf( "SimpleEmailService::%s(): %s - %s: %s\nRequest Id: %s\n", $functionname, $e['Type'], $e['Code'], $e['Message'], $error['RequestId'] );
}
return sprintf( 'SimpleEmailService::%s(): Encountered an error: %s', $functionname, $error );
}
/**
* Set SES Request
*
* @param SimpleEmailServiceRequest $ses_request description
* @return SimpleEmailService $this
*/
public function setRequestHandler( ?SimpleEmailServiceRequest $ses_request = null ) {
if ( ! is_null( $ses_request ) ) {
$ses_request->setSES( $this );
}
$this->__ses_request = $ses_request;
return $this;
}
/**
* Get SES Request
*
* @param string $verb HTTP Verb: GET, POST, DELETE
* @return SimpleEmailServiceRequest SES Request
*/
public function getRequestHandler( $verb ) {
if ( empty( $this->__ses_request ) ) {
$this->__ses_request = new SimpleEmailServiceRequest( $this, $verb );
} else {
$this->__ses_request->setVerb( $verb );
}
return $this->__ses_request;
}
}