Initial commit
This commit is contained in:
@@ -0,0 +1,354 @@
|
||||
<?php
|
||||
|
||||
namespace FluentMail\App\Services\Mailer\Providers\AmazonSes;
|
||||
|
||||
use FluentMail\App\Models\Settings;
|
||||
use FluentMail\App\Services\Mailer\BaseHandler;
|
||||
use FluentMail\Includes\Support\Arr;
|
||||
|
||||
class Handler extends BaseHandler
|
||||
{
|
||||
use ValidatorTrait;
|
||||
|
||||
protected $client = null;
|
||||
|
||||
const RAW_REQUEST = true;
|
||||
|
||||
const TRIGGER_ERROR = false;
|
||||
|
||||
public function send()
|
||||
{
|
||||
if ($this->preSend() && $this->phpMailer->preSend()) {
|
||||
$this->client = new SimpleEmailServiceMessage;
|
||||
return $this->postSend();
|
||||
}
|
||||
|
||||
return $this->handleResponse(new \WP_Error(422, __('Something went wrong!', 'fluent-smtp'), []));
|
||||
}
|
||||
|
||||
public function postSend()
|
||||
{
|
||||
$mime = chunk_split(base64_encode($this->phpMailer->getSentMIMEMessage()), 76, "\n");
|
||||
|
||||
$connectionSettings = $this->filterConnectionVars($this->getSetting());
|
||||
|
||||
$ses = fluentMailSesConnection($connectionSettings);
|
||||
|
||||
$this->response = $ses->sendRawEmail($mime);
|
||||
|
||||
return $this->handleResponse($this->response);
|
||||
}
|
||||
|
||||
protected function getFrom()
|
||||
{
|
||||
return $this->getParam('from');
|
||||
}
|
||||
|
||||
public function getVerifiedEmails()
|
||||
{
|
||||
return (new Settings)->getVerifiedEmails();
|
||||
}
|
||||
|
||||
protected function getReplyTo()
|
||||
{
|
||||
$replyTo = $this->getRecipients(
|
||||
$this->getParam('headers.reply-to')
|
||||
);
|
||||
|
||||
if (is_array($replyTo)) {
|
||||
$replyTo = reset($replyTo);
|
||||
}
|
||||
|
||||
return $replyTo;
|
||||
}
|
||||
|
||||
protected function getTo()
|
||||
{
|
||||
return $this->getRecipients($this->getParam('to'));
|
||||
}
|
||||
|
||||
protected function getCarbonCopy()
|
||||
{
|
||||
return $this->getRecipients($this->getParam('headers.cc'));
|
||||
}
|
||||
|
||||
protected function getBlindCarbonCopy()
|
||||
{
|
||||
return $this->getRecipients($this->getParam('headers.bcc'));
|
||||
}
|
||||
|
||||
protected function getRecipients($recipients)
|
||||
{
|
||||
$array = array_map(function ($recipient) {
|
||||
return isset($recipient['name'])
|
||||
? $recipient['name'] . ' <' . $recipient['email'] . '>'
|
||||
: $recipient['email'];
|
||||
}, $recipients);
|
||||
|
||||
return implode(', ', $array);
|
||||
}
|
||||
|
||||
protected function getBody()
|
||||
{
|
||||
return [
|
||||
$this->phpMailer->AltBody,
|
||||
$this->phpMailer->Body
|
||||
];
|
||||
}
|
||||
|
||||
protected function getAttachments()
|
||||
{
|
||||
$attachments = [];
|
||||
|
||||
foreach ($this->getParam('attachments') as $attachment) {
|
||||
$file = false;
|
||||
|
||||
try {
|
||||
if (is_file($attachment[0]) && is_readable($attachment[0])) {
|
||||
$fileName = basename($attachment[0]);
|
||||
$file = file_get_contents($attachment[0]);
|
||||
$mimeType = mime_content_type($attachment[0]);
|
||||
$filetype = str_replace(';', '', trim($mimeType));
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$file = false;
|
||||
}
|
||||
|
||||
if ($file === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$attachments[] = [
|
||||
'type' => $filetype,
|
||||
'name' => $fileName,
|
||||
'content' => $file
|
||||
];
|
||||
}
|
||||
|
||||
return $attachments;
|
||||
}
|
||||
|
||||
protected function getCustomEmailHeaders()
|
||||
{
|
||||
$customHeaders = [
|
||||
'X-Mailer' => 'Amazon-SES'
|
||||
];
|
||||
|
||||
$headers = [];
|
||||
foreach ($customHeaders as $key => $header) {
|
||||
$headers[] = $key . ':' . $header;
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
protected function getRegion()
|
||||
{
|
||||
return 'email.' . $this->getSetting('region') . '.amazonaws.com';
|
||||
}
|
||||
|
||||
public function getValidSenders($config)
|
||||
{
|
||||
$config = $this->filterConnectionVars($config);
|
||||
|
||||
$senders = $this->getSendersFromMappingsAndApi($config);
|
||||
|
||||
return $senders['all_senders'];
|
||||
}
|
||||
|
||||
public function getValidSendingIdentities($config)
|
||||
{
|
||||
$config = $this->filterConnectionVars($config);
|
||||
$region = 'email.' . $config['region'] . '.amazonaws.com';
|
||||
|
||||
$ses = new SimpleEmailService(
|
||||
$config['access_key'],
|
||||
$config['secret_key'],
|
||||
$region,
|
||||
static::TRIGGER_ERROR
|
||||
);
|
||||
|
||||
$validSenders = $ses->listVerifiedEmailAddresses();
|
||||
$addresses = [];
|
||||
|
||||
if (is_wp_error($validSenders)) {
|
||||
return [
|
||||
'emails' => [$config['sender_email']],
|
||||
'verified_domain' => ''
|
||||
];
|
||||
}
|
||||
|
||||
if ($validSenders && isset($validSenders['Addresses'])) {
|
||||
$addresses = $validSenders['Addresses'];
|
||||
}
|
||||
|
||||
$primaryEmail = $config['sender_email'];
|
||||
$domainArray = explode('@', $primaryEmail);
|
||||
$domainName = $domainArray[1];
|
||||
|
||||
if (apply_filters('fluent_mail_ses_primary_domain_only', true)) {
|
||||
$addresses = array_filter($addresses, function ($email) use ($domainName) {
|
||||
return !!strpos($email, $domainName);
|
||||
});
|
||||
$addresses = array_values($addresses);
|
||||
}
|
||||
|
||||
return [
|
||||
'emails' => apply_filters('fluentsmtp_ses_valid_senders', $addresses, $config),
|
||||
'verified_domain' => in_array($domainName, $validSenders['domains']) ? $domainName : ''
|
||||
];
|
||||
}
|
||||
|
||||
public function getConnectionInfo($connection)
|
||||
{
|
||||
$connection = $this->filterConnectionVars($connection);
|
||||
|
||||
$stats = $this->getStats($connection);
|
||||
$error = '';
|
||||
if (is_wp_error($stats)) {
|
||||
$error = $stats->get_error_message();
|
||||
$stats = [];
|
||||
}
|
||||
|
||||
$validSenders = $this->getSendersFromMappingsAndApi($connection);
|
||||
|
||||
$info = (string)fluentMail('view')->make('admin.ses_connection_info', [
|
||||
'connection' => $connection,
|
||||
'valid_senders' => $validSenders['all_senders'],
|
||||
'stats' => $stats,
|
||||
'error' => $error
|
||||
]);
|
||||
|
||||
return [
|
||||
'info' => $info,
|
||||
'verificationSettings' => [
|
||||
'connection_name' => 'Amazon SES',
|
||||
'all_senders' => $validSenders['all_senders'],
|
||||
'verified_senders' => $validSenders['verified_senders'],
|
||||
'verified_domain' => $validSenders['verified_domain']
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function addNewSenderEmail($connection, $email)
|
||||
{
|
||||
$connection = $this->filterConnectionVars($connection);
|
||||
$validSenders = $this->getValidSendingIdentities($connection);
|
||||
|
||||
$emailDomain = explode('@', $email);
|
||||
$emailDomain = $emailDomain[1];
|
||||
|
||||
if ($emailDomain != $validSenders['verified_domain']) {
|
||||
return new \WP_Error(422, __('Invalid email address! Please use a verified domain.', 'fluent-smtp'));
|
||||
}
|
||||
|
||||
$settings = fluentMailGetSettings();
|
||||
$mappings = Arr::get($settings, 'mappings', []);
|
||||
|
||||
if (isset($mappings[$email])) {
|
||||
return new \WP_Error(422, __('Email address already exists with another connection. Please choose a different email.', 'fluent-smtp'));
|
||||
}
|
||||
|
||||
$settings = get_option('fluentmail-settings');
|
||||
|
||||
$settings['mappings'][$email] = md5($connection['sender_email']);
|
||||
|
||||
update_option('fluentmail-settings', $settings);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function removeSenderEmail($connection, $email)
|
||||
{
|
||||
$connection = $this->filterConnectionVars($connection);
|
||||
$validSenders = $this->getValidSendingIdentities($connection);
|
||||
|
||||
$emailDomain = explode('@', $email);
|
||||
$emailDomain = $emailDomain[1];
|
||||
|
||||
if ($emailDomain != $validSenders['verified_domain']) {
|
||||
return new \WP_Error(422, __('Invalid email address! Please use a verified domain.', 'fluent-smtp'));
|
||||
}
|
||||
|
||||
if (in_array($email, $validSenders['emails'])) {
|
||||
return new \WP_Error(422, __('Sorry! you can not remove this email from this connection', 'fluent-smtp'));
|
||||
}
|
||||
|
||||
$settings = fluentMailGetSettings();
|
||||
$mappings = Arr::get($settings, 'mappings', []);
|
||||
|
||||
if (!isset($mappings[$email])) {
|
||||
return new \WP_Error(422, __('Email does not exists. Please try again.', 'fluent-smtp'));
|
||||
}
|
||||
|
||||
// check if the it's the same email or not
|
||||
if ($mappings[$email] != md5($connection['sender_email'])) {
|
||||
return new \WP_Error(422, __('Email does not exists. Please try again.', 'fluent-smtp'));
|
||||
}
|
||||
|
||||
$settings = get_option('fluentmail-settings');
|
||||
|
||||
unset($settings['mappings'][$email]);
|
||||
|
||||
update_option('fluentmail-settings', $settings);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private function getStats($config)
|
||||
{
|
||||
$region = 'email.' . $config['region'] . '.amazonaws.com';
|
||||
|
||||
$ses = new SimpleEmailService(
|
||||
$config['access_key'],
|
||||
$config['secret_key'],
|
||||
$region,
|
||||
static::TRIGGER_ERROR
|
||||
);
|
||||
|
||||
return $ses->getSendQuota();
|
||||
}
|
||||
|
||||
private function filterConnectionVars($connection)
|
||||
{
|
||||
if ($connection['key_store'] == 'wp_config') {
|
||||
$connection['access_key'] = defined('FLUENTMAIL_AWS_ACCESS_KEY_ID') ? FLUENTMAIL_AWS_ACCESS_KEY_ID : '';
|
||||
$connection['secret_key'] = defined('FLUENTMAIL_AWS_SECRET_ACCESS_KEY') ? FLUENTMAIL_AWS_SECRET_ACCESS_KEY : '';
|
||||
}
|
||||
|
||||
return $connection;
|
||||
}
|
||||
|
||||
private function getSendersFromMappingsAndApi($connection)
|
||||
{
|
||||
$validSenders = $this->getValidSendingIdentities($connection);
|
||||
$verifiedDomain = Arr::get($validSenders, 'verified_domain', '');
|
||||
if ($verifiedDomain) {
|
||||
$settings = fluentMailGetSettings();
|
||||
$mappings = Arr::get($settings, 'mappings', []);
|
||||
|
||||
$mapKey = md5($connection['sender_email']);
|
||||
$mapSenders = array_filter($mappings, function ($key) use ($mapKey) {
|
||||
return $key == $mapKey;
|
||||
});
|
||||
|
||||
$mapSenders[$connection['sender_email']] = true;
|
||||
|
||||
foreach ($validSenders['emails'] as $email) {
|
||||
$mapSenders[$email] = $email;
|
||||
}
|
||||
|
||||
$mapSenders = array_keys($mapSenders);
|
||||
|
||||
} else {
|
||||
$mapSenders = $validSenders['emails'];
|
||||
}
|
||||
|
||||
return [
|
||||
'all_senders' => $mapSenders,
|
||||
'verified_senders' => $validSenders['emails'],
|
||||
'verified_domain' => $verifiedDomain
|
||||
];
|
||||
}
|
||||
}
|
||||
+685
@@ -0,0 +1,685 @@
|
||||
<?php
|
||||
|
||||
namespace FluentMail\App\Services\Mailer\Providers\AmazonSes;
|
||||
|
||||
/**
|
||||
*
|
||||
* 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)
|
||||
*/
|
||||
const AWS_US_EAST_1 = 'email.us-east-1.amazonaws.com';
|
||||
const AWS_US_WEST_2 = 'email.us-west-2.amazonaws.com';
|
||||
const AWS_EU_WEST1 = 'email.eu-west-1.amazonaws.com';
|
||||
|
||||
const REQUEST_SIGNATURE_V3 = 'v3';
|
||||
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 boolean $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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 boolean
|
||||
*/
|
||||
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 boolean
|
||||
*/
|
||||
public function getVerifyPeer()
|
||||
{
|
||||
return $this->__verifyPeer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the verify host CURL mode
|
||||
* @return boolean
|
||||
*/
|
||||
public function getVerifyHost()
|
||||
{
|
||||
return $this->__verifyHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bulk email sending mode
|
||||
* @return boolean
|
||||
* @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 boolean $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 boolean $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 boolean $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 = array('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 = array();
|
||||
if (!isset($ses_response->body)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$domains = array();
|
||||
$addresses = array();
|
||||
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 = array('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 = array('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 = array('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 = array();
|
||||
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 = array('code' => $ses_response->code, 'message' => 'Unexpected HTTP status');
|
||||
}
|
||||
if ($ses_response->error !== false) {
|
||||
$this->__triggerError('getSendStatistics', $ses_response->error);
|
||||
return false;
|
||||
}
|
||||
|
||||
$response = array();
|
||||
if (!isset($ses_response->body)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$datapoints = array();
|
||||
foreach ($ses_response->body->GetSendStatisticsResult->SendDataPoints->member as $datapoint) {
|
||||
$p = array();
|
||||
$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 boolean $use_raw_request If this is true or there are attachments to the email `SendRawEmail` call will be used
|
||||
* @param boolean $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) {
|
||||
$response = array(
|
||||
'code' => $ses_response->code,
|
||||
'error' => array('Error' => array('message' => 'Unexpected HTTP status')),
|
||||
);
|
||||
return $response;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'MessageId' => (string)$ses_response->body->{"{$action}Result"}->MessageId,
|
||||
'RequestId' => (string)$ses_response->body->ResponseMetadata->RequestId,
|
||||
);
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
||||
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 array(
|
||||
'MessageId' => (string)$ses_response->body->SendRawEmailResult->MessageId,
|
||||
'RequestId' => (string)$ses_response->body->ResponseMetadata->RequestId,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
public function getErrorMessage($functionname, $error)
|
||||
{
|
||||
if ($error == false) {
|
||||
return sprintf("SimpleEmailService::%s(): Encountered an error, but no description given", $functionname);
|
||||
} else if (isset($error['curl']) && $error['curl']) {
|
||||
return sprintf("SimpleEmailService::%s(): %s %s", $functionname, $error['code'], $error['message']);
|
||||
} else 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|null $ses_request description
|
||||
* @return SimpleEmailService $this
|
||||
*/
|
||||
public function setRequestHandler($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;
|
||||
}
|
||||
}
|
||||
+640
@@ -0,0 +1,640 @@
|
||||
<?php
|
||||
|
||||
namespace FluentMail\App\Services\Mailer\Providers\AmazonSes;
|
||||
|
||||
/**
|
||||
* SimpleEmailServiceMessage PHP class
|
||||
*
|
||||
* @link https://github.com/daniel-zahariev/php-aws-ses
|
||||
* @package AmazonSimpleEmailService
|
||||
* @version v0.9.1
|
||||
*/
|
||||
final class SimpleEmailServiceMessage {
|
||||
|
||||
// these are public for convenience only
|
||||
// these are not to be used outside of the SimpleEmailService class!
|
||||
public $to, $cc, $bcc, $replyto, $recipientsCharset;
|
||||
public $from, $returnpath;
|
||||
public $subject, $messagetext, $messagehtml;
|
||||
public $subjectCharset, $messageTextCharset, $messageHtmlCharset;
|
||||
public $attachments, $customHeaders, $configuration_set, $message_tags;
|
||||
public $is_clean, $raw_message;
|
||||
public $mime;
|
||||
|
||||
public function __construct() {
|
||||
$this->to = array();
|
||||
$this->cc = array();
|
||||
$this->bcc = array();
|
||||
$this->replyto = array();
|
||||
$this->recipientsCharset = 'UTF-8';
|
||||
|
||||
$this->from = null;
|
||||
$this->returnpath = null;
|
||||
|
||||
$this->subject = null;
|
||||
$this->messagetext = null;
|
||||
$this->messagehtml = null;
|
||||
|
||||
$this->subjectCharset = 'UTF-8';
|
||||
$this->messageTextCharset = 'UTF-8';
|
||||
$this->messageHtmlCharset = 'UTF-8';
|
||||
|
||||
$this->attachments = array();
|
||||
$this->customHeaders = array();
|
||||
$this->configuration_set = null;
|
||||
$this->message_tags = array();
|
||||
|
||||
$this->is_clean = true;
|
||||
$this->raw_message = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* addTo, addCC, addBCC, and addReplyTo have the following behavior:
|
||||
* If a single address is passed, it is appended to the current list of addresses.
|
||||
* If an array of addresses is passed, that array is merged into the current list.
|
||||
*
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
* @link http://docs.aws.amazon.com/ses/latest/APIReference/API_Destination.html
|
||||
*/
|
||||
public function addTo($to) {
|
||||
if (!is_array($to)) {
|
||||
$this->to[] = $to;
|
||||
} else {
|
||||
$this->to = array_unique(array_merge($this->to, $to));
|
||||
}
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
*/
|
||||
public function setTo($to) {
|
||||
$this->to = (array) $to;
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the To: email address(es) for the message
|
||||
*
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
*/
|
||||
public function clearTo() {
|
||||
$this->to = array();
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
* @see addTo()
|
||||
*/
|
||||
public function addCC($cc) {
|
||||
if (!is_array($cc)) {
|
||||
$this->cc[] = $cc;
|
||||
} else {
|
||||
$this->cc = array_merge($this->cc, $cc);
|
||||
}
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the CC: email address(es) for the message
|
||||
*
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
*/
|
||||
public function clearCC() {
|
||||
$this->cc = array();
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
* @see addTo()
|
||||
*/
|
||||
public function addBCC($bcc) {
|
||||
if (!is_array($bcc)) {
|
||||
$this->bcc[] = $bcc;
|
||||
} else {
|
||||
$this->bcc = array_merge($this->bcc, $bcc);
|
||||
}
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the BCC: email address(es) for the message
|
||||
*
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
*/
|
||||
public function clearBCC() {
|
||||
$this->bcc = array();
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
* @see addTo()
|
||||
*/
|
||||
public function addReplyTo($replyto) {
|
||||
if (!is_array($replyto)) {
|
||||
$this->replyto[] = $replyto;
|
||||
} else {
|
||||
$this->replyto = array_merge($this->replyto, $replyto);
|
||||
}
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the Reply-To: email address(es) for the message
|
||||
*
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
*/
|
||||
public function clearReplyTo() {
|
||||
$this->replyto = array();
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all of the message recipients in one go
|
||||
*
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
* @uses clearTo()
|
||||
* @uses clearCC()
|
||||
* @uses clearBCC()
|
||||
* @uses clearReplyTo()
|
||||
*/
|
||||
public function clearRecipients() {
|
||||
$this->clearTo();
|
||||
$this->clearCC();
|
||||
$this->clearBCC();
|
||||
$this->clearReplyTo();
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
*/
|
||||
public function setFrom($from) {
|
||||
$this->from = $from;
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
*/
|
||||
public function setReturnPath($returnpath) {
|
||||
$this->returnpath = $returnpath;
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
*/
|
||||
public function setRecipientsCharset($charset) {
|
||||
$this->recipientsCharset = $charset;
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
*/
|
||||
public function setSubject($subject) {
|
||||
$this->subject = $subject;
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
*/
|
||||
public function setSubjectCharset($charset) {
|
||||
$this->subjectCharset = $charset;
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
* @link http://docs.aws.amazon.com/ses/latest/APIReference/API_Message.html
|
||||
*/
|
||||
public function setMessageFromString($text, $html = null) {
|
||||
$this->messagetext = $text;
|
||||
$this->messagehtml = $html;
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
*/
|
||||
public function setMessageFromFile($textfile, $htmlfile = null) {
|
||||
if (file_exists($textfile) && is_file($textfile) && is_readable($textfile)) {
|
||||
$this->messagetext = file_get_contents($textfile);
|
||||
} else {
|
||||
$this->messagetext = null;
|
||||
}
|
||||
if (file_exists($htmlfile) && is_file($htmlfile) && is_readable($htmlfile)) {
|
||||
$this->messagehtml = file_get_contents($htmlfile);
|
||||
} else {
|
||||
$this->messagehtml = null;
|
||||
}
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
*/
|
||||
public function setMessageFromURL($texturl, $htmlurl = null) {
|
||||
if ($texturl !== null) {
|
||||
$this->messagetext = file_get_contents($texturl);
|
||||
} else {
|
||||
$this->messagetext = null;
|
||||
}
|
||||
if ($htmlurl !== null) {
|
||||
$this->messagehtml = file_get_contents($htmlurl);
|
||||
} else {
|
||||
$this->messagehtml = null;
|
||||
}
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
*/
|
||||
public function setMessageCharset($textCharset, $htmlCharset = null) {
|
||||
$this->messageTextCharset = $textCharset;
|
||||
$this->messageHtmlCharset = $htmlCharset;
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
*/
|
||||
public function setConfigurationSet($configuration_set = null) {
|
||||
$this->configuration_set = $configuration_set;
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array $message_tags
|
||||
*/
|
||||
public function getMessageTags() {
|
||||
return $this->message_tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|mixed $message_tag
|
||||
*/
|
||||
public function getMessageTag($key) {
|
||||
return isset($this->message_tags[$key]) ? $this->message_tags[$key] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Message tag
|
||||
*
|
||||
* Both key and value can contain only ASCII letters (a-z, A-Z), numbers (0-9), underscores (_), or dashes (-) and be less than 256 characters.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
* @link https://docs.aws.amazon.com/ses/latest/DeveloperGuide/event-publishing-send-email.html
|
||||
* @link https://docs.aws.amazon.com/ses/latest/APIReference/API_MessageTag.html
|
||||
*/
|
||||
public function setMessageTag($key, $value) {
|
||||
$this->message_tags[$key] = $value;
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key The key of the tag to be removed
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
*/
|
||||
public function removeMessageTag($key) {
|
||||
unset($this->message_tags[$key]);
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $message_tags
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
*/
|
||||
public function setMessageTags($message_tags = array()) {
|
||||
$this->message_tags = array_merge($this->message_tags, $message_tags);
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
*/
|
||||
public function removeMessageTags() {
|
||||
$this->message_tags = array();
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add custom header - this works only with SendRawEmail
|
||||
*
|
||||
* @param string $header Your custom header
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
* @link( Restrictions on headers, http://docs.aws.amazon.com/ses/latest/DeveloperGuide/header-fields.html)
|
||||
*/
|
||||
public function addCustomHeader($header) {
|
||||
$this->customHeaders[] = $header;
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add email attachment by directly passing the content
|
||||
*
|
||||
* @param string $name The name of the file attachment as it will appear in the email
|
||||
* @param string $data The contents of the attachment file
|
||||
* @param string $mimeType Specify custom MIME type
|
||||
* @param string $contentId Content ID of the attachment for inclusion in the mail message
|
||||
* @param string $attachmentType Attachment type: attachment or inline
|
||||
* @return SimpleEmailServiceMessage $this
|
||||
*/
|
||||
public function addAttachmentFromData($name, $data, $mimeType = 'application/octet-stream', $contentId = null, $attachmentType = 'attachment') {
|
||||
$this->attachments[$name] = array(
|
||||
'name' => $name,
|
||||
'mimeType' => $mimeType,
|
||||
'data' => $data,
|
||||
'contentId' => $contentId,
|
||||
'attachmentType' => ($attachmentType == 'inline' ? 'inline; filename="' . $name . '"' : $attachmentType),
|
||||
);
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add email attachment by passing file path
|
||||
*
|
||||
* @param string $name The name of the file attachment as it will appear in the email
|
||||
* @param string $path Path to the attachment file
|
||||
* @param string $mimeType Specify custom MIME type
|
||||
* @param string $contentId Content ID of the attachment for inclusion in the mail message
|
||||
* @param string $attachmentType Attachment type: attachment or inline
|
||||
* @return boolean Status of the operation
|
||||
*/
|
||||
public function addAttachmentFromFile($name, $path, $mimeType = 'application/octet-stream', $contentId = null, $attachmentType = 'attachment') {
|
||||
if (file_exists($path) && is_file($path) && is_readable($path)) {
|
||||
$this->addAttachmentFromData($name, file_get_contents($path), $mimeType, $contentId, $attachmentType);
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add email attachment by passing file path
|
||||
*
|
||||
* @param string $name The name of the file attachment as it will appear in the email
|
||||
* @param string $url URL to the attachment file
|
||||
* @param string $mimeType Specify custom MIME type
|
||||
* @param string $contentId Content ID of the attachment for inclusion in the mail message
|
||||
* @param string $attachmentType Attachment type: attachment or inline
|
||||
* @return boolean Status of the operation
|
||||
*/
|
||||
public function addAttachmentFromUrl($name, $url, $mimeType = 'application/octet-stream', $contentId = null, $attachmentType = 'attachment') {
|
||||
$data = file_get_contents($url);
|
||||
if ($data !== false) {
|
||||
$this->addAttachmentFromData($name, $data, $mimeType, $contentId, $attachmentType);
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->is_clean = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the existence of attached inline messages
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasInlineAttachments() {
|
||||
foreach ($this->attachments as $attachment) {
|
||||
if ($attachment['attachmentType'] != 'attachment') {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw mail message
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawMessage($encode = true) {
|
||||
if ($this->is_clean && !is_null($this->raw_message) && $encode) {
|
||||
return $this->raw_message;
|
||||
}
|
||||
|
||||
$this->is_clean = true;
|
||||
|
||||
$boundary = uniqid(rand(), true);
|
||||
$raw_message = count($this->customHeaders) > 0 ? join("\n", $this->customHeaders) . "\n" : '';
|
||||
|
||||
if (!empty($this->message_tags)) {
|
||||
$message_tags = array();
|
||||
foreach ($this->message_tags as $key => $value) {
|
||||
$message_tags[] = "{$key}={$value}";
|
||||
}
|
||||
|
||||
$raw_message .= 'X-SES-MESSAGE-TAGS: ' . join(', ', $message_tags) . "\n";
|
||||
}
|
||||
|
||||
if (!is_null($this->configuration_set)) {
|
||||
$raw_message .= 'X-SES-CONFIGURATION-SET: ' . $this->configuration_set . "\n";
|
||||
}
|
||||
|
||||
$raw_message .= count($this->to) > 0 ? 'To: ' . $this->encodeRecipients($this->to) . "\n" : '';
|
||||
$raw_message .= 'From: ' . $this->encodeRecipients($this->from) . "\n";
|
||||
if (!empty($this->replyto)) {
|
||||
$raw_message .= 'Reply-To: ' . $this->encodeRecipients($this->replyto) . "\n";
|
||||
}
|
||||
|
||||
if (!empty($this->cc)) {
|
||||
$raw_message .= 'CC: ' . $this->encodeRecipients($this->cc) . "\n";
|
||||
}
|
||||
if (!empty($this->bcc)) {
|
||||
$raw_message .= 'BCC: ' . $this->encodeRecipients($this->bcc) . "\n";
|
||||
}
|
||||
|
||||
if ($this->subject != null && strlen($this->subject) > 0) {
|
||||
$raw_message .= 'Subject: =?' . $this->subjectCharset . '?B?' . base64_encode($this->subject) . "?=\n";
|
||||
}
|
||||
|
||||
$raw_message .= 'MIME-Version: 1.0' . "\n";
|
||||
$raw_message .= 'Content-type: ' . ($this->hasInlineAttachments() ? 'multipart/related' : 'Multipart/Mixed') . '; boundary="' . $boundary . '"' . "\n";
|
||||
$raw_message .= "\n--{$boundary}\n";
|
||||
$raw_message .= 'Content-type: Multipart/Alternative; boundary="alt-' . $boundary . '"' . "\n";
|
||||
|
||||
if ($this->messagetext != null && strlen($this->messagetext) > 0) {
|
||||
$charset = empty($this->messageTextCharset) ? '' : "; charset=\"{$this->messageTextCharset}\"";
|
||||
$raw_message .= "\n--alt-{$boundary}\n";
|
||||
$raw_message .= 'Content-Type: text/plain' . $charset . "\n\n";
|
||||
$raw_message .= $this->messagetext . "\n";
|
||||
}
|
||||
|
||||
|
||||
if ($this->messagehtml != null && strlen($this->messagehtml) > 0) {
|
||||
$charset = empty($this->messageHtmlCharset) ? '' : "; charset=\"{$this->messageHtmlCharset}\"";
|
||||
$raw_message .= "\n--alt-{$boundary}\n";
|
||||
$raw_message .= 'Content-Type: text/html' . $charset . "\n\n";
|
||||
$raw_message .= $this->messagehtml . "\n";
|
||||
}
|
||||
$raw_message .= "\n--alt-{$boundary}--\n";
|
||||
|
||||
foreach ($this->attachments as $attachment) {
|
||||
$raw_message .= "\n--{$boundary}\n";
|
||||
$raw_message .= 'Content-Type: ' . $attachment['mimeType'] . '; name="' . $attachment['name'] . '"' . "\n";
|
||||
$raw_message .= 'Content-Disposition: ' . $attachment['attachmentType'] . "\n";
|
||||
if (!empty($attachment['contentId'])) {
|
||||
$raw_message .= 'Content-ID: ' . $attachment['contentId'] . '' . "\n";
|
||||
}
|
||||
$raw_message .= 'Content-Transfer-Encoding: base64' . "\n";
|
||||
$raw_message .= "\n" . chunk_split(base64_encode($attachment['data']), 76, "\n") . "\n";
|
||||
}
|
||||
|
||||
$raw_message .= "\n--{$boundary}--\n";
|
||||
|
||||
if (!$encode) {
|
||||
return $raw_message;
|
||||
}
|
||||
|
||||
$this->raw_message = base64_encode($raw_message);
|
||||
|
||||
return $this->raw_message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode recipient with the specified charset in `recipientsCharset`
|
||||
*
|
||||
* @return string Encoded recipients joined with comma
|
||||
*/
|
||||
public function encodeRecipients($recipient) {
|
||||
if (is_array($recipient)) {
|
||||
return join(', ', array_map(array($this, 'encodeRecipients'), $recipient));
|
||||
}
|
||||
|
||||
if (preg_match("/(.*)<(.*)>/", $recipient, $regs)) {
|
||||
$recipient = '=?' . $this->recipientsCharset . '?B?' . base64_encode($regs[1]) . '?= <' . $regs[2] . '>';
|
||||
}
|
||||
|
||||
return $recipient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates whether the message object has sufficient information to submit a request to SES.
|
||||
*
|
||||
* This does not guarantee the message will arrive, nor that the request will succeed;
|
||||
* instead, it makes sure that no required fields are missing.
|
||||
*
|
||||
* This is used internally before attempting a SendEmail or SendRawEmail request,
|
||||
* but it can be used outside of this file if verification is desired.
|
||||
* May be useful if e.g. the data is being populated from a form; developers can generally
|
||||
* use this function to verify completeness instead of writing custom logic.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function validate() {
|
||||
// at least one destination is required
|
||||
if (count($this->to) == 0 && count($this->cc) == 0 && count($this->bcc) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// sender is required
|
||||
if ($this->from == null || strlen($this->from) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// subject is required
|
||||
if (($this->subject == null || strlen($this->subject) == 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// message is required
|
||||
if ((empty($this->messagetext) || strlen((string) $this->messagetext) == 0)
|
||||
&& (empty($this->messagehtml) || strlen((string) $this->messagehtml) == 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+376
@@ -0,0 +1,376 @@
|
||||
<?php
|
||||
|
||||
namespace FluentMail\App\Services\Mailer\Providers\AmazonSes;
|
||||
|
||||
/**
|
||||
* SimpleEmailServiceRequest PHP class
|
||||
*
|
||||
* @link https://github.com/daniel-zahariev/php-aws-ses
|
||||
* @package AmazonSimpleEmailService
|
||||
* @version v0.9.1
|
||||
*/
|
||||
class SimpleEmailServiceRequest
|
||||
{
|
||||
private $ses, $verb, $parameters = array();
|
||||
|
||||
// CURL request handler that can be reused
|
||||
protected $curl_handler = null;
|
||||
|
||||
// Holds the response from calling AWS's API
|
||||
protected $response;
|
||||
|
||||
//
|
||||
public static $curlOptions = array();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param SimpleEmailService $ses The SimpleEmailService object making this request
|
||||
* @param string $verb HTTP verb
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($ses = null, $verb = 'GET') {
|
||||
$this->ses = $ses;
|
||||
$this->verb = $verb;
|
||||
$this->response = (object) array('body' => '', 'code' => 0, 'error' => false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set SES class
|
||||
*
|
||||
* @param SimpleEmailService $ses
|
||||
* @return SimpleEmailServiceRequest $this
|
||||
*/
|
||||
public function setSES(SimpleEmailService $ses) {
|
||||
$this->ses = $ses;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set HTTP method
|
||||
*
|
||||
* @param string $verb
|
||||
* @return SimpleEmailServiceRequest $this
|
||||
*/
|
||||
public function setVerb($verb) {
|
||||
$this->verb = $verb;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set request parameter
|
||||
*
|
||||
* @param string $key Key
|
||||
* @param string $value Value
|
||||
* @param boolean $replace Whether to replace the key if it already exists (default true)
|
||||
* @return SimpleEmailServiceRequest $this
|
||||
*/
|
||||
public function setParameter($key, $value, $replace = true) {
|
||||
if(!$replace && isset($this->parameters[$key])) {
|
||||
$temp = (array)($this->parameters[$key]);
|
||||
$temp[] = $value;
|
||||
$this->parameters[$key] = $temp;
|
||||
} else {
|
||||
$this->parameters[$key] = $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the params for the request
|
||||
*
|
||||
* @return array $params
|
||||
*/
|
||||
public function getParametersEncoded() {
|
||||
$params = array();
|
||||
|
||||
foreach ($this->parameters as $var => $value) {
|
||||
if(is_array($value)) {
|
||||
foreach($value as $v) {
|
||||
$params[] = $var.'='.$this->__customUrlEncode($v);
|
||||
}
|
||||
} else {
|
||||
$params[] = $var.'='.$this->__customUrlEncode($value);
|
||||
}
|
||||
}
|
||||
|
||||
sort($params, SORT_STRING);
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the request parameters
|
||||
* @return SimpleEmailServiceRequest $this
|
||||
*/
|
||||
public function clearParameters() {
|
||||
$this->parameters = array();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate and setup CURL handler for sending requests.
|
||||
* Instance is cashed in `$this->curl_handler`
|
||||
*
|
||||
* @return resource $curl_handler
|
||||
*/
|
||||
protected function getCurlHandler() {
|
||||
if (!empty($this->curl_handler))
|
||||
return $this->curl_handler;
|
||||
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_USERAGENT, 'SimpleEmailService/php');
|
||||
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, ($this->ses->verifyHost() ? 2 : 0));
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, ($this->ses->verifyPeer() ? 1 : 0));
|
||||
curl_setopt($curl, CURLOPT_HEADER, false);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);
|
||||
curl_setopt($curl, CURLOPT_WRITEFUNCTION, array(&$this, '__responseWriteCallback'));
|
||||
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
|
||||
|
||||
foreach(self::$curlOptions as $option => $value) {
|
||||
curl_setopt($curl, $option, $value);
|
||||
}
|
||||
|
||||
$this->curl_handler = $curl;
|
||||
|
||||
return $this->curl_handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response
|
||||
*
|
||||
* @return object | false
|
||||
*/
|
||||
public function getResponse() {
|
||||
|
||||
$url = 'https://'.$this->ses->getHost().'/';
|
||||
$query = implode('&', $this->getParametersEncoded());
|
||||
$headers = $this->getHeaders($query);
|
||||
|
||||
$curl_handler = $this->getCurlHandler();
|
||||
curl_setopt($curl_handler, CURLOPT_CUSTOMREQUEST, $this->verb);
|
||||
|
||||
// Request types
|
||||
switch ($this->verb) {
|
||||
case 'GET':
|
||||
case 'DELETE':
|
||||
$url .= '?'.$query;
|
||||
break;
|
||||
|
||||
case 'POST':
|
||||
curl_setopt($curl_handler, CURLOPT_POSTFIELDS, $query);
|
||||
$headers[] = 'Content-Type: application/x-www-form-urlencoded';
|
||||
break;
|
||||
}
|
||||
curl_setopt($curl_handler, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($curl_handler, CURLOPT_URL, $url);
|
||||
|
||||
|
||||
// Execute, grab errors
|
||||
if (curl_exec($curl_handler)) {
|
||||
$this->response->code = curl_getinfo($curl_handler, CURLINFO_HTTP_CODE);
|
||||
} else {
|
||||
$this->response->error = array(
|
||||
'curl' => true,
|
||||
'code' => curl_errno($curl_handler),
|
||||
'message' => curl_error($curl_handler),
|
||||
);
|
||||
}
|
||||
|
||||
// cleanup for reusing the current instance for multiple requests
|
||||
curl_setopt($curl_handler, CURLOPT_POSTFIELDS, '');
|
||||
$this->parameters = array();
|
||||
|
||||
// Parse body into XML
|
||||
if ($this->response->error === false && !empty($this->response->body)) {
|
||||
$this->response->body = simplexml_load_string($this->response->body);
|
||||
|
||||
// Grab SES errors
|
||||
if (!in_array($this->response->code, array(200, 201, 202, 204))
|
||||
&& isset($this->response->body->Error)) {
|
||||
$error = $this->response->body->Error;
|
||||
$output = array();
|
||||
$output['curl'] = false;
|
||||
$output['Error'] = array();
|
||||
$output['Error']['Type'] = (string)$error->Type;
|
||||
$output['Error']['Code'] = (string)$error->Code;
|
||||
$output['Error']['Message'] = (string)$error->Message;
|
||||
$output['RequestId'] = (string)$this->response->body->RequestId;
|
||||
|
||||
$this->response->error = $output;
|
||||
unset($this->response->body);
|
||||
}
|
||||
}
|
||||
|
||||
$response = $this->response;
|
||||
$this->response = (object) array('body' => '', 'code' => 0, 'error' => false);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get request headers
|
||||
* @param string $query
|
||||
* @return array
|
||||
*/
|
||||
protected function getHeaders($query) {
|
||||
$headers = array();
|
||||
|
||||
if ($this->ses->getRequestSignatureVersion() == SimpleEmailService::REQUEST_SIGNATURE_V4) {
|
||||
$date = (new \DateTime('now', new \DateTimeZone('UTC')))->format('Ymd\THis\Z');
|
||||
$headers[] = 'X-Amz-Date: ' . $date;
|
||||
$headers[] = 'Host: ' . $this->ses->getHost();
|
||||
$headers[] = 'Authorization: ' . $this->__getAuthHeaderV4($date, $query);
|
||||
|
||||
} else {
|
||||
// must be in format 'Sun, 06 Nov 1994 08:49:37 GMT'
|
||||
$date = gmdate('D, d M Y H:i:s e');
|
||||
$auth = 'AWS3-HTTPS AWSAccessKeyId='.$this->ses->getAccessKey();
|
||||
$auth .= ',Algorithm=HmacSHA256,Signature='.$this->__getSignature($date);
|
||||
|
||||
$headers[] = 'Date: ' . $date;
|
||||
$headers[] = 'Host: ' . $this->ses->getHost();
|
||||
$headers[] = 'X-Amzn-Authorization: ' . $auth;
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy any leftover handlers
|
||||
*/
|
||||
public function __destruct() {
|
||||
if (!empty($this->curl_handler))
|
||||
@curl_close($this->curl_handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* CURL write callback
|
||||
*
|
||||
* @param resource $curl CURL resource
|
||||
* @param string $data Data
|
||||
* @return integer
|
||||
*/
|
||||
private function __responseWriteCallback($curl, $data) {
|
||||
if (!isset($this->response->body)) {
|
||||
$this->response->body = $data;
|
||||
} else {
|
||||
$this->response->body .= $data;
|
||||
}
|
||||
|
||||
return strlen($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contributed by afx114
|
||||
* URL encode the parameters as per http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/index.html?Query_QueryAuth.html
|
||||
* PHP's rawurlencode() follows RFC 1738, not RFC 3986 as required by Amazon. The only difference is the tilde (~), so convert it back after rawurlencode
|
||||
* See: http://www.morganney.com/blog/API/AWS-Product-Advertising-API-Requires-a-Signed-Request.php
|
||||
*
|
||||
* @param string $var String to encode
|
||||
* @return string
|
||||
*/
|
||||
private function __customUrlEncode($var) {
|
||||
return str_replace('%7E', '~', rawurlencode($var));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the auth string using Hmac-SHA256
|
||||
*
|
||||
* @internal Used by SimpleEmailServiceRequest::getResponse()
|
||||
* @param string $string String to sign
|
||||
* @return string
|
||||
*/
|
||||
private function __getSignature($string) {
|
||||
return base64_encode(hash_hmac('sha256', $string, $this->ses->getSecretKey(), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param string $dateStamp
|
||||
* @param string $regionName
|
||||
* @param string $serviceName
|
||||
* @param string $algo
|
||||
* @return string
|
||||
*/
|
||||
private function __getSigningKey($key, $dateStamp, $regionName, $serviceName, $algo) {
|
||||
$kDate = hash_hmac($algo, $dateStamp, 'AWS4' . $key, true);
|
||||
$kRegion = hash_hmac($algo, $regionName, $kDate, true);
|
||||
$kService = hash_hmac($algo, $serviceName, $kRegion, true);
|
||||
|
||||
return hash_hmac($algo,'aws4_request', $kService, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of AWS Signature Version 4
|
||||
* @see https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html
|
||||
* @param string $amz_datetime
|
||||
* @param string $query
|
||||
* @return string
|
||||
*/
|
||||
private function __getAuthHeaderV4($amz_datetime, $query) {
|
||||
$amz_date = substr($amz_datetime, 0, 8);
|
||||
$algo = 'sha256';
|
||||
$aws_algo = 'AWS4-HMAC-' . strtoupper($algo);
|
||||
|
||||
$host_parts = explode('.', $this->ses->getHost());
|
||||
$service = $host_parts[0];
|
||||
$region = $host_parts[1];
|
||||
|
||||
$canonical_uri = '/';
|
||||
if($this->verb === 'POST') {
|
||||
$canonical_querystring = '';
|
||||
$payload_data = $query;
|
||||
} else {
|
||||
$canonical_querystring = $query;
|
||||
$payload_data = '';
|
||||
}
|
||||
|
||||
// ************* TASK 1: CREATE A CANONICAL REQUEST *************
|
||||
$canonical_headers_list = [
|
||||
'host:' . $this->ses->getHost(),
|
||||
'x-amz-date:' . $amz_datetime
|
||||
];
|
||||
|
||||
$canonical_headers = implode("\n", $canonical_headers_list) . "\n";
|
||||
$signed_headers = 'host;x-amz-date';
|
||||
$payload_hash = hash($algo, $payload_data, false);
|
||||
|
||||
$canonical_request = implode("\n", array(
|
||||
$this->verb,
|
||||
$canonical_uri,
|
||||
$canonical_querystring,
|
||||
$canonical_headers,
|
||||
$signed_headers,
|
||||
$payload_hash
|
||||
));
|
||||
|
||||
// ************* TASK 2: CREATE THE STRING TO SIGN*************
|
||||
$credential_scope = $amz_date. '/' . $region . '/' . $service . '/' . 'aws4_request';
|
||||
$string_to_sign = implode("\n", array(
|
||||
$aws_algo,
|
||||
$amz_datetime,
|
||||
$credential_scope,
|
||||
hash($algo, $canonical_request, false)
|
||||
));
|
||||
|
||||
// ************* TASK 3: CALCULATE THE SIGNATURE *************
|
||||
// Create the signing key using the function defined above.
|
||||
$signing_key = $this->__getSigningKey($this->ses->getSecretKey(), $amz_date, $region, $service, $algo);
|
||||
|
||||
// Sign the string_to_sign using the signing_key
|
||||
$signature = hash_hmac($algo, $string_to_sign, $signing_key, false);
|
||||
|
||||
// ************* TASK 4: ADD SIGNING INFORMATION TO THE REQUEST *************
|
||||
return $aws_algo . ' ' . implode(', ', array(
|
||||
'Credential=' . $this->ses->getAccessKey() . '/' . $credential_scope,
|
||||
'SignedHeaders=' . $signed_headers ,
|
||||
'Signature=' . $signature
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace FluentMail\App\Services\Mailer\Providers\AmazonSes;
|
||||
|
||||
use FluentMail\App\Models\Settings;
|
||||
use FluentMail\Includes\Support\Arr;
|
||||
use FluentMail\Includes\Support\ValidationException;
|
||||
use FluentMail\App\Services\Mailer\Providers\AmazonSes\SimpleEmailService;
|
||||
|
||||
class Validator
|
||||
{
|
||||
protected $errors = null;
|
||||
|
||||
protected $provider = null;
|
||||
|
||||
public function __construct($provider, $errors)
|
||||
{
|
||||
$this->errors = $errors;
|
||||
$this->provider = $provider;
|
||||
}
|
||||
|
||||
public function validate()
|
||||
{
|
||||
|
||||
$data = fluentMail('request')->except(['action', 'nonce']);
|
||||
|
||||
$inputs = Arr::only(
|
||||
$data['provider']['options'], ['access_key', 'secret_key', 'region']
|
||||
);
|
||||
|
||||
$ses = new SimpleEmailService(
|
||||
$inputs['access_key'],
|
||||
$inputs['secret_key'],
|
||||
'email.' . $inputs['region'] . '.amazonaws.com',
|
||||
false
|
||||
);
|
||||
|
||||
$result = $ses->listVerifiedEmailAddresses();
|
||||
|
||||
if (is_wp_error($result)) {
|
||||
throw new ValidationException(wp_kses_post($result->get_error_message()), 400);
|
||||
}
|
||||
|
||||
if ($result) {
|
||||
$senderEmail = Arr::get(
|
||||
$data, 'provider.options.sender_email'
|
||||
);
|
||||
|
||||
if (!in_array($senderEmail, $result['Addresses'])) {
|
||||
throw new \Exception(esc_html__('The from email is not verified', 'fluent-smtp'), 400);
|
||||
}
|
||||
|
||||
fluentMail(Settings::class)->saveVerifiedEmails($result['Addresses']);
|
||||
}
|
||||
}
|
||||
|
||||
public function errorHandler($errno, $errstr, $errfile, $errline, $errcontext)
|
||||
{
|
||||
if (isset($errcontext['e'])) {
|
||||
$message = $errcontext['e']['Message'];
|
||||
} else {
|
||||
$message = $errcontext['error']['message'];
|
||||
}
|
||||
|
||||
$newException = new ValidationException(
|
||||
'', $errno, null, array_merge(
|
||||
$this->errors, [
|
||||
'sender_email' => [
|
||||
$errcontext['functionname'] => $message
|
||||
]
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
restore_error_handler();
|
||||
|
||||
throw $newException;
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace FluentMail\App\Services\Mailer\Providers\AmazonSes;
|
||||
|
||||
use FluentMail\Includes\Support\Arr;
|
||||
use FluentMail\App\Services\Mailer\ValidatorTrait as BaseValidatorTrait;
|
||||
|
||||
trait ValidatorTrait
|
||||
{
|
||||
use BaseValidatorTrait;
|
||||
|
||||
public function validateProviderInformation($connection)
|
||||
{
|
||||
$errors = [];
|
||||
|
||||
$keyStoreType = $connection['key_store'];
|
||||
|
||||
if ($keyStoreType == 'db') {
|
||||
if (!Arr::get($connection, 'access_key')) {
|
||||
$errors['access_key']['required'] = __('Access key is required.', 'fluent-smtp');
|
||||
}
|
||||
|
||||
if (!Arr::get($connection, 'secret_key')) {
|
||||
$errors['secret_key']['required'] = __('Secret key is required.', 'fluent-smtp');
|
||||
}
|
||||
} else if ($keyStoreType == 'wp_config') {
|
||||
if (!defined('FLUENTMAIL_AWS_ACCESS_KEY_ID') || !FLUENTMAIL_AWS_ACCESS_KEY_ID) {
|
||||
$errors['access_key']['required'] = __('Please define FLUENTMAIL_AWS_ACCESS_KEY_ID in wp-config.php file.', 'fluent-smtp');
|
||||
}
|
||||
|
||||
if (!defined('FLUENTMAIL_AWS_SECRET_ACCESS_KEY') || !FLUENTMAIL_AWS_SECRET_ACCESS_KEY) {
|
||||
$errors['secret_key']['required'] = __('Please define FLUENTMAIL_AWS_SECRET_ACCESS_KEY in wp-config.php file.', 'fluent-smtp');
|
||||
}
|
||||
}
|
||||
|
||||
if ($errors) {
|
||||
$this->throwValidationException($errors);
|
||||
}
|
||||
}
|
||||
|
||||
public function checkConnection($connection)
|
||||
{
|
||||
$connection = $this->filterConnectionVars($connection);
|
||||
$region = 'email.' . $connection['region'] . '.amazonaws.com';
|
||||
|
||||
$ses = new SimpleEmailService(
|
||||
$connection['access_key'],
|
||||
$connection['secret_key'],
|
||||
$region,
|
||||
true
|
||||
);
|
||||
|
||||
$lists = $ses->listVerifiedEmailAddresses();
|
||||
|
||||
if (is_wp_error($lists)) {
|
||||
$this->throwValidationException(['api_error' => $lists->get_error_message()]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user