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,484 @@
<?php
namespace FluentMail\App\Services;
use FluentMail\Includes\Support\Arr;
class Converter
{
public function getSuggestedConnection()
{
$wpMailSmtp = $this->maybeWPMailSmtp();
if($wpMailSmtp) {
return $wpMailSmtp;
}
$easySMTP = $this->maybeEasySmtp();
if($easySMTP) {
return $easySMTP;
}
return false;
}
private function maybeWPMailSmtp()
{
$wpMailSettings = get_option('wp_mail_smtp');
if (!$wpMailSettings) {
return false;
}
$mailSettings = Arr::get($wpMailSettings, 'mail', []);
$commonSettings = [
'sender_name' => $this->maybeFromWPMailDefined('mail', 'from_name', Arr::get($mailSettings, 'from_name')),
'sender_email' => $this->maybeFromWPMailDefined('mail', 'from_email', Arr::get($mailSettings, 'from_email')),
'force_from_name' => Arr::get($mailSettings, 'from_name_force') == 1 ? 'yes' : 'no',
'force_from_email' => Arr::get($mailSettings, 'from_email_force') == 1 ? 'yes' : 'no',
'return_path' => Arr::get($mailSettings, 'return_path') == 1 ? 'yes' : 'no'
];
// Let's try the SMTP First
$mailer = Arr::get($mailSettings, 'mailer');
if ($mailer == 'smtp') {
$smtp = Arr::get($wpMailSettings, 'smtp', []);
$auth = $this->maybeFromWPMailDefined('smtp', 'auth', Arr::get($smtp, 'auth')) == 1 ? 'yes' : 'no';
$userName = $this->maybeFromWPMailDefined('smtp', 'user', Arr::get($smtp, 'user'));
$password = $this->maybeFromWPMailDefined('smtp', 'pass', '');
if ($auth == 'yes') {
if (!$password) {
$password = $this->wpMailPassDecode(Arr::get($smtp, 'pass'));
}
}
$localSettings = [
'host' => $this->maybeFromWPMailDefined('smtp', 'host', Arr::get($smtp, 'host')),
'port' => $this->maybeFromWPMailDefined('smtp', 'port', Arr::get($smtp, 'port')),
'auth' => $auth,
'username' => $userName,
'password' => $password,
'auto_tls' => $this->maybeFromWPMailDefined('smtp', 'auto_tls', Arr::get($smtp, 'auto_tls')) == 1 ? 'yes' : 'no',
'encryption' => $this->maybeFromWPMailDefined('smtp', 'encryption', Arr::get($smtp, 'encryption', 'none')),
'key_store' => 'db',
'provider' => 'smtp'
];
$commonSettings = wp_parse_args($commonSettings, $localSettings);
} else if ($mailer == 'mailgun') {
$mailgun = Arr::get($wpMailSettings, 'mailgun', []);
$localSettings = [
'api_key' => $this->maybeFromWPMailDefined('mailgun', 'api_key', Arr::get($mailgun, 'api_key')),
'domain_name' => $this->maybeFromWPMailDefined('mailgun', 'domain', Arr::get($mailgun, 'domain')),
'key_store' => 'db',
'region' => strtolower($this->maybeFromWPMailDefined('mailgun', 'region', Arr::get($mailgun, 'region'))),
'provider' => 'mailgun'
];
$commonSettings = wp_parse_args($commonSettings, $localSettings);
unset($commonSettings['force_from_email']);
} else if ($mailer == 'sendinblue' || $mailer == 'sendgrid' || $mailer == 'pepipostapi' || $mailer == 'smtp2go') {
$local = Arr::get($wpMailSettings, $mailer, []);
$localSettings = [
'api_key' => $this->maybeFromWPMailDefined($mailer, 'api_key', Arr::get($local, 'api_key')),
'key_store' => 'db',
'provider' => ($mailer == 'pepipostapi') ? 'pepipost' : $mailer
];
$commonSettings = wp_parse_args($commonSettings, $localSettings);
unset($commonSettings['force_from_email']);
} else if ($mailer == 'amazonses') {
$local = Arr::get($wpMailSettings, $mailer, []);
$localSettings = [
'access_key' => $this->maybeFromWPMailDefined($mailer, 'client_id', Arr::get($local, 'client_id')),
'secret_key' => $this->maybeFromWPMailDefined($mailer, 'client_secret', Arr::get($local, 'client_secret')),
'region' => $this->maybeFromWPMailDefined($mailer, 'region', Arr::get($local, 'region')),
'key_store' => 'db',
'provider' => 'ses'
];
$commonSettings = wp_parse_args($commonSettings, $localSettings);
} else if ($mailer == 'mail') {
$commonSettings['provider'] = 'default';
} else {
return false;
}
return [
'title' => __('Import data from your current plugin (WP Mail SMTP)', 'fluent-smtp'),
'subtitle' => __('We have detected other SMTP plugin\'s settings available on your site. Click bellow to pre-populate the values', 'fluent-smtp'),
'settings' => $commonSettings,
'button_text' => __('Import From WP Mail SMTP', 'fluent-smtp')
];
}
private function wpMailPassDecode($encrypted)
{
if (apply_filters('wp_mail_smtp_helpers_crypto_stop', false)) {
return $encrypted;
}
if (!function_exists('\mb_strlen') || !function_exists('\mb_substr') || !function_exists('\sodium_crypto_secretbox_open')) {
return $encrypted;
}
// Unpack base64 message.
$decoded = base64_decode($encrypted); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
if (false === $decoded) {
return $encrypted;
}
if (mb_strlen($decoded, '8bit') < (SODIUM_CRYPTO_SECRETBOX_NONCEBYTES + SODIUM_CRYPTO_SECRETBOX_MACBYTES)) { // phpcs:ignore
return $encrypted;
}
// Pull nonce and ciphertext out of unpacked message.
$nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit'); // phpcs:ignore
$ciphertext = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit'); // phpcs:ignore
$secret_key = $this->getWPMailSecretKey();
if (empty($secret_key)) {
return $encrypted;
}
// Decrypt it.
$message = sodium_crypto_secretbox_open( // phpcs:ignore
$ciphertext,
$nonce,
$secret_key
);
// Check for decryption failures.
if (false === $message) {
return $encrypted;
}
return $message;
}
private function getWPMailSecretKey()
{
if (defined('WPMS_CRYPTO_KEY')) {
return WPMS_CRYPTO_KEY;
}
$secret_key = get_option('wp_mail_smtp_mail_key');
$secret_key = apply_filters('wp_mail_smtp_helpers_crypto_get_secret_key', $secret_key);
// If we already have the secret, send it back.
if (false !== $secret_key) {
$secret_key = base64_decode($secret_key); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
}
return $secret_key;
}
private function maybeFromWPMailDefined($group, $key, $value)
{
if (!defined('WPMS_ON') || !WPMS_ON) {
return $value;
}
// Just to feel safe.
$group = sanitize_key($group);
$key = sanitize_key($key);
$return = false;
switch ($group) {
case 'mail':
switch ($key) {
case 'from_name':
if (defined('WPMS_MAIL_FROM_NAME') && WPMS_MAIL_FROM_NAME) {
$value = WPMS_MAIL_FROM_NAME;
}
break;
case 'from_email':
if (defined('WPMS_MAIL_FROM') && WPMS_MAIL_FROM) {
$value = WPMS_MAIL_FROM;
}
break;
case 'mailer':
if (defined('WPMS_MAILER') && WPMS_MAILER) {
$value = WPMS_MAILER;
}
break;
case 'return_path':
if (defined('WPMS_SET_RETURN_PATH') && WPMS_SET_RETURN_PATH) {
$value = WPMS_SET_RETURN_PATH;
}
break;
case 'from_name_force':
if (defined('WPMS_MAIL_FROM_NAME_FORCE') && WPMS_MAIL_FROM_NAME_FORCE) {
$value = WPMS_MAIL_FROM_NAME_FORCE;
}
break;
case 'from_email_force':
if (defined('WPMS_MAIL_FROM_FORCE') && WPMS_MAIL_FROM_FORCE) {
$value = WPMS_MAIL_FROM_FORCE;
}
break;
}
break;
case 'smtp':
switch ($key) {
case 'host':
if (defined('WPMS_SMTP_HOST') && WPMS_SMTP_HOST) {
$value = WPMS_SMTP_HOST;
}
break;
case 'port':
if (defined('WPMS_SMTP_PORT') && WPMS_SMTP_PORT) {
$value = WPMS_SMTP_PORT;
}
break;
case 'encryption':
if (defined('WPMS_SSL') && WPMS_SSL) {
$value = WPMS_SSL;
}
break;
case 'auth':
if (defined('WPMS_SMTP_AUTH') && WPMS_SMTP_AUTH) {
$value = WPMS_SMTP_AUTH;
}
break;
case 'autotls':
if (defined('WPMS_SMTP_AUTOTLS') && WPMS_SMTP_AUTOTLS) {
$value = WPMS_SMTP_AUTOTLS;
}
break;
case 'user':
if (defined('WPMS_SMTP_USER') && WPMS_SMTP_USER) {
$value = WPMS_SMTP_USER;
}
break;
case 'pass':
if (defined('WPMS_SMTP_PASS') && WPMS_SMTP_PASS) {
$value = WPMS_SMTP_PASS;
}
break;
}
break;
case 'amazonses':
switch ($key) {
case 'client_id':
if (defined('WPMS_AMAZONSES_CLIENT_ID') && WPMS_AMAZONSES_CLIENT_ID) {
$value = WPMS_AMAZONSES_CLIENT_ID;
}
break;
case 'client_secret':
if (defined('WPMS_AMAZONSES_CLIENT_SECRET') && WPMS_AMAZONSES_CLIENT_SECRET) {
$value = WPMS_AMAZONSES_CLIENT_SECRET;
}
break;
case 'region':
if (defined('WPMS_AMAZONSES_REGION') && WPMS_AMAZONSES_REGION) {
$value = WPMS_AMAZONSES_REGION;
}
break;
}
break;
case 'mailgun':
switch ($key) {
case 'api_key':
if (defined('WPMS_MAILGUN_API_KEY') && WPMS_MAILGUN_API_KEY) {
$value = WPMS_MAILGUN_API_KEY;
}
break;
case 'domain':
if (defined('WPMS_MAILGUN_DOMAIN') && WPMS_MAILGUN_DOMAIN) {
$value = WPMS_MAILGUN_DOMAIN;
}
break;
case 'region':
if (defined('WPMS_MAILGUN_REGION') && WPMS_MAILGUN_REGION) {
$value = WPMS_MAILGUN_REGION;
}
break;
}
break;
case 'sendgrid':
switch ($key) {
case 'api_key':
if (defined('WPMS_SENDGRID_API_KEY') && WPMS_SENDGRID_API_KEY) {
$value = WPMS_SENDGRID_API_KEY;
}
break;
case 'domain':
if (defined('WPMS_SENDGRID_DOMAIN') && WPMS_SENDGRID_DOMAIN) {
$value = WPMS_SENDGRID_DOMAIN;
}
break;
}
break;
case 'sendinblue':
switch ($key) {
case 'api_key':
if (defined('WPMS_SENDINBLUE_API_KEY') && WPMS_SENDINBLUE_API_KEY) {
$value = WPMS_SENDINBLUE_API_KEY;
}
break;
case 'domain':
if (defined('WPMS_SENDINBLUE_DOMAIN') && WPMS_SENDINBLUE_DOMAIN) {
$value = WPMS_SENDINBLUE_DOMAIN;
}
break;
}
break;
case 'pepipostapi':
switch ($key) {
case 'api_key':
if (defined('WPMS_PEPIPOST_API_KEY') && WPMS_PEPIPOST_API_KEY) {
$value = WPMS_PEPIPOST_API_KEY;
}
break;
}
break;
case 'elasticmail':
switch ($key) {
case 'api_key':
if (defined('FLUENTMAIL_ELASTICMAIL_API_KEY') && FLUENTMAIL_ELASTICMAIL_API_KEY) {
$value = FLUENTMAIL_ELASTICMAIL_API_KEY;
}
break;
}
break;
}
return $value;
}
/*
* For EasySMTP
*/
private function maybeEasySmtp()
{
$settings = get_option('swpsmtp_options');
if (!$settings || !is_array($settings)) {
return false;
}
$auth = 'no';
if (Arr::get($settings, 'smtp_settings.autentication')) {
$auth = 'yes';
}
$commonSettings = [
'sender_name' => Arr::get($settings, 'from_name_field'),
'sender_email' => Arr::get($settings, 'from_email_field'),
'force_from_name' => Arr::get($settings, 'force_from_name_replace') == 1 ? 'yes' : 'no',
'force_from_email' => 'yes',
'return_path' => 'yes',
'host' => Arr::get($settings, 'smtp_settings.host'),
'port' => Arr::get($settings, 'smtp_settings.port'),
'auth' => $auth,
'username' => Arr::get($settings, 'smtp_settings.username'),
'password' => $this->decryptEasySMTPPass(Arr::get($settings, 'smtp_settings.password')),
'auto_tls' => Arr::get($settings, 'smtp_settings.password') == 1 ? 'yes' : 'no',
'encryption' => Arr::get($settings, 'smtp_settings.type_encryption'),
'key_store' => 'db',
'provider' => 'smtp'
];
return [
'title' => __('Import data from your current plugin (Easy WP SMTP)', 'fluent-smtp'),
'subtitle' => __('We have detected other SMTP plugin\'s settings available on your site. Click bellow to pre-populate the values', 'fluent-smtp'),
'driver' => 'smtp',
'settings' => $commonSettings,
'button_text' => __('Import From Easy WP SMTP', 'fluent-smtp')
];
}
private function decryptEasySMTPPass($temp_password)
{
if (!$temp_password) {
return $temp_password;
}
try {
if (get_option('swpsmtp_pass_encrypted')) {
$key = get_option('swpsmtp_enc_key', false);
if (empty($key)) {
$key = wp_salt();
}
return $this->decryptEasypassword($temp_password, $key);
}
} catch (\Exception $e) {
return $temp_password;
}
$password = '';
$decoded_pass = base64_decode($temp_password); //phpcs:ignore
/* no additional checks for servers that aren't configured with mbstring enabled */
if (!function_exists('mb_detect_encoding')) {
return $decoded_pass;
}
/* end of mbstring check */
if (base64_encode($decoded_pass) === $temp_password) { //phpcs:ignore
//it might be encoded
if (false === mb_detect_encoding($decoded_pass)) { //could not find character encoding.
$password = $temp_password;
} else {
$password = base64_decode($temp_password); //phpcs:ignore
}
} else { //not encoded
$password = $temp_password;
}
return stripslashes($password);
}
private function decryptEasyPassword($in, $key, $fmt = 1)
{
if (!function_exists('\openssl_cipher_iv_length') || !function_exists('\openssl_decrypt') || !function_exists('\openssl_digest')) {
return $in;
}
$raw = base64_decode($in);
$iv_num_bytes = openssl_cipher_iv_length('aes-256-ctr');
// and do an integrity check on the size.
if (strlen($raw) < $iv_num_bytes) {
return $in;
}
// Extract the initialisation vector and encrypted data
$iv = substr($raw, 0, $iv_num_bytes);
$raw = substr($raw, $iv_num_bytes);
$hasAlgo = 'sha256';
// Hash the key
$keyhash = openssl_digest($key, $hasAlgo, true);
// and decrypt.
$opts = 1;
$res = openssl_decrypt($raw, 'aes-256-ctr', $keyhash, $opts, $iv);
if ($res === false) {
return $in;
}
return $res;
}
}

View File

@@ -0,0 +1,43 @@
<?php namespace FluentMail\App\Services\DB;
use FluentMail\App\Services\DB\QueryBuilder\QueryBuilderHandler;
/**
* This class gives the ability to access non-static methods statically
*
* Class AliasFacade
*
* @package FluentAuthDb
*/
class AliasFacade
{
/**
* @var QueryBuilderHandler
*/
protected static $queryBuilderInstance;
/**
* @param $method
* @param $args
*
* @return mixed
*/
public static function __callStatic($method, $args)
{
if (!static::$queryBuilderInstance) {
static::$queryBuilderInstance = new QueryBuilderHandler();
}
// Call the non-static method from the class instance
return call_user_func_array(array(static::$queryBuilderInstance, $method), $args);
}
/**
* @param QueryBuilderHandler $queryBuilderInstance
*/
public static function setQueryBuilderInstance($queryBuilderInstance)
{
static::$queryBuilderInstance = $queryBuilderInstance;
}
}

View File

@@ -0,0 +1,187 @@
<?php
namespace FluentMail\App\Services\DB;
use FluentMail\App\Services\DB\Viocon\Container;
class Connection
{
/**
* @var Container
*/
protected $container;
/**
* @var string
*/
protected $adapter;
/**
* @var array
*/
protected $adapterConfig;
/**
* @var \wpdb $wpdb
*/
protected $dbInstance;
/**
* @var \wpdb $wpdb
*/
protected $wpdb;
/**
* @var Connection
*/
protected static $storedConnection;
/**
* @var EventHandler
*/
protected $eventHandler;
/**
* @param $wpdb
* @param array $adapterConfig
* @param null|string $alias
* @param null|Container $container
*/
public function __construct($wpdb, array $config = array(), $alias = null, ?Container $container = null)
{
$container = $container ? : new Container();
$this->container = $container;
$this->wpdb = $wpdb;
$this->setAdapter()->setAdapterConfig($config)->connect();
// Create event dependency
$this->eventHandler = $this->container->build('\\FluentMail\\App\\Services\\DB\\EventHandler');
if ($alias) {
$this->createAlias($alias);
}
}
/**
* Create an easily accessible query builder alias
*
* @param $alias
*/
public function createAlias($alias)
{
class_alias('FluentMail\\App\\Services\\DB\\AliasFacade', $alias);
$builder = $this->container->build('\\FluentMail\\App\\Services\\DB\\QueryBuilder\\QueryBuilderHandler', array($this));
AliasFacade::setQueryBuilderInstance($builder);
}
/**
* Returns an instance of Query Builder
*/
public function getQueryBuilder()
{
return $this->container->build('\\FluentMail\\App\\Services\\DB\\QueryBuilder\\QueryBuilderHandler', array($this));
}
/**
* Create the connection adapter
*/
protected function connect()
{
$this->setDbInstance($this->wpdb);
// Preserve the first database connection with a static property
if (! static::$storedConnection) {
static::$storedConnection = $this;
}
}
/**
* @param $db
*
* @return $this
*/
public function setDbInstance($db)
{
$this->dbInstance = $db;
return $this;
}
/**
* @return \wpdb
*/
public function getDbInstance()
{
return $this->dbInstance;
}
/**
* @param $adapter
*
* @return $this
*/
public function setAdapter($adapter = 'mysql')
{
$this->adapter = $adapter;
return $this;
}
/**
* @return string
*/
public function getAdapter()
{
return $this->adapter;
}
/**
* @param array $adapterConfig
*
* @return $this
*/
public function setAdapterConfig(array $adapterConfig)
{
$this->adapterConfig = $adapterConfig;
return $this;
}
/**
* @return array
*/
public function getAdapterConfig()
{
return $this->adapterConfig;
}
/**
* @return \FluentMail\App\Services\DB\Viocon\Container
*/
public function getContainer()
{
return $this->container;
}
/**
* @return EventHandler
*/
public function getEventHandler()
{
return $this->eventHandler;
}
/**
* @return Connection
*/
public static function getStoredConnection()
{
return static::$storedConnection;
}
}

View File

@@ -0,0 +1,99 @@
<?php namespace FluentMail\App\Services\DB;
use FluentMail\App\Services\DB\QueryBuilder\QueryBuilderHandler;
use FluentMail\App\Services\DB\QueryBuilder\Raw;
class EventHandler
{
/**
* @var array
*/
protected $events = array();
/**
* @var array
*/
protected $firedEvents = array();
/**
* @return array
*/
public function getEvents()
{
return $this->events;
}
/**
* @param $event
* @param $table
*
* @return callable|null
*/
public function getEvent($event, $table = ':any')
{
if ($table instanceof Raw) {
return null;
}
return isset($this->events[$table][$event]) ? $this->events[$table][$event] : null;
}
/**
* @param $event
* @param string $table
* @param callable $action
*
* @return void
*/
public function registerEvent($event, $table, \Closure $action)
{
$table = $table ?: ':any';
$this->events[$table][$event] = $action;
}
/**
* @param $event
* @param string $table
*
* @return void
*/
public function removeEvent($event, $table = ':any')
{
unset($this->events[$table][$event]);
}
/**
* @param \FluentMail\App\Services\DB\src\QueryBuilder\QueryBuilderHandler $queryBuilder
* @param $event
* @return mixed
*/
public function fireEvents($queryBuilder, $event)
{
$originalArgs = func_get_args();
$statements = $queryBuilder->getStatements();
$tables = isset($statements['tables']) ? $statements['tables'] : array();
// Events added with :any will be fired in case of any table,
// we are adding :any as a fake table at the beginning.
array_unshift($tables, ':any');
// Fire all events
foreach ($tables as $table) {
// Fire before events for :any table
if ($action = $this->getEvent($event, $table)) {
// Make an event id, with event type and table
$eventId = $event . $table;
// Fire event
$handlerParams = $originalArgs;
unset($handlerParams[1]); // we do not need $event
// Add to fired list
$this->firedEvents[] = $eventId;
$result = call_user_func_array($action, $handlerParams);
if (!is_null($result)) {
return $result;
};
}
}
}
}

View File

@@ -0,0 +1,6 @@
<?php namespace FluentMail\App\Services\DB;
class Exception extends \Exception
{
}

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Muhammad Usman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,545 @@
<?php namespace FluentMail\App\Services\DB\QueryBuilder\Adapters;
use FluentMail\App\Services\DB\Connection;
use FluentMail\App\Services\DB\Exception;
use FluentMail\App\Services\DB\QueryBuilder\Raw;
abstract class BaseAdapter
{
/**
* @var \FluentMail\App\Services\DB\Connection
*/
protected $connection;
/**
* @var \FluentMail\App\Services\DB\Viocon\Container
*/
protected $container;
public function __construct(Connection $connection)
{
$this->connection = $connection;
$this->container = $this->connection->getContainer();
}
/**
* Build select query string and bindings
*
* @param $statements
*
* @return array
* @throws \FluentMail\App\Services\DB\Exception
*/
public function select($statements)
{
if (! array_key_exists('tables', $statements)) {
throw new Exception('No table specified.', 3);
} elseif (! array_key_exists('selects', $statements)) {
$statements['selects'][] = '*';
}
// From
$tables = $this->arrayStr($statements['tables'], ', ');
// Select
$selects = $this->arrayStr($statements['selects'], ', ');
// Wheres
list($whereCriteria, $whereBindings) = $this->buildCriteriaWithType($statements, 'wheres', 'WHERE');
// Group bys
$groupBys = '';
if (isset($statements['groupBys']) && $groupBys = $this->arrayStr($statements['groupBys'], ', ')) {
$groupBys = 'GROUP BY ' . $groupBys;
}
// Order bys
$orderBys = '';
if (isset($statements['orderBys']) && is_array($statements['orderBys'])) {
foreach ($statements['orderBys'] as $orderBy) {
$orderBys .= $this->wrapSanitizer($orderBy['field']) . ' ' . $orderBy['type'] . ', ';
}
if ($orderBys = trim($orderBys, ', ')) {
$orderBys = 'ORDER BY ' . $orderBys;
}
}
// Limit and offset
$limit = isset($statements['limit']) ? 'LIMIT ' . $statements['limit'] : '';
$offset = isset($statements['offset']) ? 'OFFSET ' . $statements['offset'] : '';
// Having
list($havingCriteria, $havingBindings) = $this->buildCriteriaWithType($statements, 'havings', 'HAVING');
// Joins
$joinString = $this->buildJoin($statements);
$sqlArray = array(
'SELECT' . (isset($statements['distinct']) ? ' DISTINCT' : ''),
$selects,
'FROM',
$tables,
$joinString,
$whereCriteria,
$groupBys,
$havingCriteria,
$orderBys,
$limit,
$offset
);
$sql = $this->concatenateQuery($sqlArray);
$bindings = array_merge(
$whereBindings,
$havingBindings
);
return compact('sql', 'bindings');
}
/**
* Build just criteria part of the query
*
* @param $statements
* @param bool $bindValues
*
* @return array
*/
public function criteriaOnly($statements, $bindValues = true)
{
$sql = $bindings = array();
if (! isset($statements['criteria'])) {
return compact('sql', 'bindings');
}
list($sql, $bindings) = $this->buildCriteria($statements['criteria'], $bindValues);
return compact('sql', 'bindings');
}
/**
* Build a generic insert/ignore/replace query
*
* @param $statements
* @param array $data
*
* @return array
* @throws \FluentMail\App\Services\DB\Exception
*/
private function doInsert($statements, array $data, $type)
{
if (! isset($statements['tables'])) {
throw new Exception('No table specified', 3);
}
$table = end($statements['tables']);
$bindings = $keys = $values = array();
foreach ($data as $key => $value) {
$keys[] = $key;
if ($value instanceof Raw) {
$values[] = (string) $value;
} else {
$values[] = '?';
$bindings[] = $value;
}
}
$sqlArray = array(
$type . ' INTO',
$this->wrapSanitizer($table),
'(' . $this->arrayStr($keys, ',') . ')',
'VALUES',
'(' . $this->arrayStr($values, ',', false) . ')',
);
if (isset($statements['onduplicate'])) {
if (count($statements['onduplicate']) < 1) {
throw new Exception('No data given.', 4);
}
list($updateStatement, $updateBindings) = $this->getUpdateStatement($statements['onduplicate']);
$sqlArray[] = 'ON DUPLICATE KEY UPDATE ' . $updateStatement;
$bindings = array_merge($bindings, $updateBindings);
}
$sql = $this->concatenateQuery($sqlArray);
return compact('sql', 'bindings');
}
/**
* Build Insert query
*
* @param $statements
* @param array $data
*
* @return array
* @throws \FluentMail\App\Services\DB\Exception
*/
public function insert($statements, array $data)
{
return $this->doInsert($statements, $data, 'INSERT');
}
/**
* Build Insert Ignore query
*
* @param $statements
* @param array $data
*
* @return array
* @throws \FluentMail\App\Services\DB\Exception
*/
public function insertIgnore($statements, array $data)
{
return $this->doInsert($statements, $data, 'INSERT IGNORE');
}
/**
* Build Insert Ignore query
*
* @param $statements
* @param array $data
*
* @return array
* @throws \FluentMail\App\Services\DB\Exception
*/
public function replace($statements, array $data)
{
return $this->doInsert($statements, $data, 'REPLACE');
}
/**
* Build fields assignment part of SET ... or ON DUBLICATE KEY UPDATE ... statements
*
* @param array $data
*
* @return array
*/
private function getUpdateStatement($data)
{
$bindings = array();
$statement = '';
foreach ($data as $key => $value) {
if ($value instanceof Raw) {
$statement .= $this->wrapSanitizer($key) . '=' . $value . ',';
} else {
$statement .= $this->wrapSanitizer($key) . '=?,';
$bindings[] = $value;
}
}
$statement = trim($statement, ',');
return array($statement, $bindings);
}
/**
* Build update query
*
* @param $statements
* @param array $data
*
* @return array
* @throws \FluentMail\App\Services\DB\Exception
*/
public function update($statements, array $data)
{
if (! isset($statements['tables'])) {
throw new Exception('No table specified', 3);
} elseif (count($data) < 1) {
throw new Exception('No data given.', 4);
}
$table = end($statements['tables']);
// Update statement
list($updateStatement, $bindings) = $this->getUpdateStatement($data);
// Wheres
list($whereCriteria, $whereBindings) = $this->buildCriteriaWithType($statements, 'wheres', 'WHERE');
// Limit
$limit = isset($statements['limit']) ? 'LIMIT ' . $statements['limit'] : '';
$sqlArray = array(
'UPDATE',
$this->wrapSanitizer($table),
'SET ' . $updateStatement,
$whereCriteria,
$limit
);
$sql = $this->concatenateQuery($sqlArray);
$bindings = array_merge($bindings, $whereBindings);
return compact('sql', 'bindings');
}
/**
* Build delete query
*
* @param $statements
*
* @return array
* @throws \FluentMail\App\Services\DB\src\Exception
*/
public function delete($statements)
{
if (! isset($statements['tables'])) {
throw new Exception('No table specified', 3);
}
$table = end($statements['tables']);
// Wheres
list($whereCriteria, $whereBindings) = $this->buildCriteriaWithType($statements, 'wheres', 'WHERE');
// Limit
$limit = isset($statements['limit']) ? 'LIMIT ' . $statements['limit'] : '';
$sqlArray = array('DELETE FROM', $this->wrapSanitizer($table), $whereCriteria);
$sql = $this->concatenateQuery($sqlArray);
$bindings = $whereBindings;
return compact('sql', 'bindings');
}
/**
* Array concatenating method, like implode.
* But it does wrap sanitizer and trims last glue
*
* @param array $pieces
* @param $glue
* @param bool $wrapSanitizer
*
* @return string
*/
protected function arrayStr(array $pieces, $glue, $wrapSanitizer = true)
{
$str = '';
foreach ($pieces as $key => $piece) {
if ($wrapSanitizer) {
$piece = $this->wrapSanitizer($piece);
}
if (! is_int($key)) {
$piece = ($wrapSanitizer ? $this->wrapSanitizer($key) : $key) . ' AS ' . $piece;
}
$str .= $piece . $glue;
}
return trim($str, $glue);
}
/**
* Join different part of queries with a space.
*
* @param array $pieces
*
* @return string
*/
protected function concatenateQuery(array $pieces)
{
$str = '';
foreach ($pieces as $piece) {
$str = trim($str) . ' ' . trim($piece);
}
return trim($str);
}
/**
* Build generic criteria string and bindings from statements, like "a = b and c = ?"
*
* @param $statements
* @param bool $bindValues
*
* @return array
*/
protected function buildCriteria($statements, $bindValues = true)
{
$criteria = '';
$bindings = array();
foreach ($statements as $statement) {
$key = $this->wrapSanitizer($statement['key']);
$value = $statement['value'];
if (is_null($value) && $key instanceof \Closure) {
// We have a closure, a nested criteria
// Build a new NestedCriteria class, keep it by reference so any changes made
// in the closure should reflect here
$nestedCriteria = $this->container->build(
'\\FluentMail\\App\\Services\\DB\\QueryBuilder\\NestedCriteria',
array($this->connection)
);
$nestedCriteria = & $nestedCriteria;
// Call the closure with our new nestedCriteria object
$key($nestedCriteria);
// Get the criteria only query from the nestedCriteria object
$queryObject = $nestedCriteria->getQuery('criteriaOnly', true);
// Merge the bindings we get from nestedCriteria object
$bindings = array_merge($bindings, $queryObject->getBindings());
// Append the sql we get from the nestedCriteria object
$criteria .= $statement['joiner'] . ' (' . $queryObject->getSql() . ') ';
} elseif (is_array($value)) {
// where_in or between like query
$criteria .= $statement['joiner'] . ' ' . $key . ' ' . $statement['operator'];
switch ($statement['operator']) {
case 'BETWEEN':
$bindings = array_merge($bindings, $statement['value']);
$criteria .= ' ? AND ? ';
break;
default:
$valuePlaceholder = '';
foreach ($statement['value'] as $subValue) {
$valuePlaceholder .= '?, ';
$bindings[] = $subValue;
}
$valuePlaceholder = trim($valuePlaceholder, ', ');
$criteria .= ' (' . $valuePlaceholder . ') ';
break;
}
} elseif ($value instanceof Raw) {
$criteria .= "{$statement['joiner']} {$key} {$statement['operator']} $value ";
} else {
// Usual where like criteria
if (! $bindValues) {
// Specially for joins
// We are not binding values, lets sanitize then
$value = $this->wrapSanitizer($value);
$criteria .= $statement['joiner'] . ' ' . $key . ' ' . $statement['operator'] . ' ' . $value . ' ';
} elseif ($statement['key'] instanceof Raw) {
$criteria .= $statement['joiner'] . ' ' . $key . ' ';
$bindings = array_merge($bindings, $statement['key']->getBindings());
} else {
// For wheres
$valuePlaceholder = '?';
$bindings[] = $value;
$criteria .= $statement['joiner'] . ' ' . $key . ' ' . $statement['operator'] . ' '
. $valuePlaceholder . ' ';
}
}
}
// Clear all white spaces, and, or from beginning and white spaces from ending
$criteria = preg_replace('/^(\s?AND ?|\s?OR ?)|\s$/i', '', $criteria);
return array($criteria, $bindings);
}
/**
* Wrap values with adapter's sanitizer like, '`'
*
* @param $value
*
* @return string
*/
public function wrapSanitizer($value)
{
// Its a raw query, just cast as string, object has __toString()
if ($value instanceof Raw) {
return (string) $value;
} elseif ($value instanceof \Closure) {
return $value;
}
// Separate our table and fields which are joined with a ".",
// like my_table.id
$valueArr = explode('.', $value, 2);
foreach ($valueArr as $key => $subValue) {
// Don't wrap if we have *, which is not a usual field
$valueArr[$key] = trim($subValue) == '*' ? $subValue : $this->sanitizer . $subValue . $this->sanitizer;
}
// Join these back with "." and return
return implode('.', $valueArr);
}
/**
* Build criteria string and binding with various types added, like WHERE and Having
*
* @param $statements
* @param $key
* @param $type
* @param bool $bindValues
*
* @return array
*/
protected function buildCriteriaWithType($statements, $key, $type, $bindValues = true)
{
$criteria = '';
$bindings = array();
if (isset($statements[$key])) {
// Get the generic/adapter agnostic criteria string from parent
list($criteria, $bindings) = $this->buildCriteria($statements[$key], $bindValues);
if ($criteria) {
$criteria = $type . ' ' . $criteria;
}
}
return array($criteria, $bindings);
}
/**
* Build join string
*
* @param $statements
*
* @return array|string
*/
protected function buildJoin($statements)
{
$sql = '';
if (! array_key_exists('joins', $statements) || ! is_array($statements['joins'])) {
return $sql;
}
foreach ($statements['joins'] as $joinArr) {
if (is_array($joinArr['table'])) {
$mainTable = $joinArr['table'][0];
$aliasTable = $joinArr['table'][1];
$table = $this->wrapSanitizer($mainTable) . ' AS ' . $this->wrapSanitizer($aliasTable);
} else {
$table = $joinArr['table'] instanceof Raw ?
(string) $joinArr['table'] :
$this->wrapSanitizer($joinArr['table']);
}
$joinBuilder = $joinArr['joinBuilder'];
$sqlArr = array(
$sql,
strtoupper($joinArr['type']),
'JOIN',
$table,
'ON',
$joinBuilder->getQuery('criteriaOnly', false)->getSql()
);
$sql = $this->concatenateQuery($sqlArr);
}
return $sql;
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace FluentMail\App\Services\DB\QueryBuilder\Adapters;
class Mysql extends BaseAdapter
{
/**
* @var string
*/
protected $sanitizer = '`';
}

View File

@@ -0,0 +1,45 @@
<?php namespace FluentMail\App\Services\DB\QueryBuilder;
class JoinBuilder extends QueryBuilderHandler
{
/**
* @param $key
* @param $operator
* @param $value
*
* @return $this
*/
public function on($key, $operator, $value)
{
return $this->joinHandler($key, $operator, $value, 'AND');
}
/**
* @param $key
* @param $operator
* @param $value
*
* @return $this
*/
public function orOn($key, $operator, $value)
{
return $this->joinHandler($key, $operator, $value, 'OR');
}
/**
* @param $key
* @param null $operator
* @param null $value
* @param string $joiner
*
* @return $this
*/
protected function joinHandler($key, $operator = null, $value = null, $joiner = 'AND')
{
$key = $this->addTablePrefix($key);
$value = $this->addTablePrefix($value);
$this->statements['criteria'][] = compact('key', 'operator', 'value', 'joiner');
return $this;
}
}

View File

@@ -0,0 +1,20 @@
<?php namespace FluentMail\App\Services\DB\QueryBuilder;
class NestedCriteria extends QueryBuilderHandler
{
/**
* @param $key
* @param null $operator
* @param null $value
* @param string $joiner
*
* @return $this
*/
protected function whereHandler($key, $operator = null, $value = null, $joiner = 'AND')
{
$key = $this->addTablePrefix($key);
$this->statements['criteria'][] = compact('key', 'operator', 'value', 'joiner');
return $this;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,102 @@
<?php
namespace FluentMail\App\Services\DB\QueryBuilder;
class QueryObject
{
/**
* @var string
*/
protected $sql;
/**
* @var \wpdb
*/
protected $db;
/**
* @var array
*/
protected $bindings = array();
public function __construct($sql, array $bindings)
{
$this->sql = (string) $sql;
$this->bindings = $bindings;
global $wpdb;
$this->db = $wpdb;
}
/**
* @return string
*/
public function getSql()
{
return $this->sql;
}
/**
* @return array
*/
public function getBindings()
{
return $this->bindings;
}
/**
* Get the raw/bound sql
*
* @return string
*/
public function getRawSql()
{
return $this->interpolateQuery($this->sql, $this->bindings);
}
/**
* Replaces any parameter placeholders in a query with the value of that
* parameter. Useful for debugging. Assumes anonymous parameters from
* $params are are in the same order as specified in $query
*
* Reference: http://stackoverflow.com/a/1376838/656489
*
* @param string $query The sql query with parameter placeholders
* @param array $params The array of substitution parameters
*
* @return string The interpolated query
*/
protected function interpolateQuery($query, $params)
{
$keys = $placeHolders = [];
foreach ($params as $key => $value) {
if (is_string($key)) {
$keys[] = '/:' . $key . '/';
} else {
$keys[] = '/[?]/';
}
$placeHolders[] = $this->getPlaceHolder($value);
}
$query = preg_replace($keys, $placeHolders, $query, 1, $count);
return $params ? $this->db->prepare($query, $params) : $query;
}
private function getPlaceHolder($value)
{
$placeHolder = '%s';
if (is_int($value)) {
$placeHolder = '%d';
} elseif (is_float($value)) {
$placeHolder = '%f';
}
return $placeHolder;
}
}

View File

@@ -0,0 +1,34 @@
<?php namespace FluentMail\App\Services\DB\QueryBuilder;
class Raw
{
/**
* @var string
*/
protected $value;
/**
* @var array
*/
protected $bindings;
public function __construct($value, $bindings = array())
{
$this->value = (string)$value;
$this->bindings = (array)$bindings;
}
public function getBindings()
{
return $this->bindings;
}
/**
* @return string
*/
public function __toString()
{
return (string) $this->value;
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace FluentMail\App\Services\DB\QueryBuilder;
class Transaction extends QueryBuilderHandler
{
/**
* Commit the database changes
*/
public function commit()
{
$this->db->query('COMMIT');
throw new TransactionHaltException();
}
/**
* Rollback the database changes
*/
public function rollback()
{
$this->db->query('ROLLBACK');
throw new TransactionHaltException();
}
}

View File

@@ -0,0 +1,7 @@
<?php
namespace FluentMail\App\Services\DB\QueryBuilder;
class TransactionHaltException extends \Exception
{
}

View File

@@ -0,0 +1,48 @@
<?php
namespace FluentMail\App\Services\DB\Viocon;
/**
* This class gives the ability to access non-static methods statically
*
* Class AliasFacade
*
* @package Viocon
*/
class AliasFacade {
/**
* @var Container
*/
protected static $vioconInstance;
/**
* @param $method
* @param $args
*
* @return mixed
*/
public static function __callStatic($method, $args)
{
if(!static::$vioconInstance) {
static::$vioconInstance = new Container();
}
return call_user_func_array(array(static::$vioconInstance, $method), $args);
}
/**
* @param Container $instance
*/
public static function setVioconInstance(Container $instance)
{
static::$vioconInstance = $instance;
}
/**
* @return \FluentMail\App\Services\DB\Viocon\Container $instance
*/
public static function getVioconInstance()
{
return static::$vioconInstance;
}
}

View File

@@ -0,0 +1,140 @@
<?php namespace FluentMail\App\Services\DB\Viocon;
class Container
{
/**
* @var array
*/
public $registry = array();
/**
* Singleton instances
*
* @var array
*/
public $singletons = array();
public function __construct($alias = null)
{
if ($alias) {
AliasFacade::setVioconInstance($this);
class_alias('\\FluentMail\\App\\Services\\DB\\Viocon\\AliasFacade', $alias);
}
}
/**
* Register an object with a key
*
* @param string $key
* @param mixed $object
* @param bool $singleton
*
* @return void
*/
public function set($key, $object, $singleton = false)
{
$this->registry[$key] = compact('object', 'singleton');
}
/**
* If we have a registry for the given key
*
* @param string $key
*
* @return bool
*/
public function has($key)
{
return array_key_exists($key, $this->registry);
}
/**
* Register as singleton.
*
* @param string $key
* @param mixed $object
*
* @return void
*/
public function singleton($key, $object)
{
$this->set($key, $object, true);
}
/**
* Register or replace an instance as a singleton.
* Useful for replacing with Mocked instance
*
* @param string $key
* @param mixed $instance
*
* @return void
*/
public function setInstance($key, $instance)
{
$this->singletons[$key] = $instance;
}
/**
* Build from the given key.
* If there is a class registered with Container::set() then it's instance
* will be returned. If a closure is registered, a closure's return value
* will be returned. If nothing is registered then it will try to build an
* instance with new $key(...).
*
* $parameters will be passed to closure or class constructor.
*
*
* @param string $key
* @param array $parameters
*
* @return mixed
*/
public function build($key, $parameters = array())
{
// If we have a singleton instance registered the just return it
if (array_key_exists($key, $this->singletons)) {
return $this->singletons[$key];
}
// If we don't have a registered object with the key then assume user
// is trying to build a class with the given key/name
if (!array_key_exists($key, $this->registry)) {
$object = $key;
} else {
$object = $this->registry[$key]['object'];
}
$instance = $this->instanciate($object, $parameters);
// If the key is registered as a singleton, we can save the instance as singleton
// for later use
if (isset($this->registry[$key]['singleton']) && $this->registry[$key]['singleton'] === true) {
$this->singletons[$key] = $instance;
}
return $instance;
}
/**
* Instantiate an instance of the given type.
*
* @param string $key
* @param array $parameters
*
* @throws \Exception
* @return mixed
*/
protected function instanciate($key, $parameters = null)
{
if ($key instanceof \Closure) {
return call_user_func_array($key, $parameters);
}
$reflection = new \ReflectionClass($key);
return $reflection->newInstanceArgs($parameters);
}
}

View File

@@ -0,0 +1,7 @@
<?php namespace FluentMail\App\Services\DB\Viocon;
class VioconException extends \Exception
{
}

View File

@@ -0,0 +1,22 @@
<?php defined('ABSPATH') or die;
if (! function_exists('FluentSmtpDb')) {
/**
* @return \FluentMail\App\Services\DB\QueryBuilder\QueryBuilderHandler
*/
function FluentSmtpDb()
{
static $FluentSmtpDb;
if (! $FluentSmtpDb) {
global $wpdb;
$connection = new \FluentMail\App\Services\DB\Connection($wpdb, ['prefix' => $wpdb->prefix]);
$FluentSmtpDb = new \FluentMail\App\Services\DB\QueryBuilder\QueryBuilderHandler($connection);
}
return $FluentSmtpDb;
}
}

View File

@@ -0,0 +1,662 @@
<?php
/*
* Copyright (c) 2005-2007 Jon Abernathy <jon@chuggnutt.com>
*
* This script is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
namespace FluentMail\App\Services;
class Html2Text
{
const ENCODING = 'UTF-8';
protected $htmlFuncFlags;
/**
* Contains the HTML content to convert.
*
* @var string $html
*/
protected $html;
/**
* Contains the converted, formatted text.
*
* @var string $text
*/
protected $text;
/**
* List of preg* regular expression patterns to search for,
* used in conjunction with $replace.
*
* @var array $search
* @see $replace
*/
protected $search = array(
"/\r/", // Non-legal carriage return
"/[\n\t]+/", // Newlines and tabs
'/<head\b[^>]*>.*?<\/head>/i', // <head>
'/<script\b[^>]*>.*?<\/script>/i', // <script>s -- which strip_tags supposedly has problems with
'/<style\b[^>]*>.*?<\/style>/i', // <style>s -- which strip_tags supposedly has problems with
'/<i\b[^>]*>(.*?)<\/i>/i', // <i>
'/<em\b[^>]*>(.*?)<\/em>/i', // <em>
'/<ins\b[^>]*>(.*?)<\/ins>/i', // <ins>
'/(<ul\b[^>]*>|<\/ul>)/i', // <ul> and </ul>
'/(<ol\b[^>]*>|<\/ol>)/i', // <ol> and </ol>
'/(<dl\b[^>]*>|<\/dl>)/i', // <dl> and </dl>
'/<li\b[^>]*>(.*?)<\/li>/i', // <li> and </li>
'/<dd\b[^>]*>(.*?)<\/dd>/i', // <dd> and </dd>
'/<dt\b[^>]*>(.*?)<\/dt>/i', // <dt> and </dt>
'/<li\b[^>]*>/i', // <li>
'/<hr\b[^>]*>/i', // <hr>
'/<div\b[^>]*>/i', // <div>
'/(<table\b[^>]*>|<\/table>)/i', // <table> and </table>
'/(<tr\b[^>]*>|<\/tr>)/i', // <tr> and </tr>
'/<td\b[^>]*>(.*?)<\/td>/i', // <td> and </td>
'/<span class="_html2text_ignore">.+?<\/span>/i', // <span class="_html2text_ignore">...</span>
'/<(img)\b[^>]*alt=\"([^>"]+)\"[^>]*>/i', // <img> with alt tag
);
/**
* List of pattern replacements corresponding to patterns searched.
*
* @var array $replace
* @see $search
*/
protected $replace = array(
'', // Non-legal carriage return
' ', // Newlines and tabs
'', // <head>
'', // <script>s -- which strip_tags supposedly has problems with
'', // <style>s -- which strip_tags supposedly has problems with
'_\\1_', // <i>
'_\\1_', // <em>
'_\\1_', // <ins>
"\n\n", // <ul> and </ul>
"\n\n", // <ol> and </ol>
"\n\n", // <dl> and </dl>
"\t* \\1\n", // <li> and </li>
" \\1\n", // <dd> and </dd>
"\t* \\1", // <dt> and </dt>
"\n\t* ", // <li>
"\n-------------------------\n", // <hr>
"<div>\n", // <div>
"\n\n", // <table> and </table>
"\n", // <tr> and </tr>
"\t\t\\1\n", // <td> and </td>
"", // <span class="_html2text_ignore">...</span>
'[\\2]', // <img> with alt tag
);
/**
* List of preg* regular expression patterns to search for,
* used in conjunction with $entReplace.
*
* @var array $entSearch
* @see $entReplace
*/
protected $entSearch = array(
'/&#153;/i', // TM symbol in win-1252
'/&#151;/i', // m-dash in win-1252
'/&(amp|#38);/i', // Ampersand: see converter()
'/[ ]{2,}/', // Runs of spaces, post-handling
'/&#39;/i', // The apostrophe symbol
);
/**
* List of pattern replacements corresponding to patterns searched.
*
* @var array $entReplace
* @see $entSearch
*/
protected $entReplace = array(
'™', // TM symbol
'—', // m-dash
'|+|amp|+|', // Ampersand: see converter()
' ', // Runs of spaces, post-handling
'\'', // Apostrophe
);
/**
* List of preg* regular expression patterns to search for
* and replace using callback function.
*
* @var array $callbackSearch
*/
protected $callbackSearch = array(
'/<(h)[123456]( [^>]*)?>(.*?)<\/h[123456]>/i', // h1 - h6
'/[ ]*<(p)( [^>]*)?>(.*?)<\/p>[ ]*/si', // <p> with surrounding whitespace.
'/<(br)[^>]*>[ ]*/i', // <br> with leading whitespace after the newline.
'/<(b)( [^>]*)?>(.*?)<\/b>/i', // <b>
'/<(strong)( [^>]*)?>(.*?)<\/strong>/i', // <strong>
'/<(del)( [^>]*)?>(.*?)<\/del>/i', // <del>
'/<(th)( [^>]*)?>(.*?)<\/th>/i', // <th> and </th>
'/<(a) [^>]*href=("|\')([^"\']+)\2([^>]*)>(.*?)<\/a>/i' // <a href="">
);
/**
* List of preg* regular expression patterns to search for in PRE body,
* used in conjunction with $preReplace.
*
* @var array $preSearch
* @see $preReplace
*/
protected $preSearch = array(
"/\n/",
"/\t/",
'/ /',
'/<pre[^>]*>/',
'/<\/pre>/'
);
/**
* List of pattern replacements corresponding to patterns searched for PRE body.
*
* @var array $preReplace
* @see $preSearch
*/
protected $preReplace = array(
'<br>',
'&nbsp;&nbsp;&nbsp;&nbsp;',
'&nbsp;',
'',
'',
);
/**
* Temporary workspace used during PRE processing.
*
* @var string $preContent
*/
protected $preContent = '';
/**
* Contains the base URL that relative links should resolve to.
*
* @var string $baseurl
*/
protected $baseurl = '';
/**
* Indicates whether content in the $html variable has been converted yet.
*
* @var boolean $converted
* @see $html, $text
*/
protected $converted = false;
/**
* Contains URL addresses from links to be rendered in plain text.
*
* @var array $linkList
* @see buildlinkList()
*/
protected $linkList = array();
/**
* Various configuration options (able to be set in the constructor)
*
* @var array $options
*/
protected $options = array(
'do_links' => 'inline', // 'none'
// 'inline' (show links inline)
// 'nextline' (show links on the next line)
// 'table' (if a table of link URLs should be listed after the text.
// 'bbcode' (show links as bbcode)
'width' => 70, // Maximum width of the formatted text, in columns.
// Set this value to 0 (or less) to ignore word wrapping
// and not constrain text to a fixed-width column.
);
private function legacyConstruct($html = '', $fromFile = false, array $options = array())
{
$this->set_html($html, $fromFile);
$this->options = array_merge($this->options, $options);
}
/**
* @param string $html Source HTML
* @param array $options Set configuration options
*/
public function __construct($html = '', $options = array())
{
// for backwards compatibility
if (!is_array($options)) {
return call_user_func_array(array($this, 'legacyConstruct'), func_get_args());
}
$this->html = $html;
$this->options = array_merge($this->options, $options);
$this->htmlFuncFlags = (PHP_VERSION_ID < 50400)
? ENT_QUOTES
: ENT_QUOTES | ENT_HTML5;
}
/**
* Get the source HTML
*
* @return string
*/
public function getHtml()
{
return $this->html;
}
/**
* Set the source HTML
*
* @param string $html HTML source content
*/
public function setHtml($html)
{
$this->html = $html;
$this->converted = false;
}
/**
* @deprecated
*/
public function set_html($html, $from_file = false)
{
if ($from_file) {
throw new \InvalidArgumentException("Argument from_file no longer supported");
}
return $this->setHtml($html);
}
/**
* Returns the text, converted from HTML.
*
* @return string Plain text
*/
public function getText()
{
if (!$this->converted) {
$this->convert();
}
return $this->text;
}
/**
* @deprecated
*/
public function get_text()
{
return $this->getText();
}
/**
* @deprecated
*/
public function print_text()
{
print $this->getText(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
/**
* @deprecated
*/
public function p()
{
return $this->print_text();
}
/**
* Sets a base URL to handle relative links.
*
* @param string $baseurl
*/
public function setBaseUrl($baseurl)
{
$this->baseurl = $baseurl;
}
/**
* @deprecated
*/
public function set_base_url($baseurl)
{
return $this->setBaseUrl($baseurl);
}
protected function convert()
{
if (!function_exists('\mb_internal_encoding')) {
return '';
}
$origEncoding = mb_internal_encoding();
mb_internal_encoding(self::ENCODING);
$this->doConvert();
mb_internal_encoding($origEncoding);
}
protected function doConvert()
{
$this->linkList = array();
$text = trim($this->html);
$this->converter($text);
if ($this->linkList) {
$text .= "\n\nLinks:\n------\n";
foreach ($this->linkList as $i => $url) {
$text .= '[' . ($i + 1) . '] ' . $url . "\n";
}
}
$this->text = $text;
$this->converted = true;
}
protected function converter(&$text)
{
$this->convertBlockquotes($text);
$this->convertPre($text);
$text = preg_replace($this->search, $this->replace, $text);
$text = preg_replace_callback($this->callbackSearch, array($this, 'pregCallback'), $text);
$text = strip_tags($text);
$text = preg_replace($this->entSearch, $this->entReplace, $text);
$text = html_entity_decode($text, $this->htmlFuncFlags, self::ENCODING);
// Remove unknown/unhandled entities (this cannot be done in search-and-replace block)
$text = preg_replace('/&([a-zA-Z0-9]{2,6}|#[0-9]{2,4});/', '', $text);
// Convert "|+|amp|+|" into "&", need to be done after handling of unknown entities
// This properly handles situation of "&amp;quot;" in input string
$text = str_replace('|+|amp|+|', '&', $text);
// Normalise empty lines
$text = preg_replace("/\n\s+\n/", "\n\n", $text);
$text = preg_replace("/[\n]{3,}/", "\n\n", $text);
// remove leading empty lines (can be produced by eg. P tag on the beginning)
$text = ltrim($text, "\n");
if ($this->options['width'] > 0) {
$text = wordwrap($text, $this->options['width']);
}
}
/**
* Helper function called by preg_replace() on link replacement.
*
* Maintains an internal list of links to be displayed at the end of the
* text, with numeric indices to the original point in the text they
* appeared. Also makes an effort at identifying and handling absolute
* and relative links.
*
* @param string $link URL of the link
* @param string $display Part of the text to associate number with
* @param null $linkOverride
* @return string
*/
protected function buildlinkList($link, $display, $linkOverride = null)
{
$linkMethod = ($linkOverride) ? $linkOverride : $this->options['do_links'];
if ($linkMethod == 'none') {
return $display;
}
// Ignored link types
if (preg_match('!^(javascript:|mailto:|#)!i', html_entity_decode($link, $this->htmlFuncFlags, self::ENCODING))) {
return $display;
}
if (preg_match('!^([a-z][a-z0-9.+-]+:)!i', $link)) {
$url = $link;
} else {
$url = $this->baseurl;
if (mb_substr($link, 0, 1) != '/') {
$url .= '/';
}
$url .= $link;
}
if ($linkMethod == 'table') {
if (($index = array_search($url, $this->linkList)) === false) {
$index = count($this->linkList);
$this->linkList[] = $url;
}
return $display . ' [' . ($index + 1) . ']';
} elseif ($linkMethod == 'nextline') {
if ($url === $display) {
return $display;
}
return $display . "\n[" . $url . ']';
} elseif ($linkMethod == 'bbcode') {
return sprintf('[url=%s]%s[/url]', $url, $display);
} else { // link_method defaults to inline
if ($url === $display) {
return $display;
}
return $display . ' [' . $url . ']';
}
}
/**
* Helper function for PRE body conversion.
*
* @param string &$text HTML content
*/
protected function convertPre(&$text)
{
// get the content of PRE element
while (preg_match('/<pre[^>]*>(.*)<\/pre>/ismU', $text, $matches)) {
// Replace br tags with newlines to prevent the search-and-replace callback from killing whitespace
$this->preContent = preg_replace('/(<br\b[^>]*>)/i', "\n", $matches[1]);
// Run our defined tags search-and-replace with callback
$this->preContent = preg_replace_callback(
$this->callbackSearch,
array($this, 'pregCallback'),
$this->preContent
);
// convert the content
$this->preContent = sprintf(
'<div><br>%s<br></div>',
preg_replace($this->preSearch, $this->preReplace, $this->preContent)
);
// replace the content (use callback because content can contain $0 variable)
$text = preg_replace_callback(
'/<pre[^>]*>.*<\/pre>/ismU',
array($this, 'pregPreCallback'),
$text,
1
);
// free memory
$this->preContent = '';
}
}
/**
* Helper function for BLOCKQUOTE body conversion.
*
* @param string &$text HTML content
*/
protected function convertBlockquotes(&$text)
{
if (preg_match_all('/<\/*blockquote[^>]*>/i', $text, $matches, PREG_OFFSET_CAPTURE)) {
$originalText = $text;
$start = 0;
$taglen = 0;
$level = 0;
$diff = 0;
foreach ($matches[0] as $m) {
$m[1] = mb_strlen(substr($originalText, 0, $m[1]));
if ($m[0][0] == '<' && $m[0][1] == '/') {
$level--;
if ($level < 0) {
$level = 0; // malformed HTML: go to next blockquote
} elseif ($level > 0) {
// skip inner blockquote
} else {
$end = $m[1];
$len = $end - $taglen - $start;
// Get blockquote content
$body = mb_substr($text, $start + $taglen - $diff, $len);
// Set text width
$pWidth = $this->options['width'];
if ($this->options['width'] > 0) $this->options['width'] -= 2;
// Convert blockquote content
$body = trim($body);
$this->converter($body);
// Add citation markers and create PRE block
$body = preg_replace('/((^|\n)>*)/', '\\1> ', trim($body));
$body = '<pre>' . htmlspecialchars($body, $this->htmlFuncFlags, self::ENCODING) . '</pre>';
// Re-set text width
$this->options['width'] = $pWidth;
// Replace content
$text = mb_substr($text, 0, $start - $diff)
. $body
. mb_substr($text, $end + mb_strlen($m[0]) - $diff);
$diff += $len + $taglen + mb_strlen($m[0]) - mb_strlen($body);
unset($body);
}
} else {
if ($level == 0) {
$start = $m[1];
$taglen = mb_strlen($m[0]);
}
$level++;
}
}
}
}
/**
* Callback function for preg_replace_callback use.
*
* @param array $matches PREG matches
* @return string
*/
protected function pregCallback($matches)
{
switch (mb_strtolower($matches[1])) {
case 'p':
// Replace newlines with spaces.
$para = str_replace("\n", " ", $matches[3]);
// Trim trailing and leading whitespace within the tag.
$para = trim($para);
// Add trailing newlines for this para.
return "\n" . $para . "\n";
case 'br':
return "\n";
case 'b':
case 'strong':
return $this->toupper($matches[3]);
case 'del':
return $this->tostrike($matches[3]);
case 'th':
return $this->toupper("\t\t" . $matches[3] . "\n");
case 'h':
return $this->toupper("\n\n" . $matches[3] . "\n\n");
case 'a':
// override the link method
$linkOverride = null;
if (preg_match('/_html2text_link_(\w+)/', $matches[4], $linkOverrideMatch)) {
$linkOverride = $linkOverrideMatch[1];
}
// Remove spaces in URL (#1487805)
$url = str_replace(' ', '', $matches[3]);
return $this->buildlinkList($url, $matches[5], $linkOverride);
}
return '';
}
/**
* Callback function for preg_replace_callback use in PRE content handler.
*
* @param array $matches PREG matches
* @return string
*/
protected function pregPreCallback(/** @noinspection PhpUnusedParameterInspection */ $matches)
{
return $this->preContent;
}
/**
* Strtoupper function with HTML tags and entities handling.
*
* @param string $str Text to convert
* @return string Converted text
*/
protected function toupper($str)
{
// string can contain HTML tags
$chunks = preg_split('/(<[^>]*>)/', $str, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
// convert toupper only the text between HTML tags
foreach ($chunks as $i => $chunk) {
if ($chunk[0] != '<') {
$chunks[$i] = $this->strtoupper($chunk);
}
}
return implode($chunks);
}
/**
* Strtoupper multibyte wrapper function with HTML entities handling.
*
* @param string $str Text to convert
* @return string Converted text
*/
protected function strtoupper($str)
{
$str = html_entity_decode($str, $this->htmlFuncFlags, self::ENCODING);
$str = mb_strtoupper($str);
$str = htmlspecialchars($str, $this->htmlFuncFlags, self::ENCODING);
return $str;
}
/**
* Helper function for DEL conversion.
*
* @param string $text HTML content
* @return string Converted text
*/
protected function tostrike($str)
{
$rtn = '';
for ($i = 0; $i < mb_strlen($str); $i++) {
$chr = mb_substr($str, $i, 1);
$combiningChr = chr(0xC0 | 0x336 >> 6) . chr(0x80 | 0x336 & 0x3F);
$rtn .= $chr . $combiningChr;
}
return $rtn;
}
}

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

View File

@@ -0,0 +1,425 @@
<?php
namespace FluentMail\App\Services;
use InvalidArgumentException;
use FluentMail\App\Models\Settings;
use FluentMail\Includes\Support\Arr;
class NotificationHelper
{
public static function getRemoteServerUrl()
{
if (defined('FLUENTSMTP_SERVER_REMOTE_SERVER_URL')) {
return FLUENTSMTP_SERVER_REMOTE_SERVER_URL;
}
return 'https://fluentsmtp.com/wp-json/fluentsmtp_notify/v1/';
}
public static function issueTelegramPinCode($data)
{
return self::sendTeleRequest('register-site', $data, 'POST');
}
public static function registerSlackSite($data)
{
return self::sendSlackRequest('register-site', $data, 'POST');
}
public static function getTelegramConnectionInfo($token)
{
return self::sendTeleRequest('get-site-info', [], 'GET', $token);
}
public static function sendTestTelegramMessage($token = '')
{
if (!$token) {
$settings = (new Settings())->notificationSettings();
$token = Arr::get($settings, 'telegram.token');
}
return self::sendTeleRequest('send-test', [], 'POST', $token);
}
public static function disconnectTelegram($token)
{
self::sendTeleRequest('disconnect', [], 'POST', $token);
$settings = (new Settings())->notificationSettings();
$settings['telegram'] = [
'status' => 'no',
'token' => ''
];
$settings['active_channel'] = '';
update_option('_fluent_smtp_notify_settings', $settings, false);
return true;
}
public static function getTelegramBotTokenId()
{
static $token = null;
if ($token !== null) {
return $token;
}
$settings = (new Settings())->notificationSettings();
$token = Arr::get($settings, 'telegram.token', false);
if (!$token) {
$token = false;
}
return $token;
}
public static function getSlackWebhookUrl()
{
static $url = null;
if ($url !== null) {
return $url;
}
$settings = (new Settings())->notificationSettings();
$url = Arr::get($settings, 'slack.webhook_url');
if (!$url) {
$url = false;
}
return $url;
}
public static function sendFailedNotificationTele($data)
{
wp_remote_post(self::getRemoteServerUrl() . 'telegram/send-failed-notification', array(
'timeout' => 0.01,
'blocking' => false,
'body' => $data,
'cookies' => false,
'sslverify' => false,
));
return true;
}
private static function sendTeleRequest($route, $data = [], $method = 'POST', $token = '')
{
$url = self::getRemoteServerUrl() . 'telegram/' . $route;
if ($token) {
$url .= '?site_token=' . $token;
}
if ($method == 'POST') {
$response = wp_remote_post($url, [
'body' => $data,
'sslverify' => false,
'timeout' => 50
]);
} else {
$response = wp_remote_get($url, [
'sslverify' => false,
'timeout' => 50
]);
}
if (is_wp_error($response)) {
return $response;
}
$responseCode = wp_remote_retrieve_response_code($response);
$body = wp_remote_retrieve_body($response);
$responseData = json_decode($body, true);
if (!$responseData || empty($responseData['success']) || $responseCode !== 200) {
return new \WP_Error('invalid_data', 'Something went wrong', $responseData);
}
return $responseData;
}
private static function sendSlackRequest($route, $data = [], $method = 'POST', $token = '')
{
$url = self::getRemoteServerUrl() . 'slack/' . $route;
if ($token) {
$url .= '?site_token=' . $token;
}
if ($method == 'POST') {
$response = wp_remote_post($url, [
'body' => $data,
'sslverify' => false,
'timeout' => 50
]);
} else {
$response = wp_remote_get($url, [
'sslverify' => false,
'timeout' => 50
]);
}
if (is_wp_error($response)) {
return $response;
}
$responseCode = wp_remote_retrieve_response_code($response);
$body = wp_remote_retrieve_body($response);
$responseData = json_decode($body, true);
if (!$responseData || empty($responseData['success']) || $responseCode !== 200) {
return new \WP_Error('invalid_data', 'Something went wrong', $responseData);
}
return $responseData;
}
public static function sendSlackMessage($message, $webhookUrl, $blocking = false)
{
if (is_array($message)) {
$body = wp_json_encode($message);
} else {
$body = wp_json_encode(array('text' => $message));
}
$args = array(
'body' => $body,
'headers' => array(
'Content-Type' => 'application/json',
),
'cookies' => null,
'timeout' => 60,
'redirection' => 5,
'blocking' => true,
'httpversion' => '1.0',
'sslverify' => false,
'data_format' => 'body',
);
if (!$blocking) {
$args['blocking'] = false;
$args['timeout'] = 0.01;
}
$response = wp_remote_post($webhookUrl, $args);
if (!$blocking) {
return true;
}
if (is_wp_error($response)) {
return $response;
}
$body = wp_remote_retrieve_body($response);
return json_decode($body, true);
}
public static function sendDiscordMessage($message, $webhookUrl, $blocking = false)
{
$body = wp_json_encode(array(
'content' => $message,
'username' => 'FluentSMTP'
));
$args = array(
'body' => $body,
'headers' => array(
'Content-Type' => 'application/json',
),
'timeout' => 60,
'redirection' => 5,
'blocking' => true,
'httpversion' => '1.0',
'sslverify' => false,
'data_format' => 'body',
);
if (!$blocking) {
$args['blocking'] = false;
$args['timeout'] = 0.01;
}
$response = wp_remote_post($webhookUrl, $args);
if (!$blocking) {
return true;
}
if (is_wp_error($response)) {
return $response;
}
$body = wp_remote_retrieve_body($response);
return json_decode($body, true);
}
public static function getActiveChannelSettings()
{
static $channel = null;
if ($channel !== null) {
return $channel;
}
$settings = (new Settings())->notificationSettings();
$activeChannel = Arr::get($settings, 'active_channel', '');
if (!$activeChannel) {
$channel = false;
return $channel;
}
$channelSettings = Arr::get($settings, $activeChannel, []);
if (!$channelSettings || empty($channelSettings['status']) || $channelSettings['status'] != 'yes') {
$channel = false;
return $channel;
}
$channel = $channelSettings;
$channel['driver'] = $activeChannel;
return $channel;
}
public static function formatSlackMessageBlock($handler, $logData = [])
{
$sendingTo = self::unserialize(Arr::get($logData, 'to'));
if (is_array($sendingTo)) {
$sendingTo = Arr::get($sendingTo, '0.email', '');
}
if (is_array($sendingTo) || !$sendingTo) {
$sendingTo = Arr::get($logData, 'to');
}
$heading = sprintf(__('[%s] Failed to send email', 'fluent-smtp'), get_bloginfo('name'));
return [
'text' => $heading,
'blocks' => [
[
'type' => 'header',
'text' => [
'type' => 'plain_text',
'text' => $heading,
"emoji" => true
]
],
[
'type' => 'section',
'fields' => [
[
'type' => "mrkdwn",
'text' => "*Website URL:*\n " . site_url()
],
[
'type' => "mrkdwn",
'text' => "*Sending Driver:*\n " . strtoupper($handler->getSetting('provider'))
],
[
'type' => "mrkdwn",
'text' => "*To Email Address:*\n " . $sendingTo
],
[
'type' => "mrkdwn",
'text' => "*Email Subject:*\n " . Arr::get($logData, 'subject')
]
]
],
[
'type' => 'section',
'text' => [
'type' => "mrkdwn",
'text' => "*Error Message:*\n ```" . self::getErrorMessageFromResponse(self::unserialize(Arr::get($logData, 'response'))) . "```"
]
],
[
'type' => 'section',
'text' => [
'type' => "mrkdwn",
'text' => "<" . admin_url('options-general.php?page=fluent-mail#/logs?per_page=10&page=1&status=failed&search=') . "|View Failed Email(s)>"
]
]
]
];
}
public static function formatDiscordMessageBlock($handler, $logData = [])
{
$sendingTo = self::unserialize(Arr::get($logData, 'to'));
if (is_array($sendingTo)) {
$sendingTo = Arr::get($sendingTo, '0.email', '');
}
if (is_array($sendingTo) || !$sendingTo) {
$sendingTo = Arr::get($logData, 'to');
}
$heading = sprintf(__('[%s] Failed to send email', 'fluent-smtp'), get_bloginfo('name'));
$content = '## ' . $heading . "\n";
$content .= __('**Website URL:** ', 'fluent-smtp') . site_url() . "\n";
$content .= __('**Sending Driver:** ', 'fluent-smtp') . strtoupper($handler->getSetting('provider')) . "\n";
$content .= __('**To Email Address:** ', 'fluent-smtp') . $sendingTo . "\n";
$content .= __('**Email Subject:** ', 'fluent-smtp') . Arr::get($logData, 'subject') . "\n";
$content .= __('**Error Message:** ```', 'fluent-smtp') . self::getErrorMessageFromResponse(self::unserialize(Arr::get($logData, 'response'))) . "```\n";
$content .= __('[View Failed Email(s)](', 'fluent-smtp') . admin_url('options-general.php?page=fluent-mail#/logs?per_page=10&page=1&status=failed&search=') . ')';
return $content;
}
public static function getErrorMessageFromResponse($response)
{
if (!$response || !is_array($response)) {
return '';
}
if (!empty($response['fallback_response']['message'])) {
$message = $response['fallback_response']['message'];
} else {
$message = Arr::get($response, 'message');
}
if (!$message) {
return '';
}
if (!is_string($message)) {
$message = json_encode($message);
}
return $message;
}
protected static function unserialize($data)
{
if (is_serialized($data)) {
if (preg_match('/(^|;)O:[0-9]+:/', $data)) {
return '';
}
return unserialize(trim($data), ['allowed_classes' => false]);
}
return $data;
}
}

View File

@@ -0,0 +1,156 @@
<?php
namespace FluentMail\App\Services;
class Reporting
{
protected static $daily = 'P1D';
protected static $weekly = 'P1W';
protected static $monthly = 'P1M';
public function getSendingStats($from, $to)
{
$period = $this->makeDatePeriod(
$from = $this->makeFromDate($from),
$to = $this->makeToDate($to),
$frequency = $this->getFrequency($from, $to)
);
list($groupBy, $orderBy) = $this->getGroupAndOrder($frequency);
global $wpdb;
$tableName = $wpdb->prefix.FLUENT_MAIL_DB_PREFIX.'email_logs';
$items = $wpdb->get_results($wpdb->prepare(
'SELECT COUNT(id) AS count, DATE(created_at) AS date FROM `%1$s` WHERE `created_at` BETWEEN \'%2$s\' AND \'%3$s\' GROUP BY `%4$s` ORDER BY `%5$s` ASC',
$tableName,
$from->format('Y-m-d'),
$to->format('Y-m-d'),
$groupBy,
$orderBy
));
return $this->getResult($period, $items);
}
protected function makeDatePeriod($from, $to, $interval = null)
{
$interval = $interval ?: static::$daily;
return new \DatePeriod($from, new \DateInterval($interval), $to);
}
protected function makeFromDate($from)
{
$from = $from ?: '-7 days';
return new \DateTime($from);
}
protected function makeToDate($to)
{
$to = $to ? gmdate('Y-m-d', strtotime( $to . " +1 days")) : '+1 days';
return new \DateTime($to);
}
protected function getFrequency($from, $to)
{
$numDays = $to->diff($from)->format("%a");
if ($numDays > 62 && $numDays <= 181) {
return static::$weekly;
} else if ($numDays > 181) {
return static::$monthly;
}
return static::$daily;
}
protected function getGroupAndOrder($frequency)
{
$orderBy = $groupBy = 'date';
if ($frequency == static::$weekly) {
$orderBy = $groupBy = 'week';
} else if ($frequency == static::$monthly) {
$orderBy = $groupBy = 'month';
}
return [$groupBy, $orderBy];
}
protected function prepareSelect($frequency, $dateField = 'created_at')
{
$select = [
fluentMailDb()->raw('COUNT(id) AS count'),
fluentMailDb()->raw('DATE('.$dateField.') AS date')
];
if ($frequency == static::$weekly) {
$select[] = fluentMailDb()->raw('WEEK(created_at) week');
} else if ($frequency == static::$monthly) {
$select[] = fluentMailDb()->raw('MONTH(created_at) month');
}
return $select;
}
protected function getResult($period, $items)
{
$range = $this->getDateRangeArray($period);
$formatter = 'basicFormatter';
if ($this->isMonthly($period)) {
$formatter = 'monYearFormatter';
}
foreach ($items as $item) {
$date = $this->{$formatter}($item->date);
$range[$date] = (int) $item->count;
}
return $range;
}
protected function getDateRangeArray($period)
{
$range = [];
$formatter = 'basicFormatter';
if ($this->isMonthly($period)) {
$formatter = 'monYearFormatter';
}
foreach ($period as $date) {
$date = $this->{$formatter}($date);
$range[$date] = 0;
}
return $range;
}
protected function basicFormatter($date)
{
if (is_string($date)) {
$date = new \DateTime($date);
}
return $date->format('Y-m-d');
}
protected function monYearFormatter($date)
{
if (is_string($date)) {
$date = new \DateTime($date);
}
return $date->format('M Y');
}
protected function isMonthly($period)
{
return !!$period->getDateInterval()->m;
}
}

View File

@@ -0,0 +1,361 @@
<?php
namespace FluentMail\App\Services;
//This is a auto-generated file. Please do not modify
class TransStrings
{
public static function getStrings()
{
return [
' - Simulated' => __(' - Simulated', 'fluent-smtp'),
' connection.' => __(' connection.', 'fluent-smtp'),
' in the ' => __(' in the ', 'fluent-smtp'),
' option in the Google Cloud Project.' => __(' option in the Google Cloud Project.', 'fluent-smtp'),
'(Default: US East(N.Virginia) / us - east - 1)' => __('(Default: US East(N.Virginia) / us - east - 1)', 'fluent-smtp'),
'(Optional) Share Non - Sensitive Data.It will help us to improve the integrations' => __('(Optional) Share Non - Sensitive Data.It will help us to improve the integrations', 'fluent-smtp'),
'(Re Authentication Required)' => __('(Re Authentication Required)', 'fluent-smtp'),
'*** It is very important to put ' => __('*** It is very important to put ', 'fluent-smtp'),
'A name for the connection.' => __('A name for the connection.', 'fluent-smtp'),
'API Key' => __('API Key', 'fluent-smtp'),
'About' => __('About', 'fluent-smtp'),
'Access Data: Active SMTP Connection Provider, installed plugin names, php & mysql version' => __('Access Data: Active SMTP Connection Provider, installed plugin names, php & mysql version', 'fluent-smtp'),
'Access Key' => __('Access Key', 'fluent-smtp'),
'Access Keys in Config File' => __('Access Keys in Config File', 'fluent-smtp'),
'Access Token' => __('Access Token', 'fluent-smtp'),
'Actions' => __('Actions', 'fluent-smtp'),
'Activation Pin' => __('Activation Pin', 'fluent-smtp'),
'Active Connections:' => __('Active Connections:', 'fluent-smtp'),
'Active Email Connections' => __('Active Email Connections', 'fluent-smtp'),
'Active Senders:' => __('Active Senders:', 'fluent-smtp'),
'Add' => __('Add', 'fluent-smtp'),
'Add Additional Senders' => __('Add Additional Senders', 'fluent-smtp'),
'Add Another Connection' => __('Add Another Connection', 'fluent-smtp'),
'Add Multi-Part Plain Text for HTML Emails (beta)' => __('Add Multi-Part Plain Text for HTML Emails (beta)', 'fluent-smtp'),
'After 1 Year' => __('After 1 Year', 'fluent-smtp'),
'After 14 Days' => __('After 14 Days', 'fluent-smtp'),
'After 2 Years' => __('After 2 Years', 'fluent-smtp'),
'After 30 Days' => __('After 30 Days', 'fluent-smtp'),
'After 6 Months' => __('After 6 Months', 'fluent-smtp'),
'After 60 Days' => __('After 60 Days', 'fluent-smtp'),
'After 7 Days' => __('After 7 Days', 'fluent-smtp'),
'After 90 Days' => __('After 90 Days', 'fluent-smtp'),
'Alerts' => __('Alerts', 'fluent-smtp'),
'All Statuses' => __('All Statuses', 'fluent-smtp'),
'All Time' => __('All Time', 'fluent-smtp'),
'App Callback URL(Use this URL to your APP)' => __('App Callback URL(Use this URL to your APP)', 'fluent-smtp'),
'Application Client ID' => __('Application Client ID', 'fluent-smtp'),
'Application Client Secret' => __('Application Client Secret', 'fluent-smtp'),
'Application Keys in Config File' => __('Application Keys in Config File', 'fluent-smtp'),
'Apply' => __('Apply', 'fluent-smtp'),
'Are you sure you want to disconnect Discord notifications?' => __('Are you sure you want to disconnect Discord notifications?', 'fluent-smtp'),
'Are you sure you want to disconnect Slack notifications?' => __('Are you sure you want to disconnect Slack notifications?', 'fluent-smtp'),
'Are you sure you want to disconnect Telegram notifications?' => __('Are you sure you want to disconnect Telegram notifications?', 'fluent-smtp'),
'Are you sure you want to remove this email address?' => __('Are you sure you want to remove this email address?', 'fluent-smtp'),
'Are you sure, you want to delete all the logs?' => __('Are you sure, you want to delete all the logs?', 'fluent-smtp'),
'Attachments' => __('Attachments', 'fluent-smtp'),
'Authenticate with Google & Get Access Token' => __('Authenticate with Google & Get Access Token', 'fluent-smtp'),
'Authenticate with Office365 & Get Access Token' => __('Authenticate with Office365 & Get Access Token', 'fluent-smtp'),
'Authentication' => __('Authentication', 'fluent-smtp'),
'Authorized Redirect URI' => __('Authorized Redirect URI', 'fluent-smtp'),
'Authorized Redirect URIs' => __('Authorized Redirect URIs', 'fluent-smtp'),
'Awesome! Please check your email inbox and confirm your subscription.' => __('Awesome! Please check your email inbox and confirm your subscription.', 'fluent-smtp'),
'Best WP DataTables Plugin for WordPress' => __('Best WP DataTables Plugin for WordPress', 'fluent-smtp'),
'Bulk Action' => __('Bulk Action', 'fluent-smtp'),
'By Date' => __('By Date', 'fluent-smtp'),
'Cancel' => __('Cancel', 'fluent-smtp'),
'Close' => __('Close', 'fluent-smtp'),
'Community' => __('Community', 'fluent-smtp'),
'Configure Discord Notification' => __('Configure Discord Notification', 'fluent-smtp'),
'Connect With Your Email Providers' => __('Connect With Your Email Providers', 'fluent-smtp'),
'Connection Details' => __('Connection Details', 'fluent-smtp'),
'Connection Name ' => __('Connection Name ', 'fluent-smtp'),
'Connection Provider' => __('Connection Provider', 'fluent-smtp'),
'Connection deleted Successfully.' => __('Connection deleted Successfully.', 'fluent-smtp'),
'Continue' => __('Continue', 'fluent-smtp'),
'Continue to Slack' => __('Continue to Slack', 'fluent-smtp'),
'Contributors' => __('Contributors', 'fluent-smtp'),
'Create API Key.' => __('Create API Key.', 'fluent-smtp'),
'Cumulative' => __('Cumulative', 'fluent-smtp'),
'Current verified senders:' => __('Current verified senders:', 'fluent-smtp'),
'Date-Time' => __('Date-Time', 'fluent-smtp'),
'Days' => __('Days', 'fluent-smtp'),
'Default Connection' => __('Default Connection', 'fluent-smtp'),
'Delete All Logs' => __('Delete All Logs', 'fluent-smtp'),
'Delete Logs' => __('Delete Logs', 'fluent-smtp'),
'Delete Logs:' => __('Delete Logs:', 'fluent-smtp'),
'Delete Selected' => __('Delete Selected', 'fluent-smtp'),
'Disable Logging for FluentCRM Emails' => __('Disable Logging for FluentCRM Emails', 'fluent-smtp'),
'Disconnect' => __('Disconnect', 'fluent-smtp'),
'Disconnect & Reconnect' => __('Disconnect & Reconnect', 'fluent-smtp'),
'Discord Channel Details: ' => __('Discord Channel Details: ', 'fluent-smtp'),
'Discord Notifications Enabled' => __('Discord Notifications Enabled', 'fluent-smtp'),
'Discord Webhook URL' => __('Discord Webhook URL', 'fluent-smtp'),
'Documentation' => __('Documentation', 'fluent-smtp'),
'Domain Name' => __('Domain Name', 'fluent-smtp'),
'Edit Connection' => __('Edit Connection', 'fluent-smtp'),
'ElasticEmail API Settings' => __('ElasticEmail API Settings', 'fluent-smtp'),
'Email Address' => __('Email Address', 'fluent-smtp'),
'Email Body' => __('Email Body', 'fluent-smtp'),
'Email Failed:' => __('Email Failed:', 'fluent-smtp'),
'Email Headers' => __('Email Headers', 'fluent-smtp'),
'Email Log' => __('Email Log', 'fluent-smtp'),
'Email Logs' => __('Email Logs', 'fluent-smtp'),
'Email Marketing Automation and CRM Plugin for WordPress' => __('Email Marketing Automation and CRM Plugin for WordPress', 'fluent-smtp'),
'Email Sending Error Notifications' => __('Email Sending Error Notifications', 'fluent-smtp'),
'Email Simulation' => __('Email Simulation', 'fluent-smtp'),
'Email Test' => __('Email Test', 'fluent-smtp'),
'Email Type' => __('Email Type', 'fluent-smtp'),
'Enable Email Summary' => __('Enable Email Summary', 'fluent-smtp'),
'Enable email opens tracking on postmark(For HTML Emails only).' => __('Enable email opens tracking on postmark(For HTML Emails only).', 'fluent-smtp'),
'Enable link tracking on postmark (For HTML Emails only).' => __('Enable link tracking on postmark (For HTML Emails only).', 'fluent-smtp'),
'Encryption' => __('Encryption', 'fluent-smtp'),
'End date' => __('End date', 'fluent-smtp'),
'Enter Full Screen' => __('Enter Full Screen', 'fluent-smtp'),
'Enter new email address ex: new_sender@' => __('Enter new email address ex: new_sender@', 'fluent-smtp'),
'Enter the sender email address(optional).' => __('Enter the sender email address(optional).', 'fluent-smtp'),
'Failed' => __('Failed', 'fluent-smtp'),
'Fallback Connection' => __('Fallback Connection', 'fluent-smtp'),
'Fastest Contact Form Builder Plugin for WordPress' => __('Fastest Contact Form Builder Plugin for WordPress', 'fluent-smtp'),
'Filter' => __('Filter', 'fluent-smtp'),
'FluentCRM Email Logging' => __('FluentCRM Email Logging', 'fluent-smtp'),
'FluentSMTP does not store your email notifications data.' => __('FluentSMTP does not store your email notifications data.', 'fluent-smtp'),
'FluentSMTP does not store your email notifications data. ' => __('FluentSMTP does not store your email notifications data. ', 'fluent-smtp'),
'FluentSMTP is built using the following open-source libraries and software' => __('FluentSMTP is built using the following open-source libraries and software', 'fluent-smtp'),
'Follow this link to get a Domain Name from Mailgun:' => __('Follow this link to get a Domain Name from Mailgun:', 'fluent-smtp'),
'Follow this link to get an API Key from ElasticEmail: ' => __('Follow this link to get an API Key from ElasticEmail: ', 'fluent-smtp'),
'Follow this link to get an API Key from Mailgun:' => __('Follow this link to get an API Key from Mailgun:', 'fluent-smtp'),
'Follow this link to get an API Key from SMTP2GO:' => __('Follow this link to get an API Key from SMTP2GO:', 'fluent-smtp'),
'Follow this link to get an API Key from SendGrid:' => __('Follow this link to get an API Key from SendGrid:', 'fluent-smtp'),
'Follow this link to get an API Key:' => __('Follow this link to get an API Key:', 'fluent-smtp'),
'Force From Email (Recommended Settings: Enable)' => __('Force From Email (Recommended Settings: Enable)', 'fluent-smtp'),
'Force Sender Name' => __('Force Sender Name', 'fluent-smtp'),
'Friday' => __('Friday', 'fluent-smtp'),
'From' => __('From', 'fluent-smtp'),
'From Email' => __('From Email', 'fluent-smtp'),
'From Name' => __('From Name', 'fluent-smtp'),
'Functionalities' => __('Functionalities', 'fluent-smtp'),
'General Settings' => __('General Settings', 'fluent-smtp'),
'Get API Key.' => __('Get API Key.', 'fluent-smtp'),
'Get a Domain Name.' => __('Get a Domain Name.', 'fluent-smtp'),
'Get a Private API Key.' => __('Get a Private API Key.', 'fluent-smtp'),
'Get v3 API Key.' => __('Get v3 API Key.', 'fluent-smtp'),
'Getting Started' => __('Getting Started', 'fluent-smtp'),
'Gmail / Google Workspace API Settings' => __('Gmail / Google Workspace API Settings', 'fluent-smtp'),
'Great!' => __('Great!', 'fluent-smtp'),
'How can we help you?' => __('How can we help you?', 'fluent-smtp'),
'I have sent the code' => __('I have sent the code', 'fluent-smtp'),
'If you find an issue or have a suggestion please ' => __('If you find an issue or have a suggestion please ', 'fluent-smtp'),
'If you have a minute, consider ' => __('If you have a minute, consider ', 'fluent-smtp'),
'Install Fluent Forms (Free)' => __('Install Fluent Forms (Free)', 'fluent-smtp'),
'Install FluentCRM (Free)' => __('Install FluentCRM (Free)', 'fluent-smtp'),
'Install Ninja Tables (Free)' => __('Install Ninja Tables (Free)', 'fluent-smtp'),
'Installing... Please wait' => __('Installing... Please wait', 'fluent-smtp'),
'Join FluentCRM Facebook Community' => __('Join FluentCRM Facebook Community', 'fluent-smtp'),
'Join FluentForms Facebook Community' => __('Join FluentForms Facebook Community', 'fluent-smtp'),
'Last 3 months' => __('Last 3 months', 'fluent-smtp'),
'Last 30 Days' => __('Last 30 Days', 'fluent-smtp'),
'Last 7 Days' => __('Last 7 Days', 'fluent-smtp'),
'Last month' => __('Last month', 'fluent-smtp'),
'Last step!' => __('Last step!', 'fluent-smtp'),
'Last week' => __('Last week', 'fluent-smtp'),
'Less' => __('Less', 'fluent-smtp'),
'Log All Emails for Reporting' => __('Log All Emails for Reporting', 'fluent-smtp'),
'Log Emails' => __('Log Emails', 'fluent-smtp'),
'Mailer' => __('Mailer', 'fluent-smtp'),
'Mailgun API Settings' => __('Mailgun API Settings', 'fluent-smtp'),
'Manage Additional Senders' => __('Manage Additional Senders', 'fluent-smtp'),
'Marketing' => __('Marketing', 'fluent-smtp'),
'Meet ' => __('Meet ', 'fluent-smtp'),
'Message Stream' => __('Message Stream', 'fluent-smtp'),
'Monday' => __('Monday', 'fluent-smtp'),
'More' => __('More', 'fluent-smtp'),
'Next' => __('Next', 'fluent-smtp'),
'None' => __('None', 'fluent-smtp'),
'Notification Days' => __('Notification Days', 'fluent-smtp'),
'Notification Email Addresses' => __('Notification Email Addresses', 'fluent-smtp'),
'Off' => __('Off', 'fluent-smtp'),
'On' => __('On', 'fluent-smtp'),
'Oops!' => __('Oops!', 'fluent-smtp'),
'Outlook / Office365 API Settings' => __('Outlook / Office365 API Settings', 'fluent-smtp'),
'Pepipost API Settings' => __('Pepipost API Settings', 'fluent-smtp'),
'Pin copied to clipboard' => __('Pin copied to clipboard', 'fluent-smtp'),
'Please ' => __('Please ', 'fluent-smtp'),
'Please Provide an email' => __('Please Provide an email', 'fluent-smtp'),
'Please add another connection to use fallback feature' => __('Please add another connection to use fallback feature', 'fluent-smtp'),
'Please authenticate with Google to get ' => __('Please authenticate with Google to get ', 'fluent-smtp'),
'Please authenticate with Office365 to get ' => __('Please authenticate with Office365 to get ', 'fluent-smtp'),
'Please enter a valid email address' => __('Please enter a valid email address', 'fluent-smtp'),
'Please send test email to confirm if the connection is working or not.' => __('Please send test email to confirm if the connection is working or not.', 'fluent-smtp'),
'Postmark API Settings' => __('Postmark API Settings', 'fluent-smtp'),
'Prev' => __('Prev', 'fluent-smtp'),
'Private API Key' => __('Private API Key', 'fluent-smtp'),
'Provider' => __('Provider', 'fluent-smtp'),
'Quick Overview' => __('Quick Overview', 'fluent-smtp'),
'Read the documentation' => __('Read the documentation', 'fluent-smtp'),
'Real-Time Email Failure Notifications' => __('Real-Time Email Failure Notifications', 'fluent-smtp'),
'Receiver\'s Telegram Username: ' => __('Receiver\'s Telegram Username: ', 'fluent-smtp'),
'Recommended Plugin' => __('Recommended Plugin', 'fluent-smtp'),
'Region ' => __('Region ', 'fluent-smtp'),
'Remove' => __('Remove', 'fluent-smtp'),
'Resend' => __('Resend', 'fluent-smtp'),
'Resend Selected Emails' => __('Resend Selected Emails', 'fluent-smtp'),
'Resent Count' => __('Resent Count', 'fluent-smtp'),
'Retry' => __('Retry', 'fluent-smtp'),
'Run Another Test Email' => __('Run Another Test Email', 'fluent-smtp'),
'SMTP Host' => __('SMTP Host', 'fluent-smtp'),
'SMTP Password' => __('SMTP Password', 'fluent-smtp'),
'SMTP Port' => __('SMTP Port', 'fluent-smtp'),
'SMTP Username' => __('SMTP Username', 'fluent-smtp'),
'SMTP2GO API Settings' => __('SMTP2GO API Settings', 'fluent-smtp'),
'SSL' => __('SSL', 'fluent-smtp'),
'Saturday' => __('Saturday', 'fluent-smtp'),
'Save Connection Settings' => __('Save Connection Settings', 'fluent-smtp'),
'Save Email Logs:' => __('Save Email Logs:', 'fluent-smtp'),
'Save Settings' => __('Save Settings', 'fluent-smtp'),
'Search Results for' => __('Search Results for', 'fluent-smtp'),
'Search Type and Enter...' => __('Search Type and Enter...', 'fluent-smtp'),
'Secret Key' => __('Secret Key', 'fluent-smtp'),
'Select' => __('Select', 'fluent-smtp'),
'Select Email or Type' => __('Select Email or Type', 'fluent-smtp'),
'Select Provider' => __('Select Provider', 'fluent-smtp'),
'Select Region' => __('Select Region', 'fluent-smtp'),
'Select date and time' => __('Select date and time', 'fluent-smtp'),
'Send Test Email' => __('Send Test Email', 'fluent-smtp'),
'Send Test Message' => __('Send Test Message', 'fluent-smtp'),
'Send To' => __('Send To', 'fluent-smtp'),
'Send this email in HTML or in plain text format.' => __('Send this email in HTML or in plain text format.', 'fluent-smtp'),
'SendGrid API Settings' => __('SendGrid API Settings', 'fluent-smtp'),
'Sender Email ' => __('Sender Email ', 'fluent-smtp'),
'Sender Email Address' => __('Sender Email Address', 'fluent-smtp'),
'Sender Name' => __('Sender Name', 'fluent-smtp'),
'Sender Settings' => __('Sender Settings', 'fluent-smtp'),
'Sendinblue API Settings' => __('Sendinblue API Settings', 'fluent-smtp'),
'Sending Stats' => __('Sending Stats', 'fluent-smtp'),
'Sending by time of day' => __('Sending by time of day', 'fluent-smtp'),
'Server Response' => __('Server Response', 'fluent-smtp'),
'Set the return-path to match the From Email' => __('Set the return-path to match the From Email', 'fluent-smtp'),
'Settings' => __('Settings', 'fluent-smtp'),
'Slack Channel Details: ' => __('Slack Channel Details: ', 'fluent-smtp'),
'Slack Notifications Enabled' => __('Slack Notifications Enabled', 'fluent-smtp'),
'Sorry! No docs found' => __('Sorry! No docs found', 'fluent-smtp'),
'SparkPost API Settings' => __('SparkPost API Settings', 'fluent-smtp'),
'Start date' => __('Start date', 'fluent-smtp'),
'Status' => __('Status', 'fluent-smtp'),
'Status:' => __('Status:', 'fluent-smtp'),
'Store API Keys in Config File' => __('Store API Keys in Config File', 'fluent-smtp'),
'Store API Keys in DB' => __('Store API Keys in DB', 'fluent-smtp'),
'Store Access Keys in DB' => __('Store Access Keys in DB', 'fluent-smtp'),
'Store Application Keys in DB' => __('Store Application Keys in DB', 'fluent-smtp'),
'Subject' => __('Subject', 'fluent-smtp'),
'Subscribe To Updates' => __('Subscribe To Updates', 'fluent-smtp'),
'Successful' => __('Successful', 'fluent-smtp'),
'Summary Email' => __('Summary Email', 'fluent-smtp'),
'Sunday' => __('Sunday', 'fluent-smtp'),
'TLS' => __('TLS', 'fluent-smtp'),
'Telegram Connection Status: ' => __('Telegram Connection Status: ', 'fluent-smtp'),
'Telegram Notifications Enable' => __('Telegram Notifications Enable', 'fluent-smtp'),
'Test Email Has been successfully sent' => __('Test Email Has been successfully sent', 'fluent-smtp'),
'The email address already exists in the list' => __('The email address already exists in the list', 'fluent-smtp'),
'The email address must match the domain: ' => __('The email address must match the domain: ', 'fluent-smtp'),
'The email address which emails are sent from.' => __('The email address which emails are sent from.', 'fluent-smtp'),
'The name which emails are sent from.' => __('The name which emails are sent from.', 'fluent-smtp'),
'Thursday' => __('Thursday', 'fluent-smtp'),
'To' => __('To', 'fluent-smtp'),
'To send emails you will need only a Mail Send access level for this API key.' => __('To send emails you will need only a Mail Send access level for this API key.', 'fluent-smtp'),
'Today' => __('Today', 'fluent-smtp'),
'Total Email Sent (Logged):' => __('Total Email Sent (Logged):', 'fluent-smtp'),
'Track Opens' => __('Track Opens', 'fluent-smtp'),
'Transactional' => __('Transactional', 'fluent-smtp'),
'Try Again' => __('Try Again', 'fluent-smtp'),
'Tuesday' => __('Tuesday', 'fluent-smtp'),
'Turn On' => __('Turn On', 'fluent-smtp'),
'Type & press enter...' => __('Type & press enter...', 'fluent-smtp'),
'Use Auto TLS' => __('Use Auto TLS', 'fluent-smtp'),
'Validating Data. Please wait...' => __('Validating Data. Please wait...', 'fluent-smtp'),
'Wednesday' => __('Wednesday', 'fluent-smtp'),
'Write a review (really appreciated 😊)' => __('Write a review (really appreciated 😊)', 'fluent-smtp'),
'Yes, Disconnect' => __('Yes, Disconnect', 'fluent-smtp'),
'You may add additional sending emails in this' => __('You may add additional sending emails in this', 'fluent-smtp'),
'Your Discord Channel Name (For Internal Use)' => __('Your Discord Channel Name (For Internal Use)', 'fluent-smtp'),
'Your Discord Channel Webhook URL' => __('Your Discord Channel Webhook URL', 'fluent-smtp'),
'Your Email' => __('Your Email', 'fluent-smtp'),
'Your Email Address' => __('Your Email Address', 'fluent-smtp'),
'Your Name' => __('Your Name', 'fluent-smtp'),
'Your SMTP Username' => __('Your SMTP Username', 'fluent-smtp'),
'__ABOUT_BY' => __('FluentSMTP is free and will be always free. This is our pledge to WordPress community from WPManageNinja LLC.', 'fluent-smtp'),
'__ABOUT_COMMUNITY' => __('FluentSMTP is powered by community. We listen to our community users and build products that add value to businesses and save time.', 'fluent-smtp'),
'__ABOUT_INTRO' => __('is a free and open-source WordPress Plugin. Our mission is to provide the ultimate email delivery solution with your favorite Email sending service. FluentSMTP is built for performance and speed.', 'fluent-smtp'),
'__ABOUT_JOIN' => __('Join our communities and participate in great conversations.', 'fluent-smtp'),
'__ABOUT_POWERED' => __('FluentSMTP is powered by its users like you. Feel free to contribute on Github. Thanks to all of our contributors.', 'fluent-smtp'),
'__ANOTHER_CONNECTION_NOTICE' => __('Another connection with same email address exists. This connection will replace that connection', 'fluent-smtp'),
'__DEFAULT_CONNECTION_CONFLICT' => __('Default and Fallback connection cannot be the same. Please select different connections.', 'fluent-smtp'),
'__DEFAULT_MAIL_WARNING' => __('The Default(none) option does not use SMTP and will not improve email delivery on your site.', 'fluent-smtp'),
'__DEFAULT_MAIl_WARNING' => __('__DEFAULT_MAIl_WARNING', 'fluent-smtp'),
'__DISCORD_INTRO' => __('Get real-time notification on your Discord Channel on any email sending failure. Configure notification with Discord to start getting real time notifications.', 'fluent-smtp'),
'__DISCORD_NOTIFICATION_ENABLED' => __('Your FluentSMTP plugin is currently integrated with your Discord Channel. Receive timely notifications on Discord for any email sending issues from your website. This ongoing connection ensures you\'re always informed about your email delivery status.', 'fluent-smtp'),
'__EMAIL_LOGGING_OFF' => __('Email Logging is currently turned off. Only Failed and resent emails will be shown here', 'fluent-smtp'),
'__EMAIL_SUMMARY_INTRO' => __('Email summary is useful for getting weekly or daily emails about all the email sending stats for this site.', 'fluent-smtp'),
'__Email_Simulation_Label' => __('Disable sending all emails. If you enable this, no email will be sent.', 'fluent-smtp'),
'__Email_Simulation_Yes' => __('No Emails will be sent from your WordPress.', 'fluent-smtp'),
'__Email_TEXT_PART_Label' => __('Enable Multi-Part Plain Text version of your HTML Emails. This feature is in beta', 'fluent-smtp'),
'__FC_DESC' => __('is the best and complete feature-rich Email Marketing & CRM solution. It is also the simplest and fastest CRM and Marketing Plugin on WordPress. Manage your customer relationships, build your email lists, send email campaigns, build funnels, and make more profit and increase your conversion rates. (Yes, Its Free!)', 'fluent-smtp'),
'__FF_DESC' => __('is the ultimate user-friendly, fast, customizable drag-and-drop WordPress Contact Form Plugin that offers you all the premium features, plus many more completely unique additional features.', 'fluent-smtp'),
'__FORCE_SENDER_NAME_TIP' => __('When checked, the From Name setting above will be used for all emails, ignoring values set by other plugins.', 'fluent-smtp'),
'__GCP_API_INST' => sprintf(__('Please %s to create API keys on the Google Cloud Platform.', 'fluent-smtp'), '<a target="_blank" rel="nofollow" href="https://fluentsmtp.com/docs/connect-gmail-or-google-workspace-emails-with-fluentsmtp/">' . __('check the documentation', 'fluent-smtp') . '</a>'),
'__GCP_INTRO' => sprintf(__('Google API version has been upgraded. Please %s.', 'fluent-smtp'), '<a target="_blank" rel="noopener" href="https://fluentsmtp.com/docs/connect-gmail-or-google-workspace-emails-with-fluentsmtp/">' . __('read the doc and upgrade your API connection', 'fluent-smtp') . '</a>'),
'__GIT_CONTRIBUTE' => sprintf(__('If you are a developer and would like to contribute to the project, please %s', 'fluent-smtp'), '<a target="_blank" rel="nofollow" href="https://github.com/WPManageNinja/fluent-smtp/">' . __('contribute on GitHub', 'fluent-smtp') . '</a>'),
'__GMAIL_CODE_INSTRUCTION' => __('Simply copy the following snippet and replace the stars with the corresponding credential. Then simply paste to wp-config.php file of your WordPress installation', 'fluent-smtp'),
'__GMAIL_SUCCESS' => __('Your Gmail / Google Workspace Authentication has been enabled. No further action is needed. If you want to re-authenticate,', 'fluent-smtp'),
'__MAILGUN_REGION' => sprintf(__('If you are operating under EU laws, you may be required to use the EU region. %s.', 'fluent-smtp'), '<a target="_blank" href="https://www.mailgun.com/regions">' . __('More information on Mailgun.com', 'fluent-smtp') . '</a>'),
'__MAILGUN_URL_TIP' => __('Define which endpoint you want to use for sending messages.', 'fluent-smtp'),
'__NT_DESC' => __('Looking for a WordPress table plugin for your website? Then youre in the right place.', 'fluent-smtp'),
'__NT_DESC_EXT' => __('the best WP table plugin that comes with all the solutions to the problems you face while creating tables on your posts/pages.', 'fluent-smtp'),
'__PASSWORD_ENCRYPT_HELP' => __('This input will be securely encrypted using WP SALTS as encryption keys before saving.', 'fluent-smtp'),
'__PASSWORD_ENCRYPT_TIP' => __('If you change your WordPress SALT Keys, this credential will become invalid. Please update this credential whenever the WP SALTS are modified.', 'fluent-smtp'),
'__PEPIPOST_HELP' => __('Follow this link to get an API Key from Pepipost (Click Show button on Settings Page):', 'fluent-smtp'),
'__POSTMARK_CLICK' => __('If you enable this then link tracking header will be added to the email for Postmark.', 'fluent-smtp'),
'__POSTMARK_HELP' => __('Follow this link to get an API Key from Postmark (Your API key is in the API Tokens tab of your):', 'fluent-smtp'),
'__POSTMARK_OPEN' => __('If you enable this then open tracking header will be added to the email for Postmark.', 'fluent-smtp'),
'__REAL_NOTIFCATION_DESC' => __('Get real-time notification on your favorite messaging channel on any email sending failure. Configure any of the following channel to start getting real time notifications.', 'fluent-smtp'),
'__RETURN_PATH_ALERT' => __('Return Path indicates where non-delivery receipts - or bounce messages - are to be sent. If unchecked, bounce messages may be lost. With this enabled, you\'ll be emailed using "From Email" if any messages bounce as a result of issues with the recipients email.', 'fluent-smtp'),
'__RETURN_PATH_TOOLTIP' => sprintf(__('Return Path indicates where non-delivery receipts—or bounce messages—%1$s are to be sent. If unchecked, bounce messages may be lost. With this enabled, %2$s you\'ll be emailed using "From Email" if any messages bounce due to issues with the recipient\'s email.', 'fluent-smtp'), '<br />', '<br />'),
'__SLACK_INTRO' => __('Get real-time notification on your Slack Channel on any email sending failure. Configure notification with Slack Bot to start getting real time notifications.', 'fluent-smtp'),
'__SLACK_NOTIFICATION_ENABLED' => __('Your FluentSMTP plugin is currently integrated with your Slack Channel. Receive timely notifications on Slack for any email sending issues from your website. This ongoing connection ensures you\'re always informed about your email delivery status.', 'fluent-smtp'),
'__SLACK_TERMS' => sprintf(__('I agree to the %1$s of this Slack integration.', 'fluent-smtp'), '<a target="_blank" rel="noopener" href="https://fluentsmtp.com/terms-and-conditions/">' . __('terms and conditions', 'fluent-smtp') . '</a>'),
'__SMTP_CRED_HELP' => __('(If you need to provide your SMTP server\'s credentials (username and password) enable the authentication, in most cases this is required.)', 'fluent-smtp'),
'__SUBSCRIBE_INTRO' => __('Subscribe with your email to know about this plugin updates, releases and useful tips.', 'fluent-smtp'),
'__SUPPORT_INTRO' => sprintf(__('Please view the %1$s first. If you still can\'t find the answer, %2$s and we will be happy to assist you with any problems.', 'fluent-smtp'), '<a href="https://fluentsmtp.com/docs" target="_blank" rel="noopener">' . __('documentation', 'fluent-smtp') . '</a>', '<a href="https://github.com/WPManageNinja/fluent-smtp" target="_blank" rel="noopener">' . __('open a GitHub issue', 'fluent-smtp') . '</a>'),
'__TELEGRAM_NOTIFICATION_ENABLED' => sprintf(__('Your FluentSMTP plugin is currently integrated with Telegram. Receive timely notifications from %s on Telegram for any email sending issues from your website. This ongoing connection ensures you\'re always informed about your email delivery status.', 'fluent-smtp'), '<a target="_blank" rel="noopener" href="https://t.me/fluentsmtp_bot">@fluentsmtp_bot</a>'),
'__TELE_INTRO' => sprintf(__('Get real-time notifications on your %1$s for any email sending failures. Configure notifications with FluentSMTP\'s official %2$s to start receiving real-time alerts.', 'fluent-smtp'), '<a target="_blank" rel="noopener" href="https://telegram.org/">Telegram Messenger</a>', '<a target="_blank" rel="noopener" href="https://t.me/fluentsmtp_bot">telegram bot</a>'),
'__TELE_LAST_STEP' => sprintf(__('Please find %s on Telegram and send the following text to activate this connection.', 'fluent-smtp'), '<a target="_blank" rel="noopener" href="https://t.me/fluentsmtp_bot"><span class="tele_bot">@fluentsmtp_bot</span></a>'),
'__TELE_RESPONSE_ERROR' => __('We could not fetch the Telegram notification status. Here is the server response: ', 'fluent-smtp'),
'__TELE_TERMS' => sprintf(__('I agree to the %s of this Telegram integration.', 'fluent-smtp'), '<a target="_blank" rel="noopener" href="https://fluentsmtp.com/terms-and-conditions/">' . __('terms and conditions', 'fluent-smtp') . '</a>'),
'__TEST_EMAIL_INST' => __('Enter email address where test email will be sent (By default, logged in user email will be used if email address is not provided).', 'fluent-smtp'),
'__TLS_HELP' => __('(By default, the TLS encryption would be used if the server supports it. On some servers, it could be a problem and may need to be disabled.)', 'fluent-smtp'),
'__WP_CONFIG_INSTRUCTION' => __('Simply copy the following snippet and replace the stars with the corresponding credential. Then simply paste to wp-config.php file of your WordPress installation', 'fluent-smtp'),
'__default_connection_popover' => __('Select which connection will be used for sending transactional emails from your WordPress. If you use multiple connection then email will be routed based on source from email address', 'fluent-smtp'),
'__fallback_connection_popover' => __('Fallback Connection will be used if an email is failed to send in one connection. Please select a different connection than the default connection', 'fluent-smtp'),
'__from_email_tooltip' => __('If checked, the From Email setting above will be used for all emails (It will check if the from email is listed to available connections).', 'fluent-smtp'),
'__routing_info' => __('Your emails will be routed automatically based on From email address. No additional configuration is required.', 'fluent-smtp'),
'__wizard_instruction' => __('Please configure your first email service provider connection', 'fluent-smtp'),
'__wizard_sub' => __('Thank you for installing FluentSMTP - The ultimate SMTP & Email Service Connection Plugin for WordPress', 'fluent-smtp'),
'__wizard_title' => __('Welcome to FluentSMTP', 'fluent-smtp'),
'activate ' => __('activate ', 'fluent-smtp'),
'cancel' => __('cancel', 'fluent-smtp'),
'change' => __('change', 'fluent-smtp'),
'check the documentation first to create API keys at Microsoft' => __('check the documentation first to create API keys at Microsoft', 'fluent-smtp'),
'click here' => __('click here', 'fluent-smtp'),
'confirm' => __('confirm', 'fluent-smtp'),
'copy' => __('copy', 'fluent-smtp'),
'delete_logs_info' => __('delete_logs_info', 'fluent-smtp'),
'force_sender_tooltip' => __('force_sender_tooltip', 'fluent-smtp'),
'open an issue on GitHub' => __('open an issue on GitHub', 'fluent-smtp'),
'provider for the connection.' => __('provider for the connection.', 'fluent-smtp'),
'read the documentation here' => __('read the documentation here', 'fluent-smtp'),
'save_connection_error_1' => __('Please select your email service provider', 'fluent-smtp'),
'save_connection_error_2' => __('Credential Verification Failed. Please check your inputs', 'fluent-smtp'),
'write a review for FluentSMTP' => __('write a review for FluentSMTP', 'fluent-smtp')
];
}
}

View File

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