Commit inicial - WordPress Análisis de Precios Unitarios

- WordPress core y plugins
- Tema Twenty Twenty-Four configurado
- Plugin allow-unfiltered-html.php simplificado
- .gitignore configurado para excluir wp-config.php y uploads

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2025-11-03 21:04:30 -06:00
commit a22573bf0b
24068 changed files with 4993111 additions and 0 deletions

View File

@@ -0,0 +1,450 @@
<?php
namespace FluentMail\App\Services\Mailer;
use Exception;
use InvalidArgumentException;
use FluentMail\App\Models\Logger;
use FluentMail\Includes\Support\Arr;
use FluentMail\Includes\Core\Application;
use FluentMail\App\Services\Mailer\Manager;
use FluentMail\App\Services\Mailer\ValidatorTrait;
class BaseHandler
{
use ValidatorTrait;
protected $app = null;
protected $params = [];
protected $manager = null;
protected $phpMailer = null;
protected $settings = [];
protected $attributes = [];
protected $response = null;
protected $existing_row_id = null;
public function __construct(?Application $app = null, ?Manager $manager = null)
{
$this->app = $app ?: fluentMail();
$this->manager = $manager ?: fluentMail(Manager::class);
}
public function setPhpMailer($phpMailer)
{
$this->phpMailer = $phpMailer;
if(!$this->phpMailer->CharSet) {
$this->phpMailer->CharSet = 'UTF-8';
}
return $this;
}
public function setSettings($settings)
{
$this->settings = $settings;
return $this;
}
protected function preSend()
{
$this->attributes = [];
if ($this->isForced('from_name')) {
$this->phpMailer->FromName = $this->getSetting('sender_name');
}
if ($this->getSetting('return_path') == 'yes') {
$this->phpMailer->Sender = $this->phpMailer->From;
}
$this->attributes = $this->setAttributes();
return true;
}
protected function isForced($key)
{
return $this->getSetting("force_{$key}") == 'yes';
}
public function isForcedEmail()
{
return $this->getSetting("force_from_email") != 'no';
}
public function isActive()
{
return $this->getSetting('is_active') == 'yes';
}
protected function getDefaultParams()
{
$timeout = (int)ini_get('max_execution_time');
return [
'timeout' => $timeout ?: 30,
'httpversion' => '1.1',
'blocking' => true,
];
}
protected function setAttributes()
{
$from = $this->setFrom();
$replyTos = $this->setRecipientsArray(array_values(
$this->phpMailer->getReplyToAddresses()
));
$contentType = $this->phpMailer->ContentType;
$customHeaders = $this->setFormattedCustomHeaders();
$recipients = [
'to' => $this->setRecipientsArray($this->phpMailer->getToAddresses()),
'cc' => $this->setRecipientsArray($this->phpMailer->getCcAddresses()),
'bcc' => $this->setRecipientsArray($this->phpMailer->getBccAddresses())
];
return array_merge($this->attributes, [
'from' => $from,
'to' => $recipients['to'],
'subject' => $this->phpMailer->Subject,
'message' => $this->phpMailer->Body,
'alt_body' => $this->phpMailer->AltBody,
'attachments' => $this->phpMailer->getAttachments(),
'custom_headers' => $customHeaders,
'headers' => [
'reply-to' => $replyTos,
'cc' => $recipients['cc'],
'bcc' => $recipients['bcc'],
'content-type' => $contentType
]
]);
}
protected function setFrom()
{
$name = $this->getSetting('sender_name');
$email = $this->getSetting('sender_email');
$overrideName = $this->getSetting('force_from_name');
if ($name && ($overrideName == 'yes' || $this->phpMailer->FromName == 'WordPress')) {
$this->attributes['sender_name'] = $name;
$this->attributes['sender_email'] = $email;
$from = $name . ' <' . $email . '>';
} elseif ($this->phpMailer->FromName) {
$this->attributes['sender_email'] = $email;
$this->attributes['sender_name'] = $this->phpMailer->FromName;
$from = $this->phpMailer->FromName . ' <' . $email . '>';
} else {
$from = $this->attributes['sender_email'] = $email;
}
return $from;
}
protected function setRecipientsArray($array)
{
$recipients = [];
foreach ($array as $key => $recipient) {
$recipient = array_filter($recipient);
if (!$recipient) continue;
$recipients[$key] = [
'email' => array_shift($recipient)
];
if ($recipient) {
$recipients[$key]['name'] = array_shift($recipient);
}
}
return $recipients;
}
protected function setFormattedCustomHeaders()
{
$headers = [];
$customHeaders = $this->phpMailer->getCustomHeaders();
foreach ($customHeaders as $key => $header) {
if ($header[0] == 'Return-Path') {
if ($this->getSetting('options.return_path') == 'no') {
if (!empty($header[1])) {
$this->phpMailer->Sender = $header[1];
}
}
unset($customHeaders[$key]);
} else {
$headers[] = [
'key' => $header[0],
'value' => $header[1]
];
}
}
$this->phpMailer->clearCustomHeaders();
foreach ($customHeaders as $customHeader) {
$this->phpMailer->addCustomHeader($customHeader[0], $customHeader[1]);
}
return $headers;
}
public function getSetting($key = null, $default = null)
{
try {
return $key ? Arr::get($this->settings, $key, $default) : $this->settings;
} catch (Exception $e) {
return $default;
}
}
protected function getParam($key = null, $default = null)
{
try {
return $key ? Arr::get($this->attributes, $key, $default) : $this->attributes;
} catch (Exception $e) {
return $default;
}
}
protected function getHeader($key, $default = null)
{
try {
return Arr::get(
$this->attributes['headers'], $key, $default
);
} catch (Exception $e) {
return $default;
}
}
public function getSubject()
{
$subject = '';
if (isset($this->attributes['subject'])) {
$subject = $this->attributes['subject'];
}
return $subject;
}
protected function getExtraParams()
{
$this->attributes['extra']['provider'] = $this->getSetting('provider');
return $this->attributes['extra'];
}
public function handleResponse($response)
{
if ( is_wp_error($response) ) {
$code = $response->get_error_code();
if (!is_numeric($code)) {
$code = 400;
}
$message = $response->get_error_message();
$errorResponse = [
'code' => $code,
'message' => $message,
'errors' => $response->get_error_data()
];
$status = $this->processResponse($errorResponse, false);
if ( !$status ) {
throw new \PHPMailer\PHPMailer\Exception($message, $code); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
} else {
return $status;
}
} else {
return $this->processResponse($response, true);
}
}
public function processResponse($response, $status)
{
if ($this->shouldBeLogged($status)) {
$data = [
'to' => $this->serialize($this->attributes['to']),
'from' => $this->attributes['from'],
'subject' => sanitize_text_field($this->attributes['subject']),
'body' => $this->attributes['message'],
'attachments' => $this->serialize($this->attributes['attachments']),
'status' => $status ? 'sent' : 'failed',
'response' => $this->serialize($response),
'headers' => $this->serialize($this->getParam('headers')),
'extra' => $this->serialize($this->getExtraParams())
];
if($this->existing_row_id) {
$row = (new Logger())->find($this->existing_row_id);
if($row) {
$row['response'] = (array) $row['response'];
if($status) {
$row['response']['fallback'] = __('Sent using fallback connection ', 'fluent-smtp') . $this->attributes['from'];
$row['response']['fallback_response'] = $response;
} else {
$row['response']['fallback'] = __('Tried to send using fallback but failed. ', 'fluent-smtp') . $this->attributes['from'];
$row['response']['fallback_response'] = $response;
}
$data['response'] = $this->serialize( $row['response']);
$data['retries'] = $row['retries'] + 1;
(new Logger())->updateLog($data, ['id' => $row['id']]);
if(!$status) {
do_action('fluentmail_email_sending_failed_no_fallback', $row['id'], $this, $data);
}
}
} else {
$logId = (new Logger)->add($data);
if(!$status) {
// We have to fire an action for this failed job
$status = apply_filters('fluentmail_email_sending_failed', $status, $logId, $this, $data);
}
}
}
return $status;
}
protected function shouldBeLogged($status)
{
if($this->existing_row_id) {
return true;
}
if (defined('FLUENTMAIL_LOG_OFF') && FLUENTMAIL_LOG_OFF) {
return false;
}
if (!$status) {
return true;
}
$miscSettings = $this->manager->getConfig('misc');
$isLogOn = $miscSettings['log_emails'] == 'yes';
return apply_filters('fluentmail_will_log_email', $isLogOn, $miscSettings, $this);
}
protected function serialize(array $data)
{
foreach ($data as $key => $item) {
if (is_array($item)) {
$this->serialize($item);
}
if (is_object($item) || is_resource($item)) {
throw new InvalidArgumentException(
"Invalid Data: Array cannot contain an object or resource."
);
}
if (is_string($item)) {
if (is_serialized($item)) {
throw new InvalidArgumentException(
"Invalid Data: Array cannot contain serialized data."
);
}
if (filter_var($item, FILTER_VALIDATE_EMAIL)) {
$data[$key] = sanitize_email($item);
} elseif (filter_var($item, FILTER_VALIDATE_URL)) {
$data[$key] = esc_url_raw($item);
} else {
$data[$key] = sanitize_text_field($item);
}
}
}
return serialize($data);
}
protected function fireWPMailFailedAction($data)
{
$code = is_numeric($data['code']) ? $data['code'] : 400;
$code = strlen($code) < 3 ? 400 : $code;
$mail_error_data['phpmailer_exception_code'] = $code;
$mail_error_data['errors'] = $data['errors'];
$error = new \WP_Error(
$code, $data['message'], $mail_error_data
);
$this->app->doAction('wp_mail_failed', $error);
}
protected function updatedLog($id, $data)
{
try {
$data['updated_at'] = current_time('mysql');
(new Logger)->updateLog($data, ['id' => $id]);
} catch (Exception $e) {
error_log($e->getMessage());
}
}
public function getValidSenders($connection)
{
return [$connection['sender_email']];
}
public function checkConnection($connection)
{
return true;
}
public function getConnectionInfo($connection)
{
return [
'info' => (string) fluentMail('view')->make('admin.general_connection_info', [
'connection' => $connection
])
];
}
public function getPhpMailer()
{
return $this->phpMailer;
}
public function setRowId($id)
{
$this->existing_row_id = $id;
}
public function addNewSenderEmail($connection, $email)
{
return new \WP_Error('not_implemented', __('Not implemented', 'fluent-smtp'));
}
public function removeSenderEmail($connection, $email)
{
return new \WP_Error('not_implemented', __('Not implemented', 'fluent-smtp'));
}
}

View File

@@ -0,0 +1,58 @@
<?php
namespace FluentMail\App\Services\Mailer;
use FluentMail\App\Models\Logger;
use FluentMail\App\Services\Mailer\Providers\Factory;
use FluentMail\App\Services\Mailer\Providers\DefaultMail\Handler as PHPMailer;
class FluentPHPMailer
{
protected $app = null;
protected $phpMailer = null;
public function __construct($phpMailer)
{
$this->app = fluentMail();
$this->phpMailer = $phpMailer;
}
public function send()
{
if ($driver = fluentMailGetProvider($this->phpMailer->From)) {
if ($forceFromEmail = $driver->getSetting('force_from_email_id')) {
$this->phpMailer->From = $forceFromEmail;
}
return $driver->setPhpMailer($this->phpMailer)->send();
}
return $this->phpMailer->send();
}
public function sendViaFallback($rowId)
{
$driver = fluentMailGetProvider($this->phpMailer->From);
if($driver) {
$driver->setRowId($rowId);
return $driver->setPhpMailer($this->phpMailer)->send();
}
return false;
}
public function __get($key)
{
return $this->phpMailer->{$key};
}
public function __set($key, $value)
{
$this->phpMailer->{$key} = $value;
}
public function __call($method, $params)
{
return call_user_func_array([$this->phpMailer, $method], $params);
}
}

View File

@@ -0,0 +1,103 @@
<?php
namespace FluentMail\App\Services\Mailer;
use FluentMail\App\Models\Logger;
use FluentMail\App\Models\Settings;
use FluentMail\Includes\Support\Arr;
use FluentMail\Includes\Core\Application;
use FluentMail\Includes\Support\ValidationException;
use FluentMail\App\Services\Mailer\Providers\Factory;
class Manager
{
protected $app = null;
protected static $config = [];
protected static $settings = [];
protected static $resolved = [];
protected static $wpConfigSettings = [];
public function __construct(?Application $app = null)
{
$this->app = $app ?: fluentMail();
$this->initialize();
}
protected function initialize()
{
$this->loadConfigAndSettings();
$this->app->addCustomFilter('active_driver', [$this, 'activeDriver']);
}
protected function loadConfigAndSettings()
{
static::$config = require(__DIR__ . '/Providers/config.php');
static::$settings = (new Settings)->getSettings();
$this->mergeConfigAndSettings();
}
protected function mergeConfigAndSettings()
{
$databaseSettings = $this->getSettings();
Arr::set(static::$config, 'mappings', Arr::get($databaseSettings, 'mappings'));
Arr::set(static::$config, 'connections', Arr::get($databaseSettings, 'connections'));
if (isset($databaseSettings['misc'])) {
Arr::set(static::$config, "misc", array_merge(
static::$config['misc'], $databaseSettings['misc']
));
}
foreach (static::$config['providers'] as $key => $provider) {
try {
$optionKey = "providers.{$key}.options";
$options = array_merge(
$provider['options'],
Arr::get($databaseSettings, $optionKey, [])
);
Arr::set(static::$config, $optionKey, $options);
} catch (ValidationException $e) {
continue;
}
}
}
public function getMailerConfigAndSettings()
{
return static::$config;
}
public function getConfig($key = null, $default = null)
{
return $key ? Arr::get(static::$config, $key, $default) : static::$config;
}
public function getSettings($key = null, $default = null)
{
return $key ? Arr::get(static::$settings, $key, $default) : static::$settings;
}
public function getWPConfig($key = null, $default = null)
{
return $key ? Arr::get(
static::$wpConfigSettings, $key, $default
) : static::$wpConfigSettings;
}
public function activeDriver($phpMailer)
{
return fluentMailgetConnection($phpMailer->From);
}
}

View File

@@ -0,0 +1,356 @@
<?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
];
}
}

View File

@@ -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 $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;
}
}

View File

@@ -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;
}
}

View File

@@ -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(SimpleEmailService $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
));
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\DefaultMail;
use Exception;
use FluentMail\App\Services\Mailer\BaseHandler;
class Handler extends BaseHandler
{
public function send()
{
if ($this->preSend()) {
return $this->postSend();
}
return $this->handleResponse(new \WP_Error(422, __('Something went wrong!', 'fluent-smtp'), []) );
}
protected function postSend()
{
try {
$this->phpMailer->send();
return $this->handleSuccess();
} catch(Exception $e) {
return $this->handleFailure($e);
}
}
protected function handleSuccess()
{
$data = [
'code' => 200,
'message' => 'OK'
];
return $this->processResponse($data, true);
}
protected function handleFailure($exception)
{
$error = new \WP_Error($exception->getCode(), $exception->getMessage(), []);
return $this->handleResponse($error);
}
}

View File

@@ -0,0 +1,360 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\ElasticMail;
use FluentMail\Includes\Support\Arr;
use FluentMail\App\Services\Mailer\BaseHandler;
class Handler extends BaseHandler
{
use ValidatorTrait;
protected $boundary = '';
protected $postbody = [];
protected $url = 'https://api.elasticemail.com/v2/';
public function send()
{
if ($this->preSend()) {
return $this->postSend();
}
return $this->handleResponse(new \WP_Error(422, __('Something went wrong!', 'fluent-smtp'), []));
}
public function postSend()
{
$this->boundary = hash('sha256', uniqid('', true));
$this->postbody = [];
$replyTo = $this->getReplyTo();
$postData = [
'subject' => $this->getSubject(),
'from' => $this->getParam('sender_email'),
'fromName' => $this->getParam('sender_name'),
'replyTo' => Arr::get($replyTo, 'email'),
'replyToName' => Arr::get($replyTo, 'name'),
'msgTo' => $this->getToFormatted(),
'msgCC' => $this->getCcFormatted(), // with ; separated or null
'msgBcc' => $this->getBccFormatted(), // with ; separated or null
'bodyHtml' => '',
'bodyText' => '',
'charset' => $this->phpMailer->CharSet,
'encodingType' => 0,
'isTransactional' => ($this->getSetting('mail_type') == 'transactional') ? true : false
];
if ($this->phpMailer->ContentType == 'text/html') {
$postData['bodyHtml'] = $this->getBody();
} else if ($this->phpMailer->ContentType == 'multipart/alternative') {
$postData['bodyHtml'] = $this->getBody();
$postData['bodyText'] = $this->phpMailer->AltBody;
} else {
$postData['bodyText'] = $this->getBody();
}
foreach ($this->getParam('custom_headers') as $header) {
$key = trim($header['key']);
$postData['headers_' . $key] = $key . ': ' . trim($header['value']);
}
$this->parseAllPostData($postData);
$this->setAttachments();
$this->postbody[] = '--' . $this->boundary . '--';
$actualData = implode('', $this->postbody);
try {
$response = wp_remote_post($this->url . 'email/send?apikey=' . $this->getSetting('api_key'), array(
'method' => 'POST',
'headers' => array(
'content-type' => 'multipart/form-data; boundary=' . $this->boundary
),
'body' => $actualData
)
);
if (is_wp_error($response)) {
$returnResponse = new \WP_Error($response->get_error_code(), $response->get_error_message(), $response->get_error_messages());
} else {
$responseBody = wp_remote_retrieve_body($response);
$responseBody = \json_decode($responseBody, true);
if (!$responseBody['success']) {
$returnResponse = new \WP_Error('api_error', $responseBody['error'], $responseBody);
} else {
$returnResponse = [
'code' => 200,
'message' => $responseBody
];
}
}
} catch (\Exception $exception) {
$returnResponse = new \WP_Error($exception->getCode(), $exception->getMessage(), []);
}
$this->response = $returnResponse;
return $this->handleResponse($this->response);
}
protected function parseAllPostData($data)
{
foreach ($data as $key => $item) {
if (empty($item)) {
continue;
}
if (is_array($item)) {
$this->parseAllPostData($item);
} else {
$this->postbody[] = '--' . $this->boundary . "\r\n" . 'Content-Disposition: form-data; name=' . $key . "\r\n\r\n" . $item . "\r\n";
}
}
}
protected function getFrom()
{
$from = [
'email' => $this->getParam('sender_email')
];
if ($name = $this->getParam('sender_name')) {
$from['name'] = $name;
}
return $from;
}
protected function getReplyTo()
{
if ($replyTo = $this->getParam('headers.reply-to')) {
return reset($replyTo);
}
return [
'name' => '',
'email' => ''
];
}
protected function getRecipients()
{
$recipients = [
'to' => $this->getTo(),
'cc' => $this->getCarbonCopy(),
'bcc' => $this->getBlindCarbonCopy(),
];
$recipients = array_filter($recipients);
foreach ($recipients as $key => $recipient) {
$array = array_map(function ($recipient) {
return isset($recipient['name'])
? $recipient['name'] . ' <' . $recipient['email'] . '>'
: $recipient['email'];
}, $recipient);
$this->attributes['formatted'][$key] = implode(', ', $array);
}
return [$recipients];
}
protected function getCcFormatted()
{
$ccs = $this->getCarbonCopy();
if (!$ccs) {
return null;
}
$ccs = array_filter($ccs);
$toFormatted = [];
foreach ($ccs as $toEmail) {
if (!empty($toEmail['name'])) {
$string = $toEmail['name'] . ' <' . $toEmail['email'] . '>';
} else {
$string = $toEmail['email'];
}
$toFormatted[] = $string;
}
$toFormatted = array_filter($toFormatted);
return implode(';', $toFormatted);
}
protected function getBccFormatted()
{
$ccs = $this->getBlindCarbonCopy();
if (!$ccs) {
return null;
}
$ccs = array_filter($ccs);
$toFormatted = [];
foreach ($ccs as $toEmail) {
if (!empty($toEmail['name'])) {
$string = $toEmail['name'] . ' <' . $toEmail['email'] . '>';
} else {
$string = $toEmail['email'];
}
$toFormatted[] = $string;
}
$toFormatted = array_filter($toFormatted);
return implode(';', $toFormatted);
}
protected function getToFormatted()
{
$to = $this->getParam('to');
$toFormatted = [];
foreach ($to as $toEmail) {
if (!empty($toEmail['name'])) {
$string = $toEmail['name'] . ' <' . $toEmail['email'] . '>';
} else {
$string = $toEmail['email'];
}
$toFormatted[] = $string;
}
$toFormatted = array_filter($toFormatted);
return implode(';', $toFormatted);
}
protected function getCarbonCopy()
{
return $this->getParam('headers.cc');
}
protected function getBlindCarbonCopy()
{
return $this->getParam('headers.bcc');
}
protected function getBody()
{
return $this->getParam('message');
}
protected function setAttachments()
{
$rawAttachments = $this->getParam('attachments');
if (empty($rawAttachments) === true) {
return false;
}
foreach ($rawAttachments as $i => $attpath) {
if (empty($attpath) === true) {
continue;
}
if (!is_readable($attpath[0]) || !is_file($attpath[0])) {
continue;
}
//Extracting the file name
$filenameonly = explode(DIRECTORY_SEPARATOR, $attpath[0]);
$fname = end($filenameonly);
$mimeType = 'application/octet-stream'; // Default
if (function_exists('mime_content_type')) {
$detectedMime = mime_content_type($attpath[0]);
if ($detectedMime !== false) {
$mimeType = $detectedMime;
}
} elseif (function_exists('finfo_file')) {
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$detectedMime = finfo_file($finfo, $attpath[0]);
finfo_close($finfo);
if ($detectedMime !== false) {
$mimeType = $detectedMime;
}
}
// Add boundary and headers for attachment
$this->postbody[] = '--' . $this->boundary . "\r\n";
$this->postbody[] = 'Content-Disposition: form-data; name="attachments' . ($i + 1) . '"; filename="' . $fname . '"' . "\r\n";
$this->postbody[] = 'Content-Type: ' . $mimeType . "\r\n";
$this->postbody[] = "\r\n";
$handle = fopen($attpath[0], "rb");
if ($handle) {
$fileContent = '';
while (($buffer = fread($handle, 8192)) !== false && $buffer !== '') {
$fileContent .= $buffer;
}
fclose($handle);
$this->postbody[] = $fileContent . "\r\n";
}
}
}
protected function getCustomEmailHeaders()
{
return [];
}
protected function getRequestHeaders()
{
return [
'Content-Type' => 'application/json',
'X-ElasticEmail-ApiKey' => $this->getSetting('api_key')
];
}
public function setSettings($settings)
{
if ($settings['key_store'] == 'wp_config') {
$settings['api_key'] = defined('FLUENTMAIL_ELASTICMAIL_API_KEY') ? FLUENTMAIL_ELASTICMAIL_API_KEY : '';
}
$this->settings = $settings;
return $this;
}
public function checkConnection($connection)
{
$this->setSettings($connection);
$request = wp_remote_get($this->url . 'account/profileoverview', [
'body' => [
'apikey' => $this->getSetting('api_key')
]
]);
if (is_wp_error($request)) {
$this->throwValidationException([
'api_key' => [
'required' => $request->get_error_message()
]
]);
}
$response = json_decode(wp_remote_retrieve_body($request), true);
if (!$response || empty($response['success'])) {
$error = 'API Key is invalid';
if (!empty($response['error'])) {
$error = $response['error'];
}
$this->throwValidationException([
'api_key' => [
'required' => $error
]
]);
}
return true;
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\ElasticMail;
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, 'api_key')) {
$errors['api_key']['required'] = __('Api key is required.', 'fluent-smtp');
}
} else if($keyStoreType == 'wp_config') {
if(!defined('FLUENTMAIL_ELASTICMAIL_API_KEY') || !FLUENTMAIL_ELASTICMAIL_API_KEY) {
$errors['api_key']['required'] = __('Please define FLUENTMAIL_ELASTICMAIL_API_KEY in wp-config.php file.', 'fluent-smtp');
}
}
if ($errors) {
$this->throwValidationException($errors);
}
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers;
use InvalidArgumentException;
use FluentMail\App\Models\Settings;
use FluentMail\Includes\Core\Application;
class Factory
{
protected $app = null;
protected $settings = null;
public function __construct(Application $app, Settings $settings)
{
$this->app = $app;
$this->settings = $settings;
}
public function make($provider)
{
return $this->app->make($provider);
}
public function get($email)
{
if (!($conn = $this->settings->getConnection($email))) {
$conn = $this->getDefaultProvider();
}
if ($conn) {
$settings = array_merge($conn['provider_settings'], [
'title' => $conn['title']
]);
return $this->make(
$conn['provider_settings']['provider']
)->setSettings($settings);
}
throw new InvalidArgumentException(
esc_html__('There is no matching provider found by email: ', 'fluent-smtp') . $email // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
);
}
public function getDefaultProvider()
{
return fluentMailDefaultConnection();
}
}

View File

@@ -0,0 +1,334 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\Gmail;
use FluentMail\App\Models\Settings;
use FluentMail\Includes\Support\Arr;
use FluentMail\App\Services\Mailer\BaseHandler;
class Handler extends BaseHandler
{
public function send()
{
if ($this->preSend() && $this->phpMailer->preSend()) {
return $this->postSend();
}
return $this->handleResponse(new \WP_Error(422, __('Something went wrong!', 'fluent-smtp'), []));
}
protected function postSend()
{
try {
$returnResponse = $this->sendViaApi();
} catch (\Exception $e) {
$returnResponse = new \WP_Error(422, $e->getMessage(), []);
}
$this->response = $returnResponse;
return $this->handleResponse($this->response);
}
public function setSettings($settings)
{
if (Arr::get($settings, 'key_store') == 'wp_config') {
$settings['client_id'] = defined('FLUENTMAIL_GMAIL_CLIENT_ID') ? FLUENTMAIL_GMAIL_CLIENT_ID : '';
$settings['client_secret'] = defined('FLUENTMAIL_GMAIL_CLIENT_SECRET') ? FLUENTMAIL_GMAIL_CLIENT_SECRET : '';
}
$this->settings = $settings;
return $this;
}
private function sendViaApi()
{
if (!class_exists('\FluentSmtpLib\Google\Service\Gmail\Message')) {
require_once FLUENTMAIL_PLUGIN_PATH . 'includes/libs/google-api-client/build/vendor/autoload.php';
}
$message = $this->phpMailer->getSentMIMEMessage();
$data = $this->getSetting();
$googleApiMessage = new \FluentSmtpLib\Google\Service\Gmail\Message();
$file_size = strlen($message);
$googleClient = $this->getApiClient($data);
if (is_wp_error($googleClient)) {
return $googleClient;
}
$googleService = new \FluentSmtpLib\Google\Service\Gmail($googleClient);
$result = array();
try {
$googleClient->setDefer(true);
$result = $googleService->users_messages->send('me', $googleApiMessage, array('uploadType' => 'resumable'));
$chunkSizeBytes = 1 * 1024 * 1024;
// create mediafile upload
$media = new \FluentSmtpLib\Google\Http\MediaFileUpload(
$googleClient,
$result,
'message/rfc822',
$message,
true,
$chunkSizeBytes
);
$media->setFileSize($file_size);
$status = false;
while (!$status) {
$status = $media->nextChunk();
}
$result = false;
// Reset to the client to execute requests immediately in the future.
$googleClient->setDefer(false);
$googleMessageId = $status->getId();
} catch (\Exception $e) {
$errorMessage = $e->getMessage();
return new \WP_Error(422, $errorMessage, []);
}
return array(
'MessageId' => $googleMessageId,
);
}
public function validateProviderInformation($connection)
{
$errors = [];
$keyStoreType = $connection['key_store'];
$clientId = Arr::get($connection, 'client_id');
$clientSecret = Arr::get($connection, 'client_secret');
if ($keyStoreType == 'db') {
if (!$clientId) {
$errors['client_id']['required'] = __('Application Client ID is required.', 'fluent-smtp');
}
if (!$clientSecret) {
$errors['client_secret']['required'] = __('Application Client Secret key is required.', 'fluent-smtp');
}
} else if ($keyStoreType == 'wp_config') {
if (!defined('FLUENTMAIL_GMAIL_CLIENT_ID') || !FLUENTMAIL_GMAIL_CLIENT_ID) {
$errors['client_id']['required'] = __('Please define FLUENTMAIL_GMAIL_CLIENT_ID in wp-config.php file.', 'fluent-smtp');
} else {
$clientId = FLUENTMAIL_GMAIL_CLIENT_ID;
}
if (!defined('FLUENTMAIL_GMAIL_CLIENT_SECRET') || !FLUENTMAIL_GMAIL_CLIENT_SECRET) {
$errors['client_secret']['required'] = __('Please define FLUENTMAIL_GMAIL_CLIENT_SECRET in wp-config.php file.', 'fluent-smtp');
} else {
$clientSecret = FLUENTMAIL_GMAIL_CLIENT_SECRET;
}
}
if ($errors) {
$this->throwValidationException($errors);
}
$accessToken = Arr::get($connection, 'access_token');
$authToken = Arr::get($connection, 'auth_token');
if (!$accessToken && $authToken) {
// this is new, We have to generate the tokens
$body = [
'code' => $authToken,
'grant_type' => 'authorization_code',
'redirect_uri' => apply_filters('fluentsmtp_gapi_callback', 'https://fluentsmtp.com/gapi/'), // 'urn:ietf:wg:oauth:2.0:oob'
'client_id' => $clientId,
'client_secret' => $clientSecret
];
$tokens = $this->makeRequest('https://accounts.google.com/o/oauth2/token', $body, 'POST');
if (is_wp_error($tokens)) {
$errors['auth_token']['required'] = $tokens->get_error_message();
} else {
add_filter('fluentmail_saving_connection_data', function ($con, $provider) use ($connection, $tokens) {
if ($provider != 'gmail') {
return $con;
}
if (Arr::get($con, 'connection.sender_email') != $connection['sender_email']) {
return $con;
}
$con['connection']['refresh_token'] = $tokens['refresh_token'];
$con['connection']['access_token'] = $tokens['access_token'];
$con['connection']['auth_token'] = '';
$con['connection']['expire_stamp'] = time() + $tokens['expires_in'];
$con['connection']['expires_in'] = $tokens['expires_in'];
$con['connection']['version'] = 2;
return $con;
}, 10, 2);
}
} else if (!$authToken && !$accessToken) {
$errors['auth_token']['required'] = __('Please Provide Auth Token.', 'fluent-smtp');
}
if ($errors) {
$this->throwValidationException($errors);
}
}
private function makeRequest($url, $bodyArgs, $type = 'GET', $headers = false)
{
if (!$headers) {
$headers = array(
'Content-Type' => 'application/http',
'Content-Transfer-Encoding' => 'binary',
'MIME-Version' => '1.0',
);
}
$args = [
'headers' => $headers
];
if ($bodyArgs) {
$args['body'] = json_encode($bodyArgs);
}
$args['method'] = $type;
$request = wp_remote_request($url, $args);
if (is_wp_error($request)) {
$message = $request->get_error_message();
return new \WP_Error(422, $message);
}
$body = json_decode(wp_remote_retrieve_body($request), true);
if (!empty($body['error'])) {
$error = 'Unknown Error';
if (isset($body['error_description'])) {
$error = $body['error_description'];
} else if (!empty($body['error']['message'])) {
$error = $body['error']['message'];
}
return new \WP_Error(422, $error);
}
return $body;
}
private function saveNewTokens($existingData, $tokens)
{
if (empty($tokens['access_token']) || empty($tokens['refresh_token'])) {
return false;
}
$senderEmail = $existingData['sender_email'];
$existingData['access_token'] = $tokens['access_token'];
$existingData['refresh_token'] = $tokens['refresh_token'];
$existingData['expire_stamp'] = $tokens['expires_in'] + time();
$existingData['expires_in'] = $tokens['expires_in'];
(new Settings())->updateConnection($senderEmail, $existingData);
fluentMailGetProvider($senderEmail, true); // we are clearing the static cache here
wp_schedule_single_event($existingData['expire_stamp'] - 360, 'fluentsmtp_renew_gmail_token');
return true;
}
private function getApiClient($data)
{
$senderEmail = $data['sender_email'];
static $cachedServices = [];
if (isset($cachedServices[$senderEmail])) {
return $cachedServices[$senderEmail];
}
if (!class_exists('\FluentSmtpLib\Google\Client')) {
require_once FLUENTMAIL_PLUGIN_PATH . 'includes/libs/google-api-client/build/vendor/autoload.php';
}
$client = new \FluentSmtpLib\Google\Client();
$client->setClientId($data['client_id']);
$client->setClientSecret($data['client_secret']);
$client->addScope("https://www.googleapis.com/auth/gmail.compose");
$client->setAccessType('offline');
$client->setApprovalPrompt('force');
$tokens = [
'access_token' => $data['access_token'],
'refresh_token' => $data['refresh_token'],
'expires_in' => $data['expire_stamp'] - time()
];
$client->setAccessToken($tokens);
// check if expired or will be expired in 5 minutes
if (($data['expire_stamp'] - 300) < time()) {
$newTokens = $client->refreshToken($data['refresh_token']);
$result = $this->saveNewTokens($data, $newTokens);
if (!$result) {
$errorDescription = Arr::get($newTokens, 'error_description');
if (!$errorDescription) {
$errorDescription = __('Failed to renew token with Gmail Api', 'fluent-smtp');
}
return new \WP_Error('api_error', $errorDescription);
}
$client->setAccessToken($newTokens);
}
$cachedServices[$senderEmail] = $client;
return $cachedServices[$senderEmail];
}
public function getConnectionInfo($connection)
{
if (Arr::get($connection, 'key_store') == 'wp_config') {
$connection['client_id'] = defined('FLUENTMAIL_GMAIL_CLIENT_ID') ? FLUENTMAIL_GMAIL_CLIENT_ID : '';
$connection['client_secret'] = defined('FLUENTMAIL_GMAIL_CLIENT_SECRET') ? FLUENTMAIL_GMAIL_CLIENT_SECRET : '';
}
if (!class_exists('\FluentSmtpLib\Google\Client')) {
require_once FLUENTMAIL_PLUGIN_PATH . 'includes/libs/google-api-client/build/vendor/autoload.php';
}
$client = $this->getApiClient($connection);
if (is_wp_error($client)) {
return '<p style="color: red; text-align: center; font-size: 18px;">ERROR: ' . $connection->get_error_message() . '</p>';
}
$info = fluentMailgetConnection($connection['sender_email']);
$connection = $info->getSetting();
$extraRow = [
'title' => __('Token Validity', 'fluent-smtp'),
'content' => 'Valid (' . (int)(($connection['expire_stamp'] - time()) / 60) . 'minutes)'
];
if (($connection['expire_stamp']) < time()) {
$extraRow['content'] = __('Invalid. Please re-authenticate', 'fluent-smtp');
}
$connection['extra_rows'] = [$extraRow];
return [
'info' => (string)fluentMail('view')->make('admin.general_connection_info', [
'connection' => $connection
])
];
}
}

View File

@@ -0,0 +1,248 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\Mailgun;
use FluentMail\Includes\Support\Arr;
use FluentMail\App\Services\Mailer\BaseHandler;
class Handler extends BaseHandler
{
use ValidatorTrait;
protected $emailSentCode = 200;
protected $url = null;
const API_BASE_US = 'https://api.mailgun.net/v3/';
const API_BASE_EU = 'https://api.eu.mailgun.net/v3/';
public function send()
{
if ($this->preSend()) {
$this->setUrl();
return $this->postSend();
}
return $this->handleResponse(new \WP_Error(422, __('Something went wrong!', 'fluent-smtp'), []));
}
protected function setUrl()
{
$url = $this->getSetting('region') == 'eu' ? self::API_BASE_EU : self::API_BASE_US;
$url .= sanitize_text_field($this->getSetting('domain_name') . '/messages');
return $this->url = $url;
}
public function postSend()
{
$content_type = $this->getHeader('content-type');
$body = [
'from' => $this->getFrom(),
'subject' => $this->getSubject(),
'h:X-Mailer' => 'FluentMail - Mailgun',
'h:Content-Type' => $content_type
];
if (stripos($content_type, 'html') === false) {
$body['text'] = $this->getBody();
} else if ($content_type == 'multipart/alternative') {
$body['html'] = $this->getBody();
$body['text'] = $this->phpMailer->AltBody;
} else {
$body['html'] = $this->getBody();
}
if ($replyTo = $this->getReplyTo()) {
$body['h:Reply-To'] = $replyTo;
}
$recipients = [
'to' => $this->getTo(),
'cc' => $this->getCarbonCopy(),
'bcc' => $this->getBlindCarbonCopy()
];
if ($recipients = array_filter($recipients)) {
$body = array_merge($body, $recipients);
}
foreach ($this->getParam('custom_headers') as $header) {
$key = trim($header['key']);
$body['h:' . $key] = trim($header['value']);
}
$params = [
'body' => $body,
'headers' => $this->getRequestHeaders()
];
$params = array_merge($params, $this->getDefaultParams());
if (!empty($this->attributes['attachments'])) {
$params = $this->getAttachments($params);
}
$response = wp_safe_remote_post($this->url, $params);
if (is_wp_error($response)) {
$returnResponse = new \WP_Error($response->get_error_code(), $response->get_error_message(), $response->get_error_messages());
} else {
$responseBody = wp_remote_retrieve_body($response);
$responseCode = wp_remote_retrieve_response_code($response);
$isOKCode = $responseCode == $this->emailSentCode;
if ($isOKCode) {
$responseBody = \json_decode($responseBody, true);
}
if ($isOKCode && isset($responseBody['id'])) {
$returnResponse = [
'id' => Arr::get($responseBody, 'id'),
'message' => Arr::get($responseBody, 'message')
];
} else {
$returnResponse = new \WP_Error($responseCode, __('Mailgun API Error', 'fluent-smtp'), $responseBody);
}
}
$this->response = $returnResponse;
return $this->handleResponse($this->response);
}
public function setSettings($settings)
{
if ($settings['key_store'] == 'wp_config') {
$settings['api_key'] = defined('FLUENTMAIL_MAILGUN_API_KEY') ? FLUENTMAIL_MAILGUN_API_KEY : '';
$settings['domain_name'] = defined('FLUENTMAIL_MAILGUN_DOMAIN') ? FLUENTMAIL_MAILGUN_DOMAIN : '';
}
$this->settings = $settings;
return $this;
}
protected function getFrom()
{
return $this->getParam('from');
}
protected function getReplyTo()
{
return $this->getRecipients(
$this->getParam('headers.reply-to')
);
}
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->getParam('message');
}
protected function getAttachments($params)
{
$data = [];
$payload = '';
$attachments = $this->attributes['attachments'];
foreach ($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]);
}
} catch (\Exception $e) {
$file = false;
}
if ($file === false) {
continue;
}
$data[] = [
'content' => $file,
'name' => $fileName,
];
}
if (!empty($data)) {
$boundary = hash('sha256', uniqid('', true));
foreach ($params['body'] as $key => $value) {
if (is_array($value)) {
foreach ($value as $child_key => $child_value) {
$payload .= '--' . $boundary;
$payload .= "\r\n";
$payload .= 'Content-Disposition: form-data; name="' . $key . "\"\r\n\r\n";
$payload .= $child_value;
$payload .= "\r\n";
}
} else {
$payload .= '--' . $boundary;
$payload .= "\r\n";
$payload .= 'Content-Disposition: form-data; name="' . $key . '"' . "\r\n\r\n";
$payload .= $value;
$payload .= "\r\n";
}
}
foreach ($data as $key => $attachment) {
$payload .= '--' . $boundary;
$payload .= "\r\n";
$payload .= 'Content-Disposition: form-data; name="attachment[' . $key . ']"; filename="' . $attachment['name'] . '"' . "\r\n\r\n";
$payload .= $attachment['content'];
$payload .= "\r\n";
}
$payload .= '--' . $boundary . '--';
$params['body'] = $payload;
$params['headers']['Content-Type'] = 'multipart/form-data; boundary=' . $boundary;
$this->attributes['headers']['content-type'] = 'multipart/form-data';
}
return $params;
}
protected function getRequestHeaders()
{
$apiKey = $this->getSetting('api_key');
return [
'Authorization' => 'Basic ' . base64_encode('api:' . $apiKey)
];
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\Mailgun;
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, 'api_key')) {
$errors['api_key']['required'] = __('Api key is required.', 'fluent-smtp');
}
if (! Arr::get($connection, 'domain_name')) {
$errors['domain_name']['required'] = __('Domain name is required.', 'fluent-smtp');
}
} else if($keyStoreType == 'wp_config') {
if(!defined('FLUENTMAIL_MAILGUN_API_KEY') || !FLUENTMAIL_MAILGUN_API_KEY) {
$errors['api_key']['required'] = __('Please define FLUENTMAIL_MAILGUN_API_KEY in wp-config.php file.', 'fluent-smtp');
}
if(!defined('FLUENTMAIL_MAILGUN_DOMAIN') || !FLUENTMAIL_MAILGUN_DOMAIN) {
$errors['domain_name']['required'] = __('Please define FLUENTMAIL_MAILGUN_DOMAIN in wp-config.php file.', 'fluent-smtp');
}
}
if ($errors) {
$this->throwValidationException($errors);
}
}
}

View File

@@ -0,0 +1,106 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\Outlook;
use FluentMail\Includes\Support\Arr;
class API
{
private $clientId;
private $clientSecret;
public function __construct($clientId = '', $clientSecret = '')
{
$this->clientId = $clientId;
$this->clientSecret = $clientSecret;
}
public function getAuthUrl()
{
$fluentClient = new \FluentMail\Includes\OAuth2Provider($this->getConfig());
return $fluentClient->getAuthorizationUrl();
}
public function generateToken($authCode)
{
return $this->sendTokenRequest('authorization_code', [
'code' => $authCode
]);
}
/**
* @return mixed|string
*/
public function sendTokenRequest($type, $params)
{
$fluentClient = new \FluentMail\Includes\OAuth2Provider($this->getConfig());
try {
$tokens = $fluentClient->getAccessToken($type, $params);
return $tokens;
} catch (\Exception$exception) {
return new \WP_Error(422, $exception->getMessage());
}
}
/**
* @return array | \WP_Error
*/
public function sendMime($mime, $accessToken)
{
$response = wp_remote_request('https://graph.microsoft.com/v1.0/me/sendMail', [
'method' => 'POST',
'headers' => [
'Authorization' => 'Bearer ' . $accessToken,
'Content-Type' => 'text/plain'
],
'body' => $mime
]);
if (is_wp_error($response)) {
return $response;
}
$responseCode = wp_remote_retrieve_response_code($response);
if ($responseCode >= 300) {
$error = Arr::get($response, 'response.message');
if (!$error) {
$responseBody = json_decode(wp_remote_retrieve_body($response), true);
$error = Arr::get($responseBody, 'error.message');
if (!$error) {
$error = __('Something with wrong with Outlook API. Please check your API Settings', 'fluent-smtp');
}
}
return new \WP_Error($responseCode, $error);
}
$header = wp_remote_retrieve_headers($response);
return $header->getAll();
}
public function getRedirectUrl()
{
return rest_url('fluent-smtp/outlook_callback');
}
private function getConfig()
{
return [
'clientId' => $this->clientId,
'clientSecret' => $this->clientSecret,
'redirectUri' => $this->getRedirectUrl(),
'urlAuthorize' => 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
'urlAccessToken' => 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
'urlResourceOwnerDetails' => '',
'scopes' => 'https://graph.microsoft.com/user.read https://graph.microsoft.com/mail.readwrite https://graph.microsoft.com/mail.send https://graph.microsoft.com/mail.send.shared offline_access'
];
}
}

View File

@@ -0,0 +1,208 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\Outlook;
use FluentMail\App\Models\Settings;
use FluentMail\Includes\Support\Arr;
use FluentMail\App\Services\Mailer\BaseHandler;
class Handler extends BaseHandler
{
public function send()
{
$this->phpMailer->Encoding = 'base64';
if ($this->preSend() && $this->phpMailer->preSend()) {
return $this->postSend();
}
return $this->handleResponse(new \WP_Error(422, __('Something went wrong!', 'fluent-smtp'), []));
}
protected function postSend()
{
try {
$returnResponse = $this->sendViaApi();
} catch (\Exception $e) {
$returnResponse = new \WP_Error(422, $e->getMessage(), []);
}
$this->response = $returnResponse;
return $this->handleResponse($this->response);
}
public function setSettings($settings)
{
if (Arr::get($settings, 'key_store') == 'wp_config') {
$settings['client_id'] = defined('FLUENTMAIL_OUTLOOK_CLIENT_ID') ? FLUENTMAIL_OUTLOOK_CLIENT_ID : '';
$settings['client_secret'] = defined('FLUENTMAIL_OUTLOOK_CLIENT_SECRET') ? FLUENTMAIL_OUTLOOK_CLIENT_SECRET : '';
}
$this->settings = $settings;
return $this;
}
private function sendViaApi()
{
$mime = chunk_split(base64_encode($this->phpMailer->getSentMIMEMessage()), 76, "\n");
$data = $this->getSetting();
$accessToken = $this->getAccessToken($data);
$api = (new API($data['client_id'], $data['client_secret']));
$result = $api->sendMime($mime, $accessToken);
if(is_wp_error($result)) {
$errorMessage = $result->get_error_message();
return new \WP_Error(422, $errorMessage, []);
} else {
return array(
'RequestId' => $result['request-id'],
);
}
}
public function validateProviderInformation($connection)
{
$errors = [];
$keyStoreType = $connection['key_store'];
$clientId = Arr::get($connection, 'client_id');
$clientSecret = Arr::get($connection, 'client_secret');
if ($keyStoreType == 'db') {
if (!$clientId) {
$errors['client_id']['required'] = __('Application Client ID is required.', 'fluent-smtp');
}
if (!$clientSecret) {
$errors['client_secret']['required'] = __('Application Client Secret key is required.', 'fluent-smtp');
}
} else if ($keyStoreType == 'wp_config') {
if (!defined('FLUENTMAIL_OUTLOOK_CLIENT_ID') || !FLUENTMAIL_OUTLOOK_CLIENT_ID) {
$errors['client_id']['required'] = __('Please define FLUENTMAIL_OUTLOOK_CLIENT_ID in wp-config.php file.', 'fluent-smtp');
} else {
$clientId = FLUENTMAIL_OUTLOOK_CLIENT_ID;
}
if (!defined('FLUENTMAIL_OUTLOOK_CLIENT_SECRET') || !FLUENTMAIL_OUTLOOK_CLIENT_SECRET) {
$errors['client_secret']['required'] = __('Please define FLUENTMAIL_OUTLOOK_CLIENT_SECRET in wp-config.php file.', 'fluent-smtp');
} else {
$clientSecret = FLUENTMAIL_OUTLOOK_CLIENT_SECRET;
}
}
if ($errors) {
$this->throwValidationException($errors);
}
$accessToken = Arr::get($connection, 'access_token');
$authToken = Arr::get($connection, 'auth_token');
if (!$accessToken && $authToken) {
$tokens = (new API($clientId, $clientSecret))->generateToken($authToken);
if (is_wp_error($tokens)) {
$errors['auth_token']['required'] = $tokens->get_error_message();
} else {
add_filter('fluentmail_saving_connection_data', function ($con, $provider) use ($connection, $tokens) {
if ($provider != 'outlook') {
return $con;
}
if (Arr::get($con, 'connection.sender_email') != $connection['sender_email']) {
return $con;
}
$con['connection']['refresh_token'] = $tokens['refresh_token'];
$con['connection']['access_token'] = $tokens['access_token'];
$con['connection']['auth_token'] = '';
$con['connection']['expire_stamp'] = time() + $tokens['expires_in'];
return $con;
}, 10, 2);
}
} else if (!$authToken && !$accessToken) {
$errors['auth_token']['required'] = __('Please Provide Auth Token.', 'fluent-smtp');
}
if ($errors) {
$this->throwValidationException($errors);
}
}
private function saveNewTokens($existingData, $tokens)
{
if (empty($tokens['access_token']) || empty($tokens['refresh_token'])) {
return false;
}
$senderEmail = $existingData['sender_email'];
$existingData['access_token'] = $tokens['access_token'];
$existingData['refresh_token'] = $tokens['refresh_token'];
$existingData['expire_stamp'] = $tokens['expires_in'] + time();
(new Settings())->updateConnection($senderEmail, $existingData);
return fluentMailGetProvider($senderEmail, true); // we are clearing the static cache here
}
private function getAccessToken($config)
{
$accessToken = $config['access_token'];
// check if expired or will be expired in 300 seconds
if ( ($config['expire_stamp'] - 300) < time()) {
$fluentAPi = (new API($config['client_id'], $config['client_secret']));
$tokens = $fluentAPi->sendTokenRequest('refresh_token', [
'refresh_token' => $config['refresh_token']
]);
if(is_wp_error($tokens)) {
return false;
}
$this->saveNewTokens($config, $tokens);
$accessToken = $tokens['access_token'];
}
return $accessToken;
}
public function getConnectionInfo($connection)
{
if (Arr::get($connection, 'key_store') == 'wp_config') {
$connection['client_id'] = defined('FLUENTMAIL_OUTLOOK_CLIENT_ID') ? FLUENTMAIL_OUTLOOK_CLIENT_ID : '';
$connection['client_secret'] = defined('FLUENTMAIL_OUTLOOK_CLIENT_SECRET') ? FLUENTMAIL_OUTLOOK_CLIENT_SECRET : '';
}
$this->getAccessToken($connection);
$info = fluentMailgetConnection($connection['sender_email']);
$connection = $info->getSetting();
$extraRow = [
'title' => __('Token Validity', 'fluent-smtp'),
'content' => 'Valid (' . intval((($connection['expire_stamp'] - time()) / 60)) . 'm)'
];
if (($connection['expire_stamp']) < time()) {
$extraRow['content'] = 'Invalid. Please re-authenticate';
}
$connection['extra_rows'] = [$extraRow];
return [
'info' => (string)fluentMail('view')->make('admin.general_connection_info', [
'connection' => $connection
])
];
}
}

View File

@@ -0,0 +1,211 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\PepiPost;
use WP_Error as WPError;
use FluentMail\Includes\Support\Arr;
use FluentMail\Includes\Core\Application;
use FluentMail\App\Services\Mailer\Manager;
use FluentMail\App\Services\Mailer\BaseHandler;
use FluentMail\App\Services\Mailer\Providers\PepiPost\ValidatorTrait;
class Handler extends BaseHandler
{
use ValidatorTrait;
protected $emailSentCode = 202;
protected $url = 'https://api.pepipost.com/v5/mail/send';
public function send()
{
if ($this->preSend()) {
return $this->postSend();
}
return $this->handleResponse(new \WP_Error(422, __('Something went wrong!', 'fluent-smtp'), []));
}
public function postSend()
{
$body = [
'from' => $this->getFrom(),
'personalizations' => $this->getRecipients(),
'subject' => $this->getSubject(),
'content' => $this->getBody(),
'headers' => $this->getCustomEmailHeaders()
];
if ($replyTo = $this->getReplyTo()) {
$body['reply_to'] = $replyTo;
}
if (!empty($this->getParam('attachments'))) {
$body['attachments'] = $this->getAttachments();
}
$params = [
'body' => json_encode($body),
'headers' => $this->getRequestHeaders()
];
$params = array_merge($params, $this->getDefaultParams());
$response = wp_safe_remote_post($this->url, $params);
if (is_wp_error($response)) {
$returnResponse = new \WP_Error($response->get_error_code(), $response->get_error_message(), $response->get_error_messages());
} else {
$responseBody = wp_remote_retrieve_body($response);
$responseCode = wp_remote_retrieve_response_code($response);
$isOKCode = $responseCode == $this->emailSentCode;
$responseBody = \json_decode($responseBody, true);
if ($isOKCode) {
$returnResponse = [
'id' => Arr::get($responseBody, 'data.message_id'),
'message' => Arr::get($responseBody, 'message_id')
];
} else {
$returnResponse = new \WP_Error($responseCode, Arr::get($responseBody, 'error', 'Unknown Error'), $responseBody);
}
}
$this->response = $returnResponse;
return $this->handleResponse($this->response);
}
public function setSettings($settings)
{
if ($settings['key_store'] == 'wp_config') {
$settings['api_key'] = defined('FLUENTMAIL_PEPIPOST_API_KEY') ? FLUENTMAIL_PEPIPOST_API_KEY : '';
}
$this->settings = $settings;
return $this;
}
protected function getFrom()
{
return [
'name' => $this->getParam('sender_name'),
'email' => $this->getParam('sender_email')
];
}
protected function getReplyTo()
{
if ($replyTo = $this->getParam('headers.reply-to')) {
$replyTo = reset($replyTo);
return $replyTo['email'];
}
}
protected function getRecipients()
{
$recipients = [
'to' => $this->getTo(),
'cc' => $this->getCarbonCopy(),
'bcc' => $this->getBlindCarbonCopy(),
];
$recipients = array_filter($recipients);
foreach ($recipients as $key => $recipient) {
$array = array_map(function ($recipient) {
return isset($recipient['name'])
? $recipient['name'] . ' <' . $recipient['email'] . '>'
: $recipient['email'];
}, $recipient);
$this->attributes['formatted'][$key] = implode(', ', $array);
}
return [$recipients];
}
protected function getTo()
{
return $this->getParam('to');
}
protected function getCarbonCopy()
{
return array_map(function ($cc) {
return ['email' => $cc['email']];
}, $this->getParam('headers.cc'));
}
protected function getBlindCarbonCopy()
{
return array_map(function ($bcc) {
return ['email' => $bcc['email']];
}, $this->getParam('headers.bcc'));
}
protected function getBody()
{
$return = [
[
'type' => 'html',
'value' => $this->getParam('message')
]
];
if ($this->phpMailer->contentType == 'multipart/alternative') {
$return[] = [
'type' => 'amp',
'value' => $this->phpMailer->AltBody
];
}
return $return;
}
protected function getAttachments()
{
$data = [];
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]);
}
} catch (\Exception $e) {
$file = false;
}
if ($file === false) {
continue;
}
$data[] = [
'name' => $fileName,
'content' => base64_encode($file)
];
}
return $data;
}
protected function getCustomEmailHeaders()
{
return [];
}
protected function getRequestHeaders()
{
return [
'content-type' => 'application/json',
'api_key' => $this->getSetting('api_key')
];
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\PepiPost;
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, 'api_key')) {
$errors['api_key']['required'] = __('Api key is required.', 'fluent-smtp');
}
} else if($keyStoreType == 'wp_config') {
if(!defined('FLUENTMAIL_PEPIPOST_API_KEY') || !FLUENTMAIL_PEPIPOST_API_KEY) {
$errors['api_key']['required'] = __('Please define FLUENTMAIL_PEPIPOST_API_KEY in wp-config.php file.', 'fluent-smtp');
}
}
if ($errors) {
$this->throwValidationException($errors);
}
}
}

View File

@@ -0,0 +1,212 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\Postmark;
use FluentMail\Includes\Support\Arr;
use FluentMail\App\Services\Mailer\BaseHandler;
class Handler extends BaseHandler
{
use ValidatorTrait;
protected $emailSentCode = 200;
protected $url = 'https://api.postmarkapp.com/email';
public function send()
{
if ($this->preSend() && $this->phpMailer->preSend()) {
return $this->postSend();
}
return $this->handleResponse(new \WP_Error(422, __('Something went wrong!', 'fluent-smtp'), []));
}
public function postSend()
{
$body = [
'From' => $this->getParam('from'),
'To' => $this->getTo(),
'Subject' => $this->getSubject(),
'MessageStream' => $this->getSetting('message_stream', 'outbound')
];
if ($replyTo = $this->getReplyTo()) {
$body['ReplyTo'] = $replyTo;
}
if ($bcc = $this->getBlindCarbonCopy()) {
$body['Bcc'] = $bcc;
}
if ($cc = $this->getCarbonCopy()) {
$body['Cc'] = $cc;
}
$contentType = $this->getHeader('content-type');
if ($contentType == 'text/html') {
$body['HtmlBody'] = $this->getParam('message');
if ($this->getSetting('track_opens') == 'yes') {
$body['TrackOpens'] = true;
}
if ($this->getSetting('track_links') == 'yes') {
$body['TrackLinks'] = 'HtmlOnly';
}
} else if ($contentType == 'multipart/alternative') {
$body['HtmlBody'] = $this->getParam('message');
$body['TextBody'] = $this->phpMailer->AltBody;
} else {
$body['TextBody'] = $this->getParam('message');
}
if (!empty($this->getParam('attachments'))) {
$body['Attachments'] = $this->getAttachments();
}
// Add any custom headers
$customHeaders = $this->phpMailer->getCustomHeaders();
if (!empty($customHeaders)) {
foreach ($customHeaders as $header) {
$body['Headers'][] = [
'Name' => $header[0],
'Value' => $header[1]
];
}
}
// Handle apostrophes in email address From names by escaping them for the Postmark API.
$from_regex = "/(\"From\": \"[a-zA-Z\\d]+)*[\\\\]{2,}'/";
$args = array(
'headers' => $this->getRequestHeaders(),
'body' => preg_replace($from_regex, "'", wp_json_encode($body), 1),
);
$response = wp_remote_post($this->url, $args);
if (is_wp_error($response)) {
$returnResponse = new \WP_Error($response->get_error_code(), $response->get_error_message(), $response->get_error_messages());
} else {
$responseBody = wp_remote_retrieve_body($response);
$responseCode = wp_remote_retrieve_response_code($response);
$isOKCode = $responseCode == $this->emailSentCode;
$responseBody = \json_decode($responseBody, true);
if ($isOKCode) {
$returnResponse = [
'id' => Arr::get($responseBody, 'MessageID'),
'message' => Arr::get($responseBody, 'Message')
];
} else {
$returnResponse = new \WP_Error($responseCode, Arr::get($responseBody, 'Message', 'Unknown Error'), $responseBody);
}
}
$this->response = $returnResponse;
return $this->handleResponse($this->response);
}
public function setSettings($settings)
{
if ($settings['key_store'] == 'wp_config') {
$settings['api_key'] = defined('FLUENTMAIL_POSTMARK_API_KEY') ? FLUENTMAIL_POSTMARK_API_KEY : '';
}
$this->settings = $settings;
return $this;
}
protected function getReplyTo()
{
if ($replyTo = $this->getParam('headers.reply-to')) {
$replyTo = reset($replyTo);
return $replyTo['email'];
}
}
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 getAttachments()
{
$data = [];
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]);
}
} catch (\Exception $e) {
$file = false;
}
if ($file === false) {
continue;
}
$data[] = [
'Name' => $fileName,
'Content' => base64_encode($file),
'ContentType' => $this->determineMimeContentRype($attachment[0])
];
}
return $data;
}
protected function getRequestHeaders()
{
return [
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'X-Postmark-Server-Token' => $this->getSetting('api_key'),
];
}
protected function determineMimeContentRype($filename)
{
if (function_exists('mime_content_type')) {
return mime_content_type($filename);
} elseif (function_exists('finfo_open')) {
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime_type = finfo_file($finfo, $filename);
finfo_close($finfo);
return $mime_type;
} else {
return 'application/octet-stream';
}
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\Postmark;
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, 'api_key')) {
$errors['api_key']['required'] = __('Api key is required.', 'fluent-smtp');
}
} else if($keyStoreType == 'wp_config') {
if(!defined('FLUENTMAIL_POSTMARK_API_KEY') || !FLUENTMAIL_POSTMARK_API_KEY) {
$errors['api_key']['required'] = __('Please define FLUENTMAIL_POSTMARK_API_KEY in wp-config.php file.', 'fluent-smtp');
}
}
if ($errors) {
$this->throwValidationException($errors);
}
}
}

View File

@@ -0,0 +1,219 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\SendGrid;
use WP_Error as WPError;
use FluentMail\Includes\Support\Arr;
use FluentMail\Includes\Core\Application;
use FluentMail\App\Services\Mailer\Manager;
use FluentMail\App\Services\Mailer\BaseHandler;
use FluentMail\App\Services\Mailer\Providers\SendGrid\ValidatorTrait;
class Handler extends BaseHandler
{
use ValidatorTrait;
protected $emailSentCode = 202;
protected $url = 'https://api.sendgrid.com/v3/mail/send';
public function send()
{
if ($this->preSend()) {
return $this->postSend();
}
return $this->handleResponse(new \WP_Error(422, __('Something went wrong!', 'fluent-smtp'), []));
}
public function postSend()
{
$body = [
'from' => $this->getFrom(),
'personalizations' => $this->getRecipients(),
'subject' => $this->getSubject(),
'content' => $this->getBody()
];
if ($replyTo = $this->getReplyTo()) {
$body['reply_to'] = $replyTo;
}
if (!empty($this->getParam('attachments'))) {
$body['attachments'] = $this->getAttachments();
}
$params = [
'body' => json_encode($body),
'headers' => $this->getRequestHeaders()
];
$params = array_merge($params, $this->getDefaultParams());
$response = wp_safe_remote_post($this->url, $params);
if (is_wp_error($response)) {
$returnResponse = new \WP_Error($response->get_error_code(), $response->get_error_message(), $response->get_error_messages());
} else {
$responseBody = wp_remote_retrieve_body($response);
$responseCode = wp_remote_retrieve_response_code($response);
$isOKCode = $responseCode == $this->emailSentCode;
$responseBody = \json_decode($responseBody, true);
if ($isOKCode) {
$returnResponse = [
'code' => 202,
'message' => Arr::get($responseBody, 'message')
];
} else {
$returnResponse = new \WP_Error($responseCode, Arr::get($responseBody, 'errors.0.message', 'Unknown Error'), $responseBody);
}
}
$this->response = $returnResponse;
return $this->handleResponse($this->response);
}
protected function getFrom()
{
$from = [
'email' => $this->getParam('sender_email')
];
if ($name = $this->getParam('sender_name')) {
$from['name'] = $name;
}
return $from;
}
protected function getReplyTo()
{
if ($replyTo = $this->getParam('headers.reply-to')) {
return reset($replyTo);
}
}
protected function getRecipients()
{
$recipients = [
'to' => $this->getTo(),
'cc' => $this->getCarbonCopy(),
'bcc' => $this->getBlindCarbonCopy(),
];
$recipients = array_filter($recipients);
foreach ($recipients as $key => $recipient) {
$array = array_map(function ($recipient) {
return isset($recipient['name'])
? $recipient['name'] . ' <' . $recipient['email'] . '>'
: $recipient['email'];
}, $recipient);
$this->attributes['formatted'][$key] = implode(', ', $array);
}
return [$recipients];
}
protected function getTo()
{
return $this->getParam('to');
}
protected function getCarbonCopy()
{
return $this->getParam('headers.cc');
}
protected function getBlindCarbonCopy()
{
return $this->getParam('headers.bcc');
}
protected function getBody()
{
$contentType = $this->getParam('headers.content-type');
if ($contentType == 'multipart/alternative') {
return [
[
'value' => $this->phpMailer->AltBody,
'type' => 'text/plain'
],
[
'value' => $this->getParam('message'),
'type' => 'text/html'
]
];
}
return [
[
'value' => $this->getParam('message'),
'type' => $contentType
]
];
}
protected function getAttachments()
{
$data = [];
foreach ($this->getParam('attachments') as $attachment) {
$file = false;
try {
if (is_file($attachment[0]) && is_readable($attachment[0])) {
$fileName = basename($attachment[0]);
$contentId = wp_hash($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;
}
$data[] = [
'type' => $filetype,
'filename' => $fileName,
'disposition' => 'attachment',
'content_id' => $contentId,
'content' => base64_encode($file)
];
}
return $data;
}
protected function getCustomEmailHeaders()
{
return [];
}
protected function getRequestHeaders()
{
return [
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $this->getSetting('api_key')
];
}
public function setSettings($settings)
{
if ($settings['key_store'] == 'wp_config') {
$settings['api_key'] = defined('FLUENTMAIL_SENDGRID_API_KEY') ? FLUENTMAIL_SENDGRID_API_KEY : '';
}
$this->settings = $settings;
return $this;
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\SendGrid;
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, 'api_key')) {
$errors['api_key']['required'] = __('Api key is required.', 'fluent-smtp');
}
} else if($keyStoreType == 'wp_config') {
if(!defined('FLUENTMAIL_SENDGRID_API_KEY') || !FLUENTMAIL_SENDGRID_API_KEY) {
$errors['api_key']['required'] = __('Please define FLUENTMAIL_SENDGRID_API_KEY in wp-config.php file.', 'fluent-smtp');
}
}
if ($errors) {
$this->throwValidationException($errors);
}
}
public function checkConnection($connection)
{
return true;
}
}

View File

@@ -0,0 +1,199 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\SendInBlue;
use WP_Error as WPError;
use FluentMail\Includes\Support\Arr;
use FluentMail\Includes\Core\Application;
use FluentMail\App\Services\Mailer\Manager;
use FluentMail\App\Services\Mailer\BaseHandler;
use FluentMail\App\Services\Mailer\Providers\SendInBlue\ValidatorTrait;
class Handler extends BaseHandler
{
use ValidatorTrait;
protected $emailSentCode = 201;
protected $url = 'https://api.brevo.com/v3/smtp/email';
protected $allowedAttachmentExts = [
'xlsx', 'xls', 'ods', 'docx', 'docm', 'doc', 'csv', 'pdf', 'txt', 'gif',
'jpg', 'jpeg', 'png', 'tif', 'tiff', 'rtf', 'bmp', 'cgm', 'css', 'shtml',
'html', 'htm', 'zip', 'xml', 'ppt', 'pptx', 'tar', 'ez', 'ics', 'mobi',
'msg', 'pub', 'eps', 'odt', 'mp3', 'm4a', 'm4v', 'wma', 'ogg', 'flac',
'wav', 'aif', 'aifc', 'aiff', 'mp4', 'mov', 'avi', 'mkv', 'mpeg', 'mpg', 'wmv'
];
public function send()
{
if ($this->preSend()) {
return $this->postSend();
}
return $this->handleResponse(new \WP_Error(422, __('Something went wrong!', 'fluent-smtp'), []));
}
public function postSend()
{
$body = [
'sender' => $this->getFrom(),
'subject' => $this->getSubject(),
'htmlContent' => $this->getBody()
];
$contentType = $this->getParam('headers.content-type');
if ($contentType == 'multipart/alternative') {
$body['textContent'] = $this->phpMailer->AltBody;
} else if ($contentType == 'text/plain') {
$body['textContent'] = $this->getBody();
unset($body['htmlContent']);
}
if ($replyTo = $this->getReplyTo()) {
$body['replyTo'] = $replyTo;
}
$recipients = $this->setRecipients();
$body = array_merge($body, $recipients);
if (!empty($this->getParam('attachments'))) {
$body['attachment'] = $this->getAttachments();
}
$params = [
'body' => json_encode($body),
'headers' => $this->getRequestHeaders()
];
$params = array_merge($params, $this->getDefaultParams());
$response = wp_safe_remote_post($this->url, $params);
if (is_wp_error($response)) {
$returnResponse = new \WP_Error($response->get_error_code(), $response->get_error_message(), $response->get_error_messages());
} else {
$responseBody = wp_remote_retrieve_body($response);
$responseCode = wp_remote_retrieve_response_code($response);
$isOKCode = $responseCode == $this->emailSentCode;
$responseBody = \json_decode($responseBody, true);
if ($isOKCode) {
$returnResponse = [
'messageId' => Arr::get($responseBody, 'messageId')
];
} else {
$returnResponse = new \WP_Error($responseCode, Arr::get($responseBody, 'message', __('SendInBlueError API Error', 'fluent-smtp')), $responseBody);
}
}
$this->response = $returnResponse;
return $this->handleResponse($this->response);
}
public function setSettings($settings)
{
if ($settings['key_store'] == 'wp_config') {
$settings['api_key'] = defined('FLUENTMAIL_SENDINBLUE_API_KEY') ? FLUENTMAIL_SENDINBLUE_API_KEY : '';
}
$this->settings = $settings;
return $this;
}
protected function getFrom()
{
return [
'name' => $this->getParam('sender_name'),
'email' => $this->getParam('sender_email')
];
}
protected function getReplyTo()
{
if ($replyTo = $this->getParam('headers.reply-to')) {
return reset($replyTo);
}
}
protected function setRecipients()
{
$recipients = [
'to' => $this->getTo(),
'cc' => $this->getCarbonCopy(),
'bcc' => $this->getBlindCarbonCopy()
];
$recipients = array_filter($recipients);
foreach ($recipients as $key => $recipient) {
$array = array_map(function ($recipient) {
return isset($recipient['name'])
? $recipient['name'] . ' <' . $recipient['email'] . '>'
: $recipient['email'];
}, $recipient);
$this->attributes['formatted'][$key] = implode(', ', $array);
}
return $recipients;
}
protected function getTo()
{
return $this->getParam('to');
}
protected function getCarbonCopy()
{
return $this->getParam('headers.cc');
}
protected function getBlindCarbonCopy()
{
return $this->getParam('headers.bcc');
}
protected function getBody()
{
return $this->getParam('message');
}
protected function getAttachments()
{
$files = [];
foreach ($this->getParam('attachments') as $attachment) {
if (is_file($attachment[0]) && is_readable($attachment[0])) {
$ext = pathinfo($attachment[0], PATHINFO_EXTENSION);
if (in_array($ext, $this->allowedAttachmentExts, true)) {
$files[] = [
'name' => basename($attachment[0]),
'content' => base64_encode(file_get_contents($attachment[0]))
];
}
}
}
return $files;
}
protected function getCustomEmailHeaders()
{
return [];
}
protected function getRequestHeaders()
{
return [
'Api-Key' => $this->getSetting('api_key'),
'Content-Type' => 'application/json',
'Accept' => 'application/json'
];
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\SendInBlue;
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, 'api_key')) {
$errors['api_key']['required'] = __('Api key is required.', 'fluent-smtp');
}
} else if($keyStoreType == 'wp_config') {
if(!defined('FLUENTMAIL_SENDINBLUE_API_KEY') || !FLUENTMAIL_SENDINBLUE_API_KEY) {
$errors['api_key']['required'] = __('Please define FLUENTMAIL_SENDINBLUE_API_KEY in wp-config.php file.', 'fluent-smtp');
}
}
if ($errors) {
$this->throwValidationException($errors);
}
}
}

View File

@@ -0,0 +1,57 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\Simulator;
use FluentMail\App\Models\Logger;
use FluentMail\App\Services\Mailer\BaseHandler;
class Handler extends BaseHandler
{
public function send()
{
if($this->shouldBeLogged(true)) {
$atts = $this->setAttributes();
$customHeaders = $atts['custom_headers'];
$headers = $atts['headers'];
foreach ($customHeaders as $customHeader) {
$headers[$customHeader['key']] = $customHeader['value'];
}
$headers = $this->phpMailer->getCustomHeaders();
$headers['content-type'] = $this->phpMailer->ContentType;
$logData = [
'to' => maybe_serialize($this->setRecipientsArray($this->phpMailer->getToAddresses())),
'from' => maybe_serialize($this->phpMailer->From),
'subject' => $this->phpMailer->Subject,
'body' => $this->phpMailer->Body,
'attachments' => maybe_serialize($this->phpMailer->getAttachments()),
'status' => 'sent',
'response' => maybe_serialize(['status' => __('Email sending was simulated, No Email was sent originally', 'fluent-smtp')]),
'headers' => maybe_serialize($headers),
'extra' => maybe_serialize(['provider' => 'Simulator'])
];
(new Logger)->add($logData);
}
return true;
}
protected function postSend()
{
$returnResponse = [
'response' => 'OK'
];
$this->response = $returnResponse;
return $this->handleResponse($this->response);
}
public function setSettings($settings)
{
$this->settings = $settings;
return $this;
}
}

View File

@@ -0,0 +1,141 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\Smtp;
use FluentMail\Includes\Support\Arr;
use FluentMail\Includes\Core\Application;
use FluentMail\App\Services\Mailer\BaseHandler;
use FluentMail\App\Services\Mailer\Providers\Smtp\ValidatorTrait;
class Handler extends BaseHandler
{
use ValidatorTrait;
public function send()
{
if ($this->preSend()) {
if ($this->getSetting('auto_tls') == 'no') {
$this->phpMailer->SMTPAutoTLS = false;
}
return $this->postSend();
}
return $this->handleResponse(new \WP_Error(422, __('Something went wrong!', 'fluent-smtp'), []));
}
protected function postSend()
{
try {
$this->phpMailer->isSMTP();
$this->phpMailer->Host = $this->getSetting('host');
$this->phpMailer->Port = $this->getSetting('port');
if ($this->getSetting('auth') == 'yes') {
$this->phpMailer->SMTPAuth = true;
$this->phpMailer->Username = $this->getSetting('username');
$this->phpMailer->Password = $this->getSetting('password');
}
if (($encryption = $this->getSetting('encryption')) != 'none') {
$this->phpMailer->SMTPSecure = $encryption;
}
$fromEmail = $this->phpMailer->From;
if ($this->isForcedEmail() && !fluentMailIsListedSenderEmail($fromEmail)) {
$fromEmail = $this->getSetting('sender_email');
}
if (isset($this->phpMailer->FromName)) {
$fromName = $this->phpMailer->FromName;
if (
$this->getSetting('force_from_name') == 'yes' &&
$customFrom = $this->getSetting('sender_name')
) {
$fromName = $customFrom;
}
$this->phpMailer->setFrom($fromEmail, $fromName);
} else {
$this->phpMailer->setFrom($fromEmail);
}
foreach ($this->getParam('to') as $to) {
if (isset($to['name'])) {
$this->phpMailer->addAddress($to['email'], $to['name']);
} else {
$this->phpMailer->addAddress($to['email']);
}
}
foreach ($this->getParam('headers.reply-to') as $replyTo) {
if (isset($replyTo['name'])) {
$this->phpMailer->addReplyTo($replyTo['email'], $replyTo['name']);
} else {
$this->phpMailer->addReplyTo($replyTo['email']);
}
}
foreach ($this->getParam('headers.cc') as $cc) {
if (isset($cc['name'])) {
$this->phpMailer->addCC($cc['email'], $cc['name']);
} else {
$this->phpMailer->addCC($cc['email']);
}
}
foreach ($this->getParam('headers.bcc') as $bcc) {
if (isset($bcc['name'])) {
$this->phpMailer->addBCC($bcc['email'], $bcc['name']);
} else {
$this->phpMailer->addBCC($bcc['email']);
}
}
if ($attachments = $this->getParam('attachments')) {
foreach ($attachments as $attachment) {
$this->phpMailer->addAttachment($attachment[0], $attachment[7]);
}
}
if ($this->getParam('headers.content-type') == 'text/html' || $this->getParam('headers.content-type') == 'multipart/alternative') {
$this->phpMailer->isHTML(true);
}
$this->phpMailer->Subject = $this->getSubject();
$this->phpMailer->Body = $this->getParam('message');
if ($this->getParam('headers.content-type') == 'multipart/alternative') {
$this->phpMailer->AltBody = $this->getParam('alt_body');
$this->phpMailer->ContentType = 'multipart/alternative';
}
$this->phpMailer->send();
$returnResponse = [
'response' => 'OK'
];
} catch (\Exception $e) {
$returnResponse = new \WP_Error(422, $e->getMessage(), []);
}
$this->response = $returnResponse;
return $this->handleResponse($this->response);
}
public function setSettings($settings)
{
if (Arr::get($settings, 'key_store') == 'wp_config') {
$settings['username'] = defined('FLUENTMAIL_SMTP_USERNAME') ? FLUENTMAIL_SMTP_USERNAME : '';
$settings['password'] = defined('FLUENTMAIL_SMTP_PASSWORD') ? FLUENTMAIL_SMTP_PASSWORD : '';
}
$this->settings = $settings;
return $this;
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\Smtp;
use FluentMail\Includes\Support\Arr;
use FluentMail\App\Services\Mailer\ValidatorTrait as BaseValidatorTrait;
trait ValidatorTrait
{
use BaseValidatorTrait;
public function validateProviderInformation($connection)
{
$errors = [];
$keyStoreType = Arr::get($connection, 'key_store', 'db');
if (!Arr::get($connection, 'host')) {
$errors['host']['required'] = __('SMTP host is required.', 'fluent-smtp');
}
if (!Arr::get($connection, 'port')) {
$errors['port']['required'] = __('SMTP port is required.', 'fluent-smtp');
}
if (Arr::get($connection, 'auth') == 'yes') {
if ($keyStoreType == 'wp_config') {
if (!defined('FLUENTMAIL_SMTP_USERNAME') || !FLUENTMAIL_SMTP_USERNAME) {
$errors['username']['required'] = __('Please define FLUENTMAIL_SMTP_USERNAME in wp-config.php file.', 'fluent-smtp');
}
if (!defined('FLUENTMAIL_SMTP_PASSWORD') || !FLUENTMAIL_SMTP_PASSWORD) {
$errors['password']['required'] = __('Please define FLUENTMAIL_SMTP_PASSWORD in wp-config.php file.', 'fluent-smtp');
}
} else {
if (!Arr::get($connection, 'username')) {
$errors['username']['required'] = __('SMTP username is required.', 'fluent-smtp');
}
if (!Arr::get($connection, 'password')) {
$errors['password']['required'] = __('SMTP password is required.', 'fluent-smtp');
}
}
}
if ($errors) {
$this->throwValidationException($errors);
}
}
}

View File

@@ -0,0 +1,174 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\Smtp2Go;
use WP_Error as WPError;
use FluentMail\Includes\Support\Arr;
use FluentMail\Includes\Core\Application;
use FluentMail\App\Services\Mailer\Manager;
use FluentMail\App\Services\Mailer\BaseHandler;
use FluentMail\App\Services\Mailer\Providers\Smtp2Go\ValidatorTrait;
class Handler extends BaseHandler {
use ValidatorTrait;
protected $emailSentCode = 200;
protected $url = 'https://api.smtp2go.com/v3/email/send';
public function send() {
if ($this->preSend()) {
return $this->postSend();
}
return $this->handleResponse(new \WP_Error(422, __('Something went wrong!', 'fluent-smtp'), []));
}
public function postSend() {
$body = [
'sender' => $this->getFrom(),
'to' => $this->getTo(),
'cc' => $this->getCarbonCopy(),
'bcc' => $this->getBlindCarbonCopy(),
'subject' => $this->getSubject(),
'html_body' => $this->getBody(),
'text_body' => $this->phpMailer->AltBody
];
if ($replyTo = $this->getReplyTo()) {
$body['custom_headers'][] = [
'header' => 'Reply-To',
'value' => $replyTo
];
}
if (!empty($this->getParam('attachments'))) {
$body['attachments'] = $this->getAttachments();
}
$params = [
'body' => json_encode($body),
'headers' => $this->getRequestHeaders()
];
$params = array_merge($params, $this->getDefaultParams());
$response = wp_safe_remote_post($this->url, $params);
if (is_wp_error($response)) {
$returnResponse = new \WP_Error($response->get_error_code(), $response->get_error_message(), $response->get_error_messages());
} else {
$responseBody = wp_remote_retrieve_body($response);
$responseCode = wp_remote_retrieve_response_code($response);
$isOKCode = $responseCode == $this->emailSentCode;
$responseBody = \json_decode($responseBody, true);
if ($isOKCode) {
$returnResponse = [
'email_id' => Arr::get($responseBody, 'data.email_id'),
'succeeded' => Arr::get($responseBody, 'data.succeeded'),
];
} else {
$returnResponse = new \WP_Error($responseCode, Arr::get($responseBody, 'data.error', 'Unknown Error'), $responseBody);
}
}
$this->response = $returnResponse;
return $this->handleResponse($this->response);
}
protected function getFrom() {
$from = $this->getParam('sender_email');
if ($name = $this->getParam('sender_name')) {
$from = $name . ' <' . $from . '>';
}
return $from;
}
protected function getReplyTo() {
if ($replyTo = $this->getParam('headers.reply-to')) {
$replyTo = reset($replyTo);
return $replyTo['email'];
}
}
protected function getRecipients($recipients) {
return array_map(function ($recipient) {
return isset($recipient['name'])
? $recipient['name'] . ' <' . $recipient['email'] . '>'
: $recipient['email'];
}, $recipients);
}
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 getBody() {
return $this->getParam('message');
}
protected function getAttachments() {
$data = [];
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;
}
$data[] = [
'mimetype' => $filetype,
'filename' => $fileName,
'fileblob' => base64_encode($file)
];
}
return $data;
}
protected function getCustomEmailHeaders() {
return [];
}
protected function getRequestHeaders() {
return [
'Content-Type' => 'application/json',
'X-Smtp2go-Api-Key' => $this->getSetting('api_key')
];
}
public function setSettings($settings) {
if ($settings['key_store'] == 'wp_config') {
$settings['api_key'] = defined('FLUENTMAIL_SMTP2GO_API_KEY') ? FLUENTMAIL_SMTP2GO_API_KEY : '';
}
$this->settings = $settings;
return $this;
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\Smtp2Go;
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, 'api_key')) {
$errors['api_key']['required'] = __('Api key is required.', 'fluent-smtp');
}
} else if($keyStoreType == 'wp_config') {
if(!defined('FLUENTMAIL_SMTP2GO_API_KEY') || !FLUENTMAIL_SMTP2GO_API_KEY) {
$errors['api_key']['required'] = __('Please define FLUENTMAIL_SMTP2GO_API_KEY in wp-config.php file.', 'fluent-smtp');
}
}
if ($errors) {
$this->throwValidationException($errors);
}
}
public function checkConnection($connection)
{
return true;
}
}

View File

@@ -0,0 +1,210 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\SparkPost;
use WP_Error as WPError;
use FluentMail\Includes\Support\Arr;
use FluentMail\Includes\Core\Application;
use FluentMail\App\Services\Mailer\Manager;
use FluentMail\App\Services\Mailer\BaseHandler;
use FluentMail\App\Services\Mailer\Providers\SparkPost\ValidatorTrait;
class Handler extends BaseHandler
{
use ValidatorTrait;
protected $emailSentCode = 202;
protected $url = 'https://api.sparkpost.com/api/v1/transmissions';
public function send()
{
if ($this->preSend()) {
return $this->postSend();
}
return $this->handleResponse(new \WP_Error(422, __('Something went wrong!', 'fluent-smtp'), []) );
}
public function postSend()
{
$body = [
'options' => [
'sandbox' => false
],
'content' => [
'from' => $this->getFrom(),
'subject' => $this->getSubject(),
'html' => $this->phpMailer->Body,
'text' => $this->phpMailer->AltBody,
'headers' => (object) []
],
'recipients' => $this->getTo(),
'cc' => $this->getCarbonCopy(),
'bcc' => $this->getBlindCarbonCopy()
];
if ($replyTo = $this->getReplyTo()) {
$body['content']['reply_to'] = $replyTo;
}
if (!empty($this->getParam('attachments'))) {
$body['content']['attachments'] = $this->getAttachments();
}
$params = [
'body' => json_encode($body),
'headers' => $this->getRequestHeaders()
];
$params = array_merge($params, $this->getDefaultParams());
$response = wp_safe_remote_post($this->url, $params);
if (is_wp_error($response)) {
$returnResponse = new \WP_Error($response->get_error_code(), $response->get_error_message(), $response->get_error_messages());
} else {
$responseBody = wp_remote_retrieve_body($response);
$responseCode = wp_remote_retrieve_response_code($response);
$isOKCode = $responseCode < 300;
$responseBody = \json_decode($responseBody, true);
if($isOKCode) {
$returnResponse = [
'response' => $responseBody
];
} else {
$returnResponse = new \WP_Error($responseCode, __('SparkPost API Error', 'fluent-smtp'), $responseBody);
}
}
$this->response = $returnResponse;
return $this->handleResponse($this->response);
}
public function setSettings($settings)
{
if($settings['key_store'] == 'wp_config') {
$settings['api_key'] = defined('FLUENTMAIL_SPARKPOST_API_KEY') ? FLUENTMAIL_SPARKPOST_API_KEY : '';
}
$this->settings = $settings;
return $this;
}
protected function getFrom()
{
$email = $this->getParam('sender_email');
if ($name = $this->getParam('sender_name')) {
$from = $name . ' <' . $email . '>';
} else {
$from = $email;
}
return $from;
}
protected function getTo()
{
$address = [];
foreach ($this->getParam('to') as $to) {
$address[] = [
'address' => [
'email' => $to['email']
]
];
}
return $address;
}
protected function getReplyTo()
{
if ($replyTo = $this->getParam('headers.reply-to')) {
$replyTo = reset($replyTo);
return $replyTo['email'];
}
}
protected function getCarbonCopy()
{
$address = [];
foreach ($this->getParam('headers.cc') as $cc) {
$address[] = [
'address' => [
'email' => $cc['email']
]
];
}
return $address;
}
protected function getBlindCarbonCopy()
{
$address = [];
foreach ($this->getParam('headers.bcc') as $bcc) {
$address[] = [
'address' => [
'email' => $bcc['email']
]
];
}
return $address;
}
protected function getAttachments()
{
$data = [];
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;
}
$data[] = [
'name' => $fileName,
'type' => $filetype,
'content' => base64_encode($file)
];
}
return $data;
}
protected function getCustomEmailHeaders()
{
return [
'X-Mailer' => 'FluentMail - SparkPost'
];
}
protected function getRequestHeaders()
{
return [
'Content-Type' => 'application/json',
'Authorization' => $this->getSetting('api_key')
];
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\SparkPost;
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, 'api_key')) {
$errors['api_key']['required'] = __('Api key is required.', 'fluent-smtp');
}
} else if($keyStoreType == 'wp_config') {
if(!defined('FLUENTMAIL_SPARKPOST_API_KEY') || !FLUENTMAIL_SPARKPOST_API_KEY) {
$errors['api_key']['required'] = __('Please define FLUENTMAIL_SPARKPOST_API_KEY in wp-config.php file.', 'fluent-smtp');
}
}
if ($errors) {
$this->throwValidationException($errors);
}
}
}

View File

@@ -0,0 +1,253 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\TransMail;
use FluentMail\Includes\Support\Arr;
use FluentMail\App\Services\Mailer\BaseHandler;
class Handler extends BaseHandler
{
use ValidatorTrait;
protected $emailSentCode = 200;
protected $url = null;
public function send()
{
if ($this->preSend()) {
$this->setUrl();
return $this->postSend();
}
return $this->handleResponse(new \WP_Error(422, __('Something went wrong!', 'fluent-smtp'), []));
}
protected function setUrl()
{
return $this->url = 'https://transmail.zoho.' . $this->getSetting('domain_name') . '/v1.1/email';
}
public function postSend()
{
$body = [
'bounce_address' => $this->getSetting('bounce_address'),
'from' => json_encode([
'name' => $this->phpMailer->FromName,
'address' => $this->phpMailer->From,
]),
'to' => json_encode([
[
'email_address' => [
'address' => '',
'name' => ''
]
]
]),
'cc' => json_encode([
[
'email_address' => [
'address' => '',
'name' => ''
]
]
]),
'bcc' => json_encode([
[
'email_address' => [
'address' => '',
'name' => ''
]
]
]),
'reply_to' => json_encode([
'address' => '',
'name' => ''
]),
'subject' => $this->getSubject()
];
if ($this->phpMailer->ContentType == 'text/html') {
$body['htmlbody'] = $this->getBody();
} else if ($this->phpMailer->ContentType == 'multipart/alternative') {
$body['htmlbody'] = $this->getBody();
$body['textbody'] = $this->getParam('alt_body');
} else {
$body['textbody'] = $this->getBody();
}
$headers1 = array(
'Authorization' => 'Zoho-enczapikey ' . $this->getSetting('token'),
'Content-Type' => 'application/json',
'Accept' => 'application/json'
);
$data_string = json_encode($body);
$args = array(
'body' => $data_string,
'headers' => $headers1,
'method' => 'POST'
);
$response = wp_safe_remote_post($this->url, $args);
if (is_wp_error($response)) {
$returnResponse = new \WP_Error($response->get_error_code(), $response->get_error_message(), $response->get_error_messages());
} else {
$responseBody = wp_remote_retrieve_body($response);
$responseCode = wp_remote_retrieve_response_code($response);
$isOKCode = $responseCode == $this->emailSentCode;
if ($isOKCode) {
$responseBody = \json_decode($responseBody, true);
}
if ($isOKCode && isset($responseBody['id'])) {
$returnResponse = [
'id' => Arr::get($responseBody, 'id'),
'message' => Arr::get($responseBody, 'message')
];
} else {
$returnResponse = new \WP_Error($responseCode, __('Mailgun API Error', 'fluent-smtp'), $responseBody);
}
}
$this->response = $returnResponse;
return $this->handleResponse($this->response);
}
public function setSettings($settings)
{
if ($settings['key_store'] == 'wp_config') {
$settings['api_key'] = defined('FLUENTMAIL_MAILGUN_API_KEY') ? FLUENTMAIL_MAILGUN_API_KEY : '';
$settings['domain_name'] = defined('FLUENTMAIL_MAILGUN_DOMAIN') ? FLUENTMAIL_MAILGUN_DOMAIN : '';
}
$this->settings = $settings;
return $this;
}
protected function getFrom()
{
return $this->getParam('from');
}
protected function getReplyTo()
{
return $this->getRecipients(
$this->getParam('headers.reply-to')
);
}
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->getParam('message');
}
protected function getAttachments($params)
{
$data = [];
$payload = '';
$attachments = $this->attributes['attachments'];
foreach ($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]);
}
} catch (\Exception $e) {
$file = false;
}
if ($file === false) {
continue;
}
$data[] = [
'content' => $file,
'name' => $fileName,
];
}
if (!empty($data)) {
$boundary = hash('sha256', uniqid('', true));
foreach ($params['body'] as $key => $value) {
if (is_array($value)) {
foreach ($value as $child_key => $child_value) {
$payload .= '--' . $boundary;
$payload .= "\r\n";
$payload .= 'Content-Disposition: form-data; name="' . $key . "\"\r\n\r\n";
$payload .= $child_value;
$payload .= "\r\n";
}
} else {
$payload .= '--' . $boundary;
$payload .= "\r\n";
$payload .= 'Content-Disposition: form-data; name="' . $key . '"' . "\r\n\r\n";
$payload .= $value;
$payload .= "\r\n";
}
}
foreach ($data as $key => $attachment) {
$payload .= '--' . $boundary;
$payload .= "\r\n";
$payload .= 'Content-Disposition: form-data; name="attachment[' . $key . ']"; filename="' . $attachment['name'] . '"' . "\r\n\r\n";
$payload .= $attachment['content'];
$payload .= "\r\n";
}
$payload .= '--' . $boundary . '--';
$params['body'] = $payload;
$params['headers']['Content-Type'] = 'multipart/form-data; boundary=' . $boundary;
$this->attributes['headers']['content-type'] = 'multipart/form-data';
}
return $params;
}
protected function getRequestHeaders()
{
$apiKey = $this->getSetting('api_key');
return [
'Authorization' => 'Basic ' . base64_encode('api:' . $apiKey)
];
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace FluentMail\App\Services\Mailer\Providers\TransMail;
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, 'api_key')) {
$errors['api_key']['required'] = __('Api key is required.', 'fluent-smtp');
}
if (! Arr::get($connection, 'domain_name')) {
$errors['domain_name']['required'] = __('Domain name is required.', 'fluent-smtp');
}
} else if($keyStoreType == 'wp_config') {
if(!defined('FLUENTMAIL_MAILGUN_API_KEY') || !FLUENTMAIL_MAILGUN_API_KEY) {
$errors['api_key']['required'] = __('Please define FLUENTMAIL_MAILGUN_API_KEY in wp-config.php file.', 'fluent-smtp');
}
if(!defined('FLUENTMAIL_MAILGUN_DOMAIN') || !FLUENTMAIL_MAILGUN_DOMAIN) {
$errors['domain_name']['required'] = __('Please define FLUENTMAIL_MAILGUN_DOMAIN in wp-config.php file.', 'fluent-smtp');
}
}
if ($errors) {
$this->throwValidationException($errors);
}
}
}

View File

@@ -0,0 +1,252 @@
<?php
return [
'connections' => [],
'mappings' => [],
'providers' => [
'smtp' => [
'key' => 'smtp',
'title' => __('SMTP server', 'fluent-smtp'),
'image' => fluentMailAssetUrl('images/provider-smtp.svg'),
'provider' => 'Smtp',
'need_pro' => 'no',
'is_smtp' => true,
'options' => [
'sender_name' => '',
'sender_email' => '',
'force_from_name' => 'no',
'force_from_email' => 'yes',
'return_path' => 'yes',
'host' => '',
'port' => '',
'auth' => 'yes',
'username' => '',
'password' => '',
'auto_tls' => 'yes',
'encryption' => 'none',
'key_store' => 'db'
],
'note' => '<a href="https://fluentsmtp.com/docs/set-up-fluent-smtp-with-any-host-or-mailer/" target="_blank" rel="noopener">' . __('Read the documentation', 'fluent-smtp') . '</a>' . __(' for how to configure any SMTP with FluentSMTP.', 'fluent-smtp')
],
'ses' => [
'key' => 'ses',
'title' => __('Amazon SES', 'fluent-smtp'),
'image' => fluentMailAssetUrl('images/provider-aws-ses.svg'),
'provider' => 'AmazonSes',
'options' => [
'sender_name' => '',
'sender_email' => '',
'force_from_name' => 'no',
'force_from_email' => 'yes',
'return_path' => 'yes',
'access_key' => '',
'secret_key' => '',
'region' => 'us-east-1',
'key_store' => 'db'
],
'regions' => [
'us-east-1' => __('US East (N. Virginia)', 'fluent-smtp'),
'us-east-2' => __('US East (Ohio)', 'fluent-smtp'),
'us-west-1' => __('US West (N. California)', 'fluent-smtp'),
'us-west-2' => __('US West (Oregon)', 'fluent-smtp'),
'ca-central-1' => __('Canada (Central)', 'fluent-smtp'),
'eu-west-1' => __('EU (Ireland)', 'fluent-smtp'),
'eu-west-2' => __('EU (London)', 'fluent-smtp'),
'eu-west-3' => __('Europe (Paris)', 'fluent-smtp'),
'eu-central-1' => __('EU (Frankfurt)', 'fluent-smtp'),
'eu-south-1' => __('Europe (Milan)', 'fluent-smtp'),
'eu-north-1' => __('Europe (Stockholm)', 'fluent-smtp'),
'ap-south-1' => __('Asia Pacific (Mumbai)', 'fluent-smtp'),
'ap-northeast-2' => __('Asia Pacific (Seoul)', 'fluent-smtp'),
'ap-southeast-1' => __('Asia Pacific (Singapore)', 'fluent-smtp'),
'ap-southeast-2' => __('Asia Pacific (Sydney)', 'fluent-smtp'),
'ap-northeast-1' => __('Asia Pacific (Tokyo)', 'fluent-smtp'),
'ap-northeast-3' => __('Asia Pacific (Osaka)', 'fluent-smtp'),
'sa-east-1' => __('South America (São Paulo)', 'fluent-smtp'),
'me-south-1' => __('Middle East (Bahrain)', 'fluent-smtp'),
'us-gov-west-1' => __('AWS GovCloud (US)', 'fluent-smtp'),
'af-south-1' => __('Africa (Cape Town)', 'fluent-smtp'),
'cn-northwest-1' => __('China (Ningxia)', 'fluent-smtp')
],
'note' => '<a href="https://fluentsmtp.com/docs/set-up-amazon-ses-in-fluent-smtp/" target="_blank" rel="noopener">' . __('Read the documentation', 'fluent-smtp') . '</a>' . __(' for how to configure Amazon SES with FluentSMTP.', 'fluent-smtp')
],
'mailgun' => [
'key' => 'mailgun',
'title' => __('Mailgun', 'fluent-smtp'),
'image' => fluentMailAssetUrl('images/provider-mailgun.svg'),
'provider' => 'Mailgun',
'options' => [
'sender_name' => '',
'sender_email' => '',
'force_from_name' => 'no',
'return_path' => 'yes',
'api_key' => '',
'domain_name' => '',
'key_store' => 'db',
'region' => 'us'
],
'note' => '<a href="https://fluentsmtp.com/docs/configure-mailgun-in-fluent-smtp-to-send-emails/" target="_blank" rel="noopener">' . __('Read the documentation', 'fluent-smtp') . '</a>' . __(' for how to configure Mailgun with FluentSMTP.', 'fluent-smtp')
],
'sendgrid' => [
'key' => 'sendgrid',
'title' => __('SendGrid', 'fluent-smtp'),
'image' => fluentMailAssetUrl('images/provider-sendgrid.svg'),
'provider' => 'SendGrid',
'options' => [
'sender_name' => '',
'sender_email' => '',
'force_from_name' => 'no',
'api_key' => '',
'key_store' => 'db'
],
'note' => '<a href="https://fluentsmtp.com/docs/set-up-the-sendgrid-driver-in-fluent-smtp/" target="_blank" rel="noopener">' . __('Read the documentation', 'fluent-smtp') . '</a>' . __(' for how to configure SendGrid with FluentSMTP.', 'fluent-smtp')
],
'sendinblue' => [
'key' => 'sendinblue',
'title' => __('Sendinblue', 'fluent-smtp'),
'image' => fluentMailAssetUrl('images/provider-sendinblue.svg'),
'provider' => 'SendInBlue',
'options' => [
'sender_name' => '',
'sender_email' => '',
'force_from_name' => 'no',
'api_key' => '',
'key_store' => 'db'
],
'note' => '<a href="https://fluentsmtp.com/docs/setting-up-sendinblue-mailer-in-fluent-smtp/" target="_blank" rel="noopener">' . __('Read the documentation', 'fluent-smtp') . '</a>' . __(' for how to configure Sendinblue with FluentSMTP.', 'fluent-smtp')
],
'sparkpost' => [
'key' => 'sparkpost',
'title' => __('SparkPost', 'fluent-smtp'),
'image' => fluentMailAssetUrl('images/provider-sparkpost.svg'),
'provider' => 'SparkPost',
'options' => [
'sender_name' => '',
'sender_email' => '',
'force_from_name' => 'no',
'api_key' => '',
'key_store' => 'db'
],
'note' => '<a href="https://fluentsmtp.com/docs/configure-sparkpost-in-fluent-smtp-to-send-emails/" target="_blank" rel="noopener">' . __('Read the documentation', 'fluent-smtp') . '</a>' . __(' for how to configure SparkPost with FluentSMTP.', 'fluent-smtp')
],
'pepipost' => [
'key' => 'pepipost',
'title' => __('Netcore Email API, formerly Pepipost', 'fluent-smtp'),
'image' => fluentMailAssetUrl('images/provider-netcore.svg'),
'provider' => 'PepiPost',
'options' => [
'sender_name' => '',
'sender_email' => '',
'force_from_name' => 'no',
'api_key' => '',
'key_store' => 'db'
],
'note' => '<a href="https://fluentsmtp.com/docs/set-up-the-pepipost-mailer-in-fluent-smtp/" target="_blank" rel="noopener">' . __('Read the documentation', 'fluent-smtp') . '</a>' . __(' for how to configure Netcore (formerly Pepipost) with FluentSMTP.', 'fluent-smtp')
],
'postmark' => [
'key' => 'postmark',
'title' => __('Postmark', 'fluent-smtp'),
'image' => fluentMailAssetUrl('images/provider-postmark.svg'),
'provider' => 'Postmark',
'options' => [
'sender_name' => '',
'sender_email' => '',
'force_from_name' => 'no',
'track_opens' => 'no',
'track_links' => 'no',
'api_key' => '',
'message_stream' => 'outbound',
'key_store' => 'db'
],
'note' => '<a href="https://fluentsmtp.com/docs/configure-postmark-in-fluent-smtp-to-send-emails/" target="_blank" rel="noopener">' . __('Read the documentation', 'fluent-smtp') . '</a>' . __(' for how to configure Postmark with FluentSMTP.', 'fluent-smtp')
],
'elasticmail' => [
'key' => 'elasticmail',
'title' => __('Elastic Email', 'fluent-smtp'),
'image' => fluentMailAssetUrl('images/provider-elastic-email.svg'),
'provider' => 'ElasticMail',
'options' => [
'sender_name' => '',
'sender_email' => '',
'force_from_name' => 'no',
'api_key' => '',
'mail_type' => 'transactional',
'key_store' => 'db'
],
'note' => '<a href="https://fluentsmtp.com/docs/configure-elastic-email-in-fluent-smtp/" target="_blank" rel="noopener">' . __('Read the documentation', 'fluent-smtp') . '</a>' . __(' for how to configure Elastic Email with FluentSMTP.', 'fluent-smtp')
],
'smtp2go' => [
'key' => 'smtp2go',
'title' => __('SMTP2GO', 'fluent-smtp'),
'image' => fluentMailAssetUrl('images/provider-smtp2go.svg'),
'provider' => 'Smtp2Go',
'options' => [
'sender_name' => '',
'sender_email' => '',
'force_from_name' => 'no',
'api_key' => '',
'key_store' => 'db'
]
],
'gmail' => [
'key' => 'gmail',
'title' => __('Gmail or Google Workspace', 'fluent-smtp'),
'image' => fluentMailAssetUrl('images/provider-gmail-google-workspace.svg'),
'provider' => 'Gmail',
'options' => [
'sender_name' => '',
'sender_email' => '',
'force_from_name' => 'no',
'return_path' => 'yes',
'key_store' => 'db',
'client_id' => '',
'client_secret' => '',
'auth_token' => '',
'access_token' => '',
'refresh_token' => ''
],
'note' => __('Gmail/Google Workspace is not recommended for sending mass marketing emails.', 'fluent-smtp')
],
'outlook' => [
'key' => 'outlook',
'title' => __('Outlook or Office 365', 'fluent-smtp'),
'image' => fluentMailAssetUrl('images/provider-microsoft.svg'),
'provider' => 'Outlook',
'options' => [
'sender_name' => '',
'sender_email' => '',
'force_from_name' => 'no',
'return_path' => 'yes',
'key_store' => 'db',
'client_id' => '',
'client_secret' => '',
'auth_token' => '',
'access_token' => '',
'refresh_token' => ''
],
'note' => __('Outlook/Office365 is not recommended for sending mass marketing emails.', 'fluent-smtp')
],
'default' => [
'key' => 'default',
'title' => __('PHP mail()', 'fluent-smtp'),
'image' => fluentMailAssetUrl('images/provider-php.svg'),
'provider' => 'DefaultMail',
'options' => [
'sender_name' => '',
'sender_email' => '',
'force_from_name' => 'no',
'force_from_email' => 'yes',
'return_path' => 'yes',
'key_store' => 'db'
],
'note' => __('The Default option does not use SMTP or any Email Service Providers so it will not improve email delivery on your site.', 'fluent-smtp')
],
],
'misc' => [
'log_emails' => 'yes',
'log_saved_interval_days' => '14',
'disable_fluentcrm_logs' => 'no',
'default_connection' => '',
'fallback_connection' => ''
]
];

View File

@@ -0,0 +1,39 @@
<?php
namespace FluentMail\App\Services\Mailer;
use FluentMail\App\Models\Settings;
use FluentMail\Includes\Support\Arr;
use FluentMail\Includes\Support\ValidationException;
trait ValidatorTrait
{
public function validateBasicInformation($connection)
{
$errors = [];
if (!($email = Arr::get($connection, 'sender_email'))) {
$errors['sender_email']['required'] = __('Sender email is required.', 'fluent-smtp');
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors['sender_email']['email'] = __('Invalid email address.', 'fluent-smtp');
}
if ($errors) {
$this->throwValidationException($errors);
}
}
public function validateProviderInformation($inputs)
{
// Required Method
}
public function throwValidationException($errors)
{
throw new ValidationException(
esc_html__('Unprocessable Entity', 'fluent-smtp'), 422, null, $errors // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
);
}
}

View File

@@ -0,0 +1 @@
<?php // silence is golden