This commit is contained in:
2026-07-02 15:54:39 -06:00
commit 9883323161
17470 changed files with 4470592 additions and 0 deletions
@@ -0,0 +1,174 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Alerts;
use Gravity_Forms\Gravity_SMTP\Alerts\Connectors\Alert_Connector;
use Gravity_Forms\Gravity_SMTP\Alerts\Connectors\Slack_Alert_Connector;
use Gravity_Forms\Gravity_SMTP\Alerts\Connectors\Twilio_Alert_Connector;
use Gravity_Forms\Gravity_SMTP\Alerts\Endpoints\Save_Alerts_Settings_Endpoint;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Save_Plugin_Settings_Endpoint;
use Gravity_Forms\Gravity_SMTP\Data_Store\Data_Store_Router;
use Gravity_Forms\Gravity_SMTP\Models\Event_Model;
use Gravity_Forms\Gravity_SMTP\Utils\Booliesh;
class Alerts_Handler {
const ALERTS_DATA_TRANSIENT = 'gravitysmtp_alerts_data';
/**
* @var Event_Model
*/
protected $events;
/**
* @var Data_Store_Router
*/
protected $plugin_data;
/**
* @var Alert_Connector[]
*/
protected $connectors;
public function __construct( $events, $plugin_data, $connectors ) {
$this->events = $events;
$this->plugin_data = $plugin_data;
$this->connectors = $connectors;
}
protected function default_settings() {
return array(
Save_Alerts_Settings_Endpoint::PARAM_NOTIFY_WHEN_EMAIL_FAILS => false,
Save_Alerts_Settings_Endpoint::PARAM_SLACK_ALERTS_ENABLED => false,
Save_Alerts_Settings_Endpoint::PARAM_SLACK_ALERTS => array(),
Save_Alerts_Settings_Endpoint::PARAM_TWILIO_ALERTS_ENABLED => false,
Save_Alerts_Settings_Endpoint::PARAM_TWILIO_ALERTS => array(),
Save_Alerts_Settings_Endpoint::PARAM_ALERT_THRESHOLD_COUNT => 5,
Save_Alerts_Settings_Endpoint::PARAM_ALERT_THRESHOLD_INTERVAL => 5,
);
}
public function record_failed_email() {
$current_data = get_transient( self::ALERTS_DATA_TRANSIENT );
$alert_count_interval = $this->plugin_data->get_plugin_setting( Save_Alerts_Settings_Endpoint::PARAM_ALERT_THRESHOLD_INTERVAL, 5 );
if ( $current_data !== false ) {
$current_data['count'] += 1;
$created_at = new \DateTime( date( 'Y-m-d H:i:s', $current_data['created_at'] ) );
$now = new \DateTime();
$interval = $now->diff( $created_at );
$seconds_diff = (int) $interval->format( '%i' ) * 60 + ( (int) $interval->format( '%s' ) );
$new_exp = ( MINUTE_IN_SECONDS * ( $alert_count_interval + 2 ) ) - $seconds_diff;
set_transient( self::ALERTS_DATA_TRANSIENT, $current_data, $new_exp );
return;
}
$current_data = array(
'count' => 1,
'created_at' => time(),
);
set_transient( self::ALERTS_DATA_TRANSIENT, $current_data, MINUTE_IN_SECONDS * ( $alert_count_interval + 2 ) );
}
public function failed_emails_alert() {
$alerts_settings = $this->plugin_data->get_plugin_setting( Save_Alerts_Settings_Endpoint::PARAM_SETTINGS, $this->default_settings() );
$logging_enabled = $this->plugin_data->get_plugin_setting( Save_Plugin_Settings_Endpoint::PARAM_EVENT_LOG_ENABLED, false );
$send_on_fail_enabled = Booliesh::get( $alerts_settings[ Save_Alerts_Settings_Endpoint::PARAM_NOTIFY_WHEN_EMAIL_FAILS ] );
// This alert trigger is not enabled.
if ( ! $send_on_fail_enabled ) {
return;
}
$count = isset( $alerts_settings[ Save_Alerts_Settings_Endpoint::PARAM_ALERT_THRESHOLD_COUNT ] ) ? $alerts_settings[ Save_Alerts_Settings_Endpoint::PARAM_ALERT_THRESHOLD_COUNT ] : 5;
$failures = get_transient( self::ALERTS_DATA_TRANSIENT );
if ( false === $failures ) {
return;
}
if ( $failures['count'] < $count ) {
return;
}
$slack_enabled = Booliesh::get( $alerts_settings[ Save_Alerts_Settings_Endpoint::PARAM_SLACK_ALERTS_ENABLED ] );
if ( $slack_enabled ) {
$this->send_slack_alerts( $failures['count'], $logging_enabled, $alerts_settings[ Save_Alerts_Settings_Endpoint::PARAM_SLACK_ALERTS ] );
}
$twilio_enabled = Booliesh::get( $alerts_settings[ Save_Alerts_Settings_Endpoint::PARAM_TWILIO_ALERTS_ENABLED ] );
if ( $twilio_enabled ) {
$this->send_twilio_alerts( $failures['count'], $logging_enabled, $alerts_settings[ Save_Alerts_Settings_Endpoint::PARAM_TWILIO_ALERTS ] );
}
delete_transient( self::ALERTS_DATA_TRANSIENT );
}
private function failed_email_message( $count, $logging_enabled ) {
$base_url = admin_url( 'admin.php' );
if ( $logging_enabled ) {
$url = add_query_arg( array(
'page' => 'gravitysmtp-activity-log',
), $base_url );
} else {
$url = add_query_arg( array(
'page' => 'gravitysmtp-dashboard',
), $base_url );
}
return esc_html__( sprintf( 'Your site %s has experienced %d email send failures. For more details visit %s', get_bloginfo( 'name' ), $count, $url ) );
}
private function send_slack_alerts( $count, $logging_enabled, $alerts ) {
if ( empty( $alerts ) ) {
return;
}
/**
* @var Slack_Alert_Connector $slack_connector
*/
$slack_connector = $this->connectors['slack'];
$message = $this->failed_email_message( $count, $logging_enabled );
foreach ( $alerts as $alert ) {
$args = array(
'webhook_url' => $alert['slack_webhook_url'],
'message' => $message
);
$slack_connector->send( $args );
}
}
private function send_twilio_alerts( $count, $logging_enabled, $alerts ) {
if ( empty( $alerts ) ) {
return;
}
/**
* @var Twilio_Alert_Connector $twilio_connector
*/
$twilio_connector = $this->connectors['twilio'];
$message = $this->failed_email_message( $count, $logging_enabled );
foreach ( $alerts as $alert ) {
$args = array(
'account_id' => $alert['twilio_account_id'],
'auth_token' => $alert['twilio_auth_token'],
'to' => $alert['twilio_to_phone_number'],
'from' => $alert['twilio_from_phone_number'],
'message' => $message,
);
$twilio_connector->send( $args );
}
}
}
@@ -0,0 +1,99 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Alerts;
use Gravity_Forms\Gravity_SMTP\Alerts\Config\Alerts_Config;
use Gravity_Forms\Gravity_SMTP\Alerts\Config\Alerts_Endpoints_Config;
use Gravity_Forms\Gravity_SMTP\Alerts\Connectors\Slack_Alert_Connector;
use Gravity_Forms\Gravity_SMTP\Alerts\Connectors\Twilio_Alert_Connector;
use Gravity_Forms\Gravity_SMTP\Alerts\Endpoints\Save_Alerts_Settings_Endpoint;
use Gravity_Forms\Gravity_SMTP\Alerts\Endpoints\Send_Test_Alert_Endpoint;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Logging\Logging_Service_Provider;
use Gravity_Forms\Gravity_Tools\Providers\Config_Service_Provider;
use Gravity_Forms\Gravity_Tools\Service_Container;
class Alerts_Service_Provider extends Config_Service_Provider {
const FAILED_EMAILS_ALERT_ACTION_NAME = 'failed_emails_alert_action';
const ALERTS_CONFIG = 'alerts_config';
const ALERTS_ENDPOINTS_CONFIG = 'alerts_endpoints_config';
const TWILIO_ALERT_CONNECTOR = 'twilio_alert_connector';
const SLACK_ALERT_CONNECTOR = 'slack_alert_connector';
const SAVE_ALERTS_SETTINGS_ENDPOINT = 'save_alerts_settings_endpoint';
const ALERTS_HANDLER = 'alerts_handler';
const SEND_TEST_ALERT_ENDPOINT = 'send_test_alert_endpoint';
protected $configs = array(
self::ALERTS_CONFIG => Alerts_Config::class,
self::ALERTS_ENDPOINTS_CONFIG => Alerts_Endpoints_Config::class
);
public function register( Service_Container $container ) {
parent::register( $container );
$container->add( self::TWILIO_ALERT_CONNECTOR, function () use ( $container ) {
$debug_logger = $container->get( Logging_Service_Provider::DEBUG_LOGGER );
return new Twilio_Alert_Connector( $debug_logger );
} );
$container->add( self::SLACK_ALERT_CONNECTOR, function () use ( $container ) {
$debug_logger = $container->get( Logging_Service_Provider::DEBUG_LOGGER );
return new Slack_Alert_Connector( $debug_logger );
} );
$container->add( self::SAVE_ALERTS_SETTINGS_ENDPOINT, function () use ( $container ) {
$plugin_data_store = $container->get( Connector_Service_Provider::DATA_STORE_PLUGIN_OPTS );
return new Save_Alerts_Settings_Endpoint( $plugin_data_store );
} );
$container->add( self::SEND_TEST_ALERT_ENDPOINT, function () use ( $container ) {
$connectors = array(
'slack' => $container->get( self::SLACK_ALERT_CONNECTOR ),
'twilio' => $container->get( self::TWILIO_ALERT_CONNECTOR ),
);
return new Send_Test_Alert_Endpoint( $connectors );
} );
$container->add( self::ALERTS_HANDLER, function () use ( $container ) {
$connectors = array(
'slack' => $container->get( self::SLACK_ALERT_CONNECTOR ),
'twilio' => $container->get( self::TWILIO_ALERT_CONNECTOR ),
);
$data_store = $container->get( Connector_Service_Provider::DATA_STORE_ROUTER );
$event_model = $container->get( Connector_Service_Provider::EVENT_MODEL );
return new Alerts_Handler( $event_model, $data_store, $connectors );
} );
}
public function init( \Gravity_Forms\Gravity_Tools\Service_Container $container ) {
add_action( 'wp_ajax_' . Save_Alerts_Settings_Endpoint::ACTION_NAME, function () use ( $container ) {
$container->get( self::SAVE_ALERTS_SETTINGS_ENDPOINT )->handle();
} );
add_action( 'wp_ajax_' . Send_Test_Alert_Endpoint::ACTION_NAME, function () use ( $container ) {
$container->get( self::SEND_TEST_ALERT_ENDPOINT )->handle();
} );
if ( ! wp_next_scheduled( self::FAILED_EMAILS_ALERT_ACTION_NAME ) ) {
wp_schedule_event( time(), 'every-minute', self::FAILED_EMAILS_ALERT_ACTION_NAME );
}
add_action( 'gravitysmtp_on_send_failure', function ( $email_id ) use ( $container ) {
$container->get( self::ALERTS_HANDLER )->record_failed_email();
} );
add_action( self::FAILED_EMAILS_ALERT_ACTION_NAME, function () use ( $container ) {
$container->get( self::ALERTS_HANDLER )->failed_emails_alert();
} );
}
}
@@ -0,0 +1,264 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Alerts\Config;
use Gravity_Forms\Gravity_SMTP\Alerts\Endpoints\Save_Alerts_Settings_Endpoint;
use Gravity_Forms\Gravity_SMTP\Apps\Endpoints\Get_Dashboard_Data_Endpoint;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Save_Plugin_Settings_Endpoint;
use Gravity_Forms\Gravity_SMTP\Gravity_SMTP;
use Gravity_Forms\Gravity_SMTP\Utils\Booliesh;
use Gravity_Forms\Gravity_Tools\Config;
class Alerts_Config extends Config {
const SETTING_SEND_ON_FAIL = 'send_on_fail';
const SETTING_ENABLE_SLACK_ALERTS = 'enable_slack_alerts';
const SETTING_ENABLE_TWILIO_ALERTS = 'enable_twilio_alerts';
const SETTING_SLACK_ALERTS = 'slack_alerts';
const SETTING_SLACK_WEBHOOK_URL = 'slack_webhook_url';
const SETTING_TWILIO_ALERTS = 'twilio_alerts';
const SETTING_TWILIO_ACCOUNT_ID = 'twilio_account_id';
const SETTING_TWILIO_ACCOUNT_NAME = 'twilio_account_name';
const SETTING_TWILIO_AUTH_TOKEN = 'twilio_auth_token';
const SETTING_TWILIO_FROM_PHONE_NUMBER = 'twilio_from_phone_number';
const SETTING_TWILIO_TO_PHONE_NUMBER = 'twilio_to_phone_number';
protected $script_to_localize = 'gravitysmtp_scripts_admin';
protected $name = 'gravitysmtp_admin_config';
protected $overwrite = false;
public function should_enqueue() {
if ( ! is_admin() ) {
return false;
}
$page = filter_input( INPUT_GET, 'page' );
if ( ! is_string( $page ) ) {
return false;
}
$page = htmlspecialchars( $page );
if ( $page !== 'gravitysmtp-settings' ) {
return false;
}
return true;
}
public function data() {
return array(
'components' => array(
'settings' => array(
'i18n' => $this->i18n_values(),
'data' => $this->data_values(),
),
)
);
}
protected function i18n_values() {
return array(
'alerts' => array(
'top_heading' => esc_html__( 'Alerts', 'gravitysmtp' ),
'top_content' => __( "Use these settings to configure alerts for failed email sending attempts. Set up notifications through Webhooks or SMS (via Twilio) to ensure you're informed when an email fails to send. Multiple integrations can be added and managed.", 'gravitysmtp' ),
'alerts_box_heading' => esc_html__( 'Alerts Settings', 'gravitysmtp' ),
'notify_heading' => esc_html__( 'When to Notify', 'gravitysmtp' ),
'email_request_fails_label' => esc_html__( 'Email send request fails', 'gravitysmtp' ),
'email_request_fails_help_text' => esc_html__( 'Enable this option send an alert when an email send attempt fails for any reason.', 'gravitysmtp' ),
'alert_threshold_count_label' => esc_html__( 'Failure Amount', 'gravitysmtp' ),
'alert_threshold_count_help_text' => esc_html__( 'The number of failures to trigger an alert.', 'gravitysmtp' ),
'alert_threshold_interval_label' => esc_html__( 'Alert Rate', 'gravitysmtp' ),
'alert_threshold_interval_help_text' => esc_html__( 'Interval for sending alerts about failures (in minutes).', 'gravitysmtp' ),
'slack_heading' => esc_html__( 'Webhooks', 'gravitysmtp' ),
'slack_alerts_label' => esc_html__( 'Webhook Alerts', 'gravitysmtp' ),
'slack_alerts_help_text' => esc_html__( "Get notified via webhook or SMS (Twilio) when emails fail to send. Webhooks can be used with services like Slack, Zapier, and more.", 'gravitysmtp' ),
'slack_webhook_add_button_label' => esc_html__( 'Add Webhook', 'gravitysmtp' ),
'slack_webhook_delete_button_label' => esc_html__( 'Delete', 'gravitysmtp' ),
'start_sending_test_alert' => esc_html__( 'Sending a test alert from the alerts settings page.', 'gravitysmtp' ),
'snackbar_test_alert_success' => esc_html__( 'Alert successfully configured!', 'gravitysmtp' ),
'snackbar_test_alert_error' => esc_html__( 'Could not send alert. Check Debug Log for details.', 'gravitysmtp' ),
'twilio_heading' => esc_html__( 'Twilio', 'gravitysmtp' ),
'twilio_alerts_block_heading' => esc_html__( 'Twilio Account: %s', 'gravitysmtp' ),
'twilio_alerts_label' => esc_html__( 'SMS via Twilio Alerts', 'gravitysmtp' ),
'twilio_alerts_help_text' => __( "Enter the Twilio account you'd like to use to send alerts when email sending fails.", 'gravitysmtp' ),
'twilio_account_add_button_label' => esc_html__( 'Add Another Account', 'gravitysmtp' ),
'twilio_account_delete_button_label' => esc_html__( 'Delete', 'gravitysmtp' ),
'save_settings_button_label' => esc_html__( 'Save Settings', 'gravitysmtp' ),
'drag_button_label' => esc_html__( 'Click to toggle drag and drop.', 'gravitysmtp' ),
'begin_drag_notice' => __( 'Entering drag and drop for item %1$s.', 'gravitysmtp' ),
'end_drag_notice' => __( 'Exiting drag and drop for item %1$s.', 'gravitysmtp' ),
'end_drop_notice' => __( 'Item %1$s moved to position %2$s.', 'gravitysmtp' ),
'move_item_notice' => __( 'Moving item %1$s to position %2$s.', 'gravitysmtp' ),
)
);
}
private function empty_twilio_item() {
return array(
'repeater_item_block_content_title' => esc_html__( 'Twilio Account:', 'gravitysmtp' ),
'repeater_item_collapsed' => false,
'repeater_item_id' => 'repeater-twilio-alerts-0',
'twilio_account_name' => '',
'twilio_account_id' => '',
'twilio_auth_token' => '',
'twilio_from_phone_number' => '',
'twilio_to_phone_number' => '',
);
}
private function empty_slack_item() {
return array(
'repeater_item_id' => 'repeater-slack-alerts-0',
'slack_webhook_url' => '',
);
}
private function default_setting_values() {
return array(
Save_Alerts_Settings_Endpoint::PARAM_NOTIFY_WHEN_EMAIL_FAILS => false,
Save_Alerts_Settings_Endpoint::PARAM_SLACK_ALERTS_ENABLED => false,
Save_Alerts_Settings_Endpoint::PARAM_SLACK_ALERTS => array(),
Save_Alerts_Settings_Endpoint::PARAM_TWILIO_ALERTS_ENABLED => false,
Save_Alerts_Settings_Endpoint::PARAM_TWILIO_ALERTS => array(),
Save_Alerts_Settings_Endpoint::PARAM_ALERT_THRESHOLD_COUNT => 5,
Save_Alerts_Settings_Endpoint::PARAM_ALERT_THRESHOLD_INTERVAL => 5,
);
}
protected function data_values() {
$container = Gravity_SMTP::container();
$plugin_data_store = $container->get( Connector_Service_Provider::DATA_STORE_ROUTER );
// todo: not sure these defaults work correctly
$alerts_settings = $plugin_data_store->get_plugin_setting( Save_Alerts_Settings_Endpoint::PARAM_SETTINGS, $this->default_setting_values() );
$notify_when_email_sending_fails_enabled = Booliesh::get( $alerts_settings[ Save_Alerts_Settings_Endpoint::PARAM_NOTIFY_WHEN_EMAIL_FAILS ] );
$slack_alerts_enabled = Booliesh::get( $alerts_settings[ Save_Alerts_Settings_Endpoint::PARAM_SLACK_ALERTS_ENABLED ] );
$twilio_alerts_enabled = Booliesh::get( $alerts_settings[ Save_Alerts_Settings_Endpoint::PARAM_TWILIO_ALERTS_ENABLED ] );
$alert_threshold_count = isset( $alerts_settings[ Save_Alerts_Settings_Endpoint::PARAM_ALERT_THRESHOLD_COUNT ] ) ? $alerts_settings[ Save_Alerts_Settings_Endpoint::PARAM_ALERT_THRESHOLD_COUNT ] : 5;
$alert_threshold_interval = isset( $alerts_settings[ Save_Alerts_Settings_Endpoint::PARAM_ALERT_THRESHOLD_INTERVAL ] ) ? $alerts_settings[ Save_Alerts_Settings_Endpoint::PARAM_ALERT_THRESHOLD_INTERVAL ] : 5;
$slack_alerts = ! empty( $alerts_settings[ Save_Alerts_Settings_Endpoint::PARAM_SLACK_ALERTS ] ) ? $alerts_settings[ Save_Alerts_Settings_Endpoint::PARAM_SLACK_ALERTS ] : array( $this->empty_slack_item() );
$twilio_alerts = ! empty( $alerts_settings[ Save_Alerts_Settings_Endpoint::PARAM_TWILIO_ALERTS ] ) ? $alerts_settings[ Save_Alerts_Settings_Endpoint::PARAM_TWILIO_ALERTS ] : array( $this->empty_twilio_item() );
// Fix boolean strings
foreach ( $twilio_alerts as $key => $values ) {
$values['repeater_item_collapsed'] = Booliesh::get( $values['repeater_item_collapsed'] );
$twilio_alerts[ $key ] = $values;
}
return array(
'alerts_settings' => array(
'notify_when_email_sending_fails_enabled' => $notify_when_email_sending_fails_enabled,
'slack_alerts_enabled' => $slack_alerts_enabled,
'twilio_alerts_enabled' => $twilio_alerts_enabled,
'alert_threshold_count' => $alert_threshold_count,
'alert_threshold_interval' => $alert_threshold_interval,
self::SETTING_SLACK_ALERTS => array(
'fields' => array(
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'Webhook URL', 'gravitysmtp' ),
'isVisible' => false,
),
'name' => self::SETTING_SLACK_WEBHOOK_URL,
),
),
array(
'component' => 'Button',
'props' => array(
'label' => esc_html__( 'Test Webhook', 'gravitysmtp' ),
'icon' => 'play',
'iconPosition' => 'leading',
'iconPrefix' => 'gravity-admin-icon',
'size' => 'size-height-m',
'type' => 'white',
),
)
),
'items' => $slack_alerts,
'path' => 'gravitysmtp_admin_config.components.settings.data.alerts_settings.' . self::SETTING_SLACK_ALERTS . '.items',
),
self::SETTING_TWILIO_ALERTS => array(
'fields' => array(
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'Account Name', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'name' => self::SETTING_TWILIO_ACCOUNT_NAME,
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'Twilio Account SID', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'name' => self::SETTING_TWILIO_ACCOUNT_ID,
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'Twilio Auth Token', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'name' => self::SETTING_TWILIO_AUTH_TOKEN,
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'From Phone Number', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'name' => self::SETTING_TWILIO_FROM_PHONE_NUMBER,
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'To Phone Number', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'name' => self::SETTING_TWILIO_TO_PHONE_NUMBER,
),
),
array(
'component' => 'Button',
'props' => array(
'customClasses' => [ 'gravitysmtp-alerts-settings__twilio-test-connection' ],
'label' => esc_html__( 'Test Connection', 'gravitysmtp' ),
'icon' => 'play',
'iconPosition' => 'leading',
'iconPrefix' => 'gravity-admin-icon',
'size' => 'size-height-m',
'type' => 'white',
),
),
),
'items' => $twilio_alerts,
'path' => 'gravitysmtp_admin_config.components.settings.data.alerts_settings.' . self::SETTING_TWILIO_ALERTS . '.items',
),
),
);
}
}
@@ -0,0 +1,47 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Alerts\Config;
use Gravity_Forms\Gravity_SMTP\Alerts\Endpoints\Save_Alerts_Settings_Endpoint;
use Gravity_Forms\Gravity_SMTP\Alerts\Endpoints\Send_Test_Alert_Endpoint;
use Gravity_Forms\Gravity_Tools\Config;
class Alerts_Endpoints_Config extends Config {
protected $script_to_localize = 'gravitysmtp_scripts_admin';
protected $name = 'gravitysmtp_admin_config';
public function should_enqueue() {
return is_admin();
}
public function data() {
return array(
'common' => array(
'endpoints' => array(
Save_Alerts_Settings_Endpoint::ACTION_NAME => array(
'action' => array(
'value' => Save_Alerts_Settings_Endpoint::ACTION_NAME,
'default' => 'mock_endpoint',
),
'nonce' => array(
'value' => wp_create_nonce( Save_Alerts_Settings_Endpoint::ACTION_NAME ),
'default' => 'nonce',
),
),
Send_Test_Alert_Endpoint::ACTION_NAME => array(
'action' => array(
'value' => Send_Test_Alert_Endpoint::ACTION_NAME,
'default' => 'mock_endpoint',
),
'nonce' => array(
'value' => wp_create_nonce( Send_Test_Alert_Endpoint::ACTION_NAME ),
'default' => 'nonce',
),
),
),
),
);
}
}
@@ -0,0 +1,62 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Alerts\Connectors;
use Gravity_Forms\Gravity_SMTP\Logging\Debug\Debug_Logger;
class Slack_Alert_Connector implements Alert_Connector {
/**
* @var Debug_Logger
*/
private $debug_logger;
public function __construct( Debug_Logger $debug_logger ) {
$this->debug_logger = $debug_logger;
}
public function send( $send_args ) {
$webhook_url = $send_args['webhook_url'];
$message = $send_args['message'];
$request_body = array(
'text' => $message,
);
$request_body = apply_filters( 'gravitysmtp_slack_alert_request_body', $request_body, $send_args );
$this->debug_logger->log_debug( __METHOD__ . '(): About to make request to a webhook url with the following request args: ' . json_encode( $request_body ) );
$request_params = array(
'body' => json_encode( $request_body ),
'headers' => array(
'Content-Type' => 'application/json',
),
);
$request = $this->make_request( $webhook_url, $request_params );
if ( is_wp_error( $request ) ) {
$this->debug_logger->log_error( __METHOD__ . '(): Request to Webhook URL failed. Details: ' . $request->get_error_message() );
return false;
}
$this->debug_logger->log_debug( __METHOD__ . '(): Request to Webhook URL succeeded.' );
return true;
}
public function make_request( $url, $request_args ) {
$request = wp_safe_remote_post( $url, $request_args );
$code = wp_remote_retrieve_response_code( $request );
if ( (int) $code !== 200 ) {
$this->debug_logger->log_error( wp_remote_retrieve_body( $request ) );
return new \WP_Error( 'Could not send message via Slack.' );
}
return true;
}
}
@@ -0,0 +1,80 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Alerts\Connectors;
use Gravity_Forms\Gravity_SMTP\Logging\Debug\Debug_Logger;
class Twilio_Alert_Connector implements Alert_Connector {
const BASE_URL = 'https://api.twilio.com/2010-04-01/Accounts';
/**
* @var Debug_Logger
*/
private $debug_logger;
public function __construct( Debug_Logger $debug_logger ) {
$this->debug_logger = $debug_logger;
}
public function send( $send_args ) {
$account_id = $send_args['account_id'];
$auth_token = $send_args['auth_token'];
$to = $send_args['to'];
$from = $send_args['from'];
$message = $send_args['message'];
$request_body = array(
'ApplicationSid' => $account_id,
'Body' => $message,
'To' => $to,
'From' => $from,
);
$request_body = apply_filters( 'gravitysmtp_twilio_alert_request_body', $request_body, $send_args );
$request_headers = array(
'Authorization' => $this->get_auth_header( $account_id, $auth_token ),
);
$this->debug_logger->log_debug( __METHOD__ . '(): About to make request to Twilio with the following request args: ' . json_encode( $request_body ) );
$request_params = array(
'body' => $request_body,
'headers' => $request_headers,
);
$request = $this->make_request( $this->get_request_url( $account_id ), $request_params );
if ( is_wp_error( $request ) ) {
$this->debug_logger->log_error( __METHOD__ . '(): Request to Twilio failed. Details: ' . $request->get_error_message() );
return false;
}
$this->debug_logger->log_debug( __METHOD__ . '(): Request to Twilio succeeded.' );
return true;
}
public function make_request( $url, $request_args ) {
$request = wp_remote_post( $url, $request_args );
$code = wp_remote_retrieve_response_code( $request );
if ( (int) $code !== 201 ) {
$this->debug_logger->log_error( wp_remote_retrieve_body( $request ) );
return new \WP_Error( 'Could not send message via Twilio.' );
}
return true;
}
private function get_request_url( $account_id ) {
return sprintf( '%s/%s/Messages.json', self::BASE_URL, $account_id );
}
private function get_auth_header( $account_id, $auth_token ) {
return 'Basic ' . base64_encode( sprintf( '%s:%s', $account_id, $auth_token ) );
}
}
@@ -0,0 +1,11 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Alerts\Connectors;
interface Alert_Connector {
public function send( $send_args );
public function make_request( $url, $request_args );
}
@@ -0,0 +1,57 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Alerts\Endpoints;
use Gravity_Forms\Gravity_SMTP\Data_Store\Plugin_Opts_Data_Store;
use Gravity_Forms\Gravity_SMTP\Users\Roles;
use Gravity_Forms\Gravity_Tools\Endpoints\Endpoint;
class Save_Alerts_Settings_Endpoint extends Endpoint {
const PARAM_SETTINGS = 'alerts_settings';
const PARAM_ALERT_THRESHOLD_COUNT = 'alert_threshold_count';
const PARAM_ALERT_THRESHOLD_INTERVAL = 'alert_threshold_interval';
const PARAM_NOTIFY_WHEN_EMAIL_FAILS = 'notify_when_email_sending_fails_enabled';
const PARAM_SLACK_ALERTS_ENABLED = 'slack_alerts_enabled';
const PARAM_SLACK_ALERTS = 'slack_alerts';
const PARAM_TWILIO_ALERTS_ENABLED = 'twilio_alerts_enabled';
const PARAM_TWILIO_ALERTS = 'twilio_alerts';
const ACTION_NAME = 'save_alerts_settings';
protected $minimum_cap = Roles::EDIT_ALERTS;
/**
* @var Plugin_Opts_Data_Store
*/
protected $plugin_data_store;
protected $required_params = array(
self::PARAM_SETTINGS,
);
public function __construct( $plugin_data_store ) {
$this->plugin_data_store = $plugin_data_store;
}
protected function get_nonce_name() {
return self::ACTION_NAME;
}
public function handle() {
if ( ! $this->validate() ) {
wp_send_json_error( __( 'Missing required parameters.', 'gravitysmtp' ), 400 );
}
$settings = filter_input( INPUT_POST, self::PARAM_SETTINGS, FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
$this->plugin_data_store->save( self::PARAM_SETTINGS, $settings );
wp_send_json_success( $settings );
}
}
@@ -0,0 +1,94 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Alerts\Endpoints;
use Gravity_Forms\Gravity_SMTP\Alerts\Connectors\Alert_Connector;
use Gravity_Forms\Gravity_SMTP\Users\Roles;
use Gravity_Forms\Gravity_Tools\Endpoints\Endpoint;
class Send_Test_Alert_Endpoint extends Endpoint {
const PARAM_DATA = 'data';
const PARAM_DATA_TYPE = 'type';
const PARAM_DATA_SETTINGS = 'settings';
const ACTION_NAME = 'send_test_alert';
protected $minimum_cap = Roles::VIEW_TOOLS_SENDATEST;
/**
* @var Alert_Connector[]
*/
protected $connectors;
protected $required_params = array(
self::PARAM_DATA,
);
public function __construct( $connectors ) {
$this->connectors = $connectors;
}
protected function get_nonce_name() {
return self::ACTION_NAME;
}
public function handle() {
if ( ! $this->validate() ) {
wp_send_json_error( __( 'Missing required parameters.', 'gravitysmtp' ), 400 );
}
$data = filter_input( INPUT_POST, self::PARAM_DATA, FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
if ( empty( $data[ self::PARAM_DATA_TYPE ] ) ) {
wp_send_json_error( __( 'Data array parameter must contain a type key.', 'gravitysmtp' ), 400 );
}
$type = $data[ self::PARAM_DATA_TYPE ];
if ( empty( $this->connectors[ $type ] ) ) {
wp_send_json_error( __( 'Invalid connector type of ' . $type . ' provided.', 'gravitysmtp' ), 400 );
}
/**
* @var Alert_Connector $connector
*/
$connector = $this->connectors[ $type ];
$settings = $data[ self::PARAM_DATA_SETTINGS ];
switch ( $type ) {
case 'slack':
default:
if ( empty( $settings['slack_webhook_url'] ) ) {
wp_send_json_error( __( 'Slack connector requires a webhook_url.', 'gravitysmtp' ), 400 );
}
$args = array(
'webhook_url' => $settings['slack_webhook_url'],
'message' => __( 'Gravity SMTP Test: Webhook is working!', 'gravitysmtp' ),
);
break;
case 'twilio':
if ( empty( $settings['twilio_account_id'] ) || empty( $settings['twilio_auth_token'] ) || empty( $settings['twilio_to_phone_number'] ) || empty( $settings['twilio_from_phone_number'] ) ) {
wp_send_json_error( __( 'Twilio connector requires a twilio_account_id, twilio_auth_token, twilio_to_phone_number, and twilio_from_phone_number.', 'gravitysmtp' ), 400 );
}
$args = array(
'account_id' => $settings['twilio_account_id'],
'auth_token' => $settings['twilio_auth_token'],
'to' => $settings['twilio_to_phone_number'],
'from' => $settings['twilio_from_phone_number'],
'message' => __( 'Gravity SMTP Test: Twilio is set up!', 'gravitysmtp' ),
);
break;
}
$sent = $connector->send( $args );
if ( ! $sent ) {
wp_send_json_error( __( 'Could not send alert. Check Debug Log for details.', 'gravitysmtp' ), 500 );
}
wp_send_json_success( __( 'Alert successfully configured!', 'gravitysmtp' ) );
}
}
@@ -0,0 +1,292 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Apps;
use Gravity_Forms\Gravity_SMTP\Apps\Config\Apps_Config;
use Gravity_Forms\Gravity_SMTP\Apps\Config\Dashboard_Config;
use Gravity_Forms\Gravity_SMTP\Apps\Config\Email_Log_Config;
use Gravity_Forms\Gravity_SMTP\Apps\Config\Email_Log_Single_Config;
use Gravity_Forms\Gravity_SMTP\Apps\Config\Settings_Config;
use Gravity_Forms\Gravity_SMTP\Apps\Config\Tools_Config;
use Gravity_Forms\Gravity_SMTP\Apps\Endpoints\Get_Dashboard_Data_Endpoint;
use Gravity_Forms\Gravity_SMTP\Assets\Assets_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Save_Plugin_Settings_Endpoint;
use Gravity_Forms\Gravity_SMTP\Feature_Flags\Feature_Flag_Manager;
use Gravity_Forms\Gravity_SMTP\Gravity_SMTP;
use Gravity_Forms\Gravity_SMTP\Models\Suppressed_Emails_Model;
use Gravity_Forms\Gravity_SMTP\Utils\Booliesh;
use Gravity_Forms\Gravity_Tools\Apps\Registers_Apps;
use Gravity_Forms\Gravity_Tools\Providers\Config_Service_Provider;
use Gravity_Forms\Gravity_Tools\Service_Container;
class App_Service_Provider extends Config_Service_Provider {
use Registers_Apps;
const APPS_CONFIG = 'apps_config';
const EMAIL_LOG_CONFIG = 'email_log_config';
const EMAIL_LOG_SINGLE_CONFIG = 'email_log_single_config';
const SETTINGS_CONFIG = 'settings_config';
const TOOLS_CONFIG = 'tools_config';
const DASHBOARD_CONFIG = 'dashboard_config';
const GET_DASHBOARD_DATA_ENDPOINT = 'get_dashboard_data_endpoint';
const SHOULD_ENQUEUE_SETUP_WIZARD = 'should_enqueue_setup_wizard';
const FEATURE_FLAG_DASHBOARD = 'gravitysmtp_dashboard_app';
protected $configs = array(
self::APPS_CONFIG => Apps_Config::class,
self::EMAIL_LOG_CONFIG => Email_Log_Config::class,
self::EMAIL_LOG_SINGLE_CONFIG => Email_Log_Single_Config::class,
self::SETTINGS_CONFIG => Settings_Config::class,
self::TOOLS_CONFIG => Tools_Config::class,
self::DASHBOARD_CONFIG => Dashboard_Config::class,
);
protected $plugin_url;
public function __construct( $plugin_url ) {
$this->plugin_url = $plugin_url;
}
public function register( Service_Container $container ) {
parent::register( $container );
$this->container->add( self::SHOULD_ENQUEUE_SETUP_WIZARD, function () use ( $container ) {
return function () {
$page = filter_input( INPUT_GET, 'page' );
if ( ! is_string( $page ) ) {
return false;
}
$setup_wizard_page = filter_input( INPUT_GET, 'setup-wizard-page' );
$page = htmlspecialchars( $page );
$container = Gravity_SMTP::container();
$should_display = Booliesh::get( $container->get( Connector_Service_Provider::DATA_STORE_ROUTER )->get_plugin_setting( Save_Plugin_Settings_Endpoint::PARAM_SETUP_WIZARD_SHOULD_DISPLAY, 'true' ) );
return $should_display ? strpos( $page, 'gravitysmtp-' ) !== false : is_string( $setup_wizard_page );
};
}, true );
$min = $this->container->get( Assets_Service_Provider::ENVIRONMENT_DETAILS )->get_min();
$ver = $this->container->get( Assets_Service_Provider::ENVIRONMENT_DETAILS )->get_version();
$this->register_setup_wizard_app( $min, $ver );
$this->register_settings_app( $min, $ver );
$this->register_activity_log_app( $min, $ver );
$this->register_tools_app( $min, $ver );
$this->register_dashboard_app( $min, $ver );
$this->register_suppression_app( $min, $ver );
$this->container->add( self::GET_DASHBOARD_DATA_ENDPOINT, function() use ( $container ) {
$dashboard_config = $container->get( self::DASHBOARD_CONFIG );
return new Get_Dashboard_Data_Endpoint( $dashboard_config );
});
}
public function init( \Gravity_Forms\Gravity_Tools\Service_Container $container ) {
add_action( 'wp_ajax_' . Get_Dashboard_Data_Endpoint::ACTION_NAME, function () use ( $container ) {
$container->get( self::GET_DASHBOARD_DATA_ENDPOINT )->handle();
} );
}
protected function register_setup_wizard_app( $min, $ver ) {
$args = array(
'app_name' => 'setup-wizard',
'script_name' => 'gravitysmtp_scripts_admin',
'object_name' => 'gravitysmtp_admin_config',
'chunk' => './setup-wizard',
'enqueue' => $this->container->get( self::SHOULD_ENQUEUE_SETUP_WIZARD ),
'css' => array(
'handle' => 'setup_wizard_styles',
'src' => $this->plugin_url . "/assets/css/dist/setup-wizard{$min}.css",
'deps' => array( 'gravitysmtp_styles_base' ),
'ver' => $ver,
),
'root_element' => 'gravitysmtp-setup-wizard-root',
);
$this->register_app( $args );
}
protected function register_activity_log_app( $min, $ver ) {
$args = array(
'app_name' => 'activity-log',
'script_name' => 'gravitysmtp_scripts_admin',
'object_name' => 'gravitysmtp_admin_config',
'chunk' => './activity-log',
'enqueue' => array( $this, 'should_enqueue_activity_log' ),
'css' => array(
'handle' => 'activity_log_styles',
'src' => $this->plugin_url . "/assets/css/dist/activity-log{$min}.css",
'deps' => array( 'gravitysmtp_styles_base' ),
'ver' => $ver,
),
'root_element' => 'gravitysmtp-activity-log-app-root',
);
$this->register_app( $args );
}
protected function register_settings_app( $min, $ver ) {
$args = array(
'app_name' => 'settings',
'script_name' => 'gravitysmtp_scripts_admin',
'object_name' => 'gravitysmtp_admin_config',
'chunk' => './settings',
'enqueue' => array( $this, 'should_enqueue_settings' ),
'css' => array(
'handle' => 'settings_styles',
'src' => $this->plugin_url . "/assets/css/dist/settings{$min}.css",
'deps' => array( 'gravitysmtp_styles_base' ),
'ver' => $ver,
),
'root_element' => 'gravitysmtp-settings-app-root',
);
$this->register_app( $args );
}
protected function register_tools_app( $min, $ver ) {
$args = array(
'app_name' => 'tools',
'script_name' => 'gravitysmtp_scripts_admin',
'object_name' => 'gravitysmtp_admin_config',
'chunk' => './tools',
'enqueue' => array( $this, 'should_enqueue_tools' ),
'css' => array(
'handle' => 'tools_styles',
'src' => $this->plugin_url . "/assets/css/dist/tools{$min}.css",
'deps' => array( 'gravitysmtp_styles_base' ),
'ver' => $ver,
),
'root_element' => 'gravitysmtp-tools-app-root',
);
$this->register_app( $args );
}
protected function register_dashboard_app( $min, $ver ) {
$args = array(
'app_name' => 'dashboard',
'script_name' => 'gravitysmtp_scripts_admin',
'object_name' => 'gravitysmtp_admin_config',
'chunk' => './dashboard',
'enqueue' => array( $this, 'should_enqueue_dashboard' ),
'css' => array(
'handle' => 'dashboard_styles',
'src' => $this->plugin_url . "/assets/css/dist/dashboard{$min}.css",
'deps' => array( 'gravitysmtp_styles_base' ),
'ver' => $ver,
),
'root_element' => 'gravitysmtp-dashboard-app-root',
);
$this->register_app( $args );
}
protected function register_suppression_app( $min, $ver ) {
$args = array(
'app_name' => 'suppression',
'script_name' => 'gravitysmtp_scripts_admin',
'object_name' => 'gravitysmtp_admin_config',
'chunk' => './suppression',
'enqueue' => array( $this, 'should_enqueue_suppression' ),
'css' => array(
'handle' => 'suppression_styles',
'src' => $this->plugin_url . "/assets/css/dist/suppression{$min}.css",
'deps' => array( 'gravitysmtp_styles_base' ),
'ver' => $ver,
),
'root_element' => 'gravitysmtp-suppression-app-root',
);
$this->register_app( $args );
}
public function should_enqueue_dashboard() {
$enabled = Feature_Flag_Manager::is_enabled( self::FEATURE_FLAG_DASHBOARD );
if ( ! $enabled ) {
return false;
}
$page = filter_input( INPUT_GET, 'page' );
if ( ! is_string( $page ) ) {
return false;
}
$page = htmlspecialchars( $page );
return $page === 'gravitysmtp-dashboard';
}
public function should_enqueue_activity_log() {
$page = filter_input( INPUT_GET, 'page' );
if ( ! is_string( $page ) ) {
return false;
}
$page = htmlspecialchars( $page );
return $page === 'gravitysmtp-activity-log';
}
public function should_enqueue_settings() {
$page = filter_input( INPUT_GET, 'page' );
if ( ! is_string( $page ) ) {
return false;
}
$page = htmlspecialchars( $page );
return $page === 'gravitysmtp-settings';
}
public function should_enqueue_tools() {
$page = filter_input( INPUT_GET, 'page' );
if ( ! is_string( $page ) ) {
return false;
}
$page = htmlspecialchars( $page );
return $page === 'gravitysmtp-tools';
}
public function should_enqueue_suppression() {
$page = filter_input( INPUT_GET, 'page' );
if ( ! is_string( $page ) ) {
return false;
}
$page = htmlspecialchars( $page );
return $page === 'gravitysmtp-suppression';
}
protected function get_root_markup( $root ) {
return '<div class="gravity-app gravity-app--smtp gravitysmtp-app" data-js="' . $root . '"><div class="gform-loader__mask gform-loader__mask--theme-light"><svg class="gform-loader gform-loader--ring" height="64" width="64" viewBox="25 25 50 50" style="animation: 2s linear 0s infinite normal none running gformLoaderRotate; height: 64px; width: 64px;"><circle cx="50" cy="50" r="20" stroke-width="3.125" style="stroke: rgb(144, 146, 178);"></circle></svg></div></div>';
}
/**
* Use our custom action name to inject the app.
*
* @return string
*/
protected function get_inject_action() {
return 'gravitysmtp_app_body';
}
}
@@ -0,0 +1,185 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Apps\Config;
use Gravity_Forms\Gravity_SMTP\Alerts\Endpoints\Save_Alerts_Settings_Endpoint;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Save_Plugin_Settings_Endpoint;
use Gravity_Forms\Gravity_SMTP\Experimental_Features\Experiment_Features_Handler;
use Gravity_Forms\Gravity_SMTP\Gravity_SMTP;
use Gravity_Forms\Gravity_SMTP\Users\Roles;
use Gravity_Forms\Gravity_SMTP\Utils\Booliesh;
use Gravity_Forms\Gravity_Tools\Config;
class Apps_Config extends Config {
protected $script_to_localize = 'gravitysmtp_scripts_admin';
protected $name = 'gravitysmtp_admin_config';
public function data() {
$container = Gravity_SMTP::container();
$plugin_data_store = $container->get( Connector_Service_Provider::DATA_STORE_ROUTER );
$debug_log_enabled = $plugin_data_store->get_plugin_setting( Save_Plugin_Settings_Endpoint::PARAM_DEBUG_LOG_ENABLED, 'false' );
$debug_log_enabled = ! empty( $debug_log_enabled ) ? $debug_log_enabled !== 'false' : false;
$test_mode = $plugin_data_store->get_plugin_setting( Save_Plugin_Settings_Endpoint::PARAM_TEST_MODE );
$test_mode = ! empty( $test_mode ) ? $test_mode !== 'false' : false;
$usage_analytics_enabled = $plugin_data_store->get_plugin_setting( Save_Plugin_Settings_Endpoint::PARAM_USAGE_ANALYTICS, 'true' );
$usage_analytics_enabled = ! empty( $usage_analytics_enabled ) ? $usage_analytics_enabled !== 'false' : false;
// todo: @aaron from here to line 42, please refactor as you see fit. We need deep defaults maybe, or a pattern, and i need deep Booliesh hahaha unless what i did there is cool
$experimental_features = $plugin_data_store->get_plugin_setting( Experiment_Features_Handler::ENABLED_EXPERIMENTS_PARAM, array() );
if ( ! isset( $experimental_features[ 'alerts_management' ] ) ) {
$experimental_features[ 'alerts_management' ] = false;
}
foreach( $experimental_features as $feature => $enabled ) {
$experimental_features[ $feature ] = Booliesh::get( $enabled );
}
return array(
'common' => array(
'i18n' => array(
'aria_label_collapsed_metabox' => esc_html__( 'Expand', 'gravitysmtp' ),
'aria_label_expanded_metabox' => esc_html__( 'Collapse', 'gravitysmtp' ),
'confirm_change_cancel' => esc_html__( 'Cancel', 'gravitysmtp' ),
'confirm_change_confirm' => esc_html__( 'Confirm', 'gravitysmtp' ),
'debug_log_enabled' => esc_html__( 'Debug Log Enabled', 'gravitysmtp' ),
'test_mode_enabled' => esc_html__( 'Test Mode Enabled', 'gravitysmtp' ),
'setting_locked' => esc_html__( 'This setting is locked due to a defined constant and cannot be modified.', 'gravitysmtp' ),
'debug_messages' => array(
/* translators: %1$s is the body of the ajax request. */
'deleting_activity_log_rows' => esc_html__( 'Deleting activity log rows: %1$s', 'gravitysmtp' ),
/* translators: %1$s is the error. */
'deleting_activity_log_rows_error' => esc_html__( 'Error deleting activity log rows: %1$s', 'gravitysmtp' ),
/* translators: %1$s is the body of the ajax request. */
'deleting_all_debug_logs' => esc_html__( 'Deleting all debug logs: %1$s', 'gravitysmtp' ),
/* translators: %1$s is the error. */
'deleting_all_debug_logs_error' => esc_html__( 'Error deleting all debug logs: %1$s', 'gravitysmtp' ),
/* translators: %1$s is the active connector they are saving settings for, %2$s is the body of the ajax request. */
'saving_integration_settings' => esc_html__( 'Saving integration settings for the %1$s connector: %2$s', 'gravitysmtp' ),
/* translators: %1$s is the active connector they are saving settings for, %2$s is the error. */
'saving_integration_settings_error' => esc_html__( 'Error saving integration settings for the %1$s connector: %2$s', 'gravitysmtp' ),
/* translators: %1$s is the body of the ajax request. */
'saving_plugin_settings' => esc_html__( 'Saving plugin settings: %1$s', 'gravitysmtp' ),
/* translators: %1$s is the error. */
'saving_plugin_settings_error' => esc_html__( 'Error saving plugin settings: %1$s', 'gravitysmtp' ),
),
'general_settings_usage_analytics_label' => esc_html__( 'Share Gravity SMTP Analytics', 'gravitysmtp' ),
/* translators: {{learn_link}} tags are replaced by opening and closing tags for a link to our learn more page for usage */
'general_settings_usage_analytics_help_text' => esc_html__( 'We love improving the email sending experience for everyone in our community. By enabling analytics you can help us learn more about how our customers use Gravity SMTP. {{learn_link}}Learn more{{learn_link}}', 'gravitysmtp' ),
'snackbar_api_save_success' => esc_html__( 'API settings saved', 'gravitysmtp' ),
'snackbar_api_save_integration_enabled' => esc_html__( 'API settings saved and %1$s integration enabled', 'gravitysmtp' ),
'snackbar_generic_update_error' => esc_html__( 'Error saving setting', 'gravitysmtp' ),
'snackbar_generic_update_success' => esc_html__( 'Setting successfully updated', 'gravitysmtp' ),
'snackbar_send_test_mail_error' => esc_html__( 'Could not send test email; please check your logs', 'gravitysmtp' ),
'snackbar_send_test_mail_success' => esc_html__( 'Email successfully sent', 'gravitysmtp' ),
'snackbar_activity_log_delete_error' => esc_html__( 'Error deleting log entries', 'gravitysmtp' ),
'snackbar_email_log_error' => esc_html__( 'Error getting email log for requested page', 'gravitysmtp' ),
'snackbar_email_log_detail_generic_error' => esc_html__( 'Error getting email log details', 'gravitysmtp' ),
'snackbar_email_log_detail_empty_error' => esc_html__( 'Error getting email log details, the log data was empty', 'gravitysmtp' ),
'snackbar_email_log_delete_error' => esc_html__( 'Error deleting email log', 'gravitysmtp' ),
'snackbar_activity_log_delete_success' => esc_html__( 'Email log successfully deleted', 'gravitysmtp' ),
'snackbar_debug_log_delete_error' => esc_html__( 'Error deleting debug log', 'gravitysmtp' ),
'snackbar_debug_log_delete_success' => esc_html__( 'Debug log successfully deleted', 'gravitysmtp' ),
'snackbar_url_copied' => esc_html__( 'URL copied to clipboard', 'gravitysmtp' ),
'test_mode_warning_notice' => esc_html__( 'Test mode is enabled, emails will not be sent.', 'gravitysmtp' ),
),
'data' => array(
'constants' => array(
'CAPS_DELETE_DEBUG_LOG' => Roles::DELETE_DEBUG_LOG,
'CAPS_DELETE_EMAIL_LOG' => Roles::DELETE_EMAIL_LOG,
'CAPS_DELETE_EMAIL_LOG_DETAILS' => Roles::DELETE_EMAIL_LOG_DETAILS,
'CAPS_EDIT_ALERTS' => Roles::EDIT_ALERTS,
'CAPS_EDIT_ALERTS_SLACK_SETTINGS' => Roles::EDIT_ALERTS_SLACK_SETTINGS,
'CAPS_EDIT_ALERTS_TWILIO_SETTINGS' => Roles::EDIT_ALERTS_TWILIO_SETTINGS,
'CAPS_EDIT_DEBUG_LOG' => Roles::EDIT_DEBUG_LOG,
'CAPS_EDIT_EMAIL_LOG' => Roles::EDIT_EMAIL_LOG,
'CAPS_EDIT_EMAIL_LOG_DETAILS' => Roles::EDIT_EMAIL_LOG_DETAILS,
'CAPS_EDIT_EMAIL_LOG_SETTINGS' => Roles::EDIT_EMAIL_LOG_SETTINGS,
'CAPS_EDIT_DEBUG_LOG_SETTINGS' => Roles::EDIT_DEBUG_LOG_SETTINGS,
'CAPS_EDIT_EMAIL_MANAGEMENT_SETTINGS' => Roles::EDIT_EMAIL_MANAGEMENT_SETTINGS,
'CAPS_EDIT_GENERAL_SETTINGS' => Roles::EDIT_GENERAL_SETTINGS,
'CAPS_EDIT_INTEGRATIONS' => Roles::EDIT_INTEGRATIONS,
'CAPS_EDIT_LICENSE_KEY' => Roles::EDIT_LICENSE_KEY,
'CAPS_EDIT_EXPERIMENTAL_FEATURES' => Roles::EDIT_EXPERIMENTAL_FEATURES,
'CAPS_EDIT_NOTIFICATIONS_SETTINGS' => Roles::EDIT_NOTIFICATIONS_SETTINGS,
'CAPS_EDIT_TEST_MODE' => Roles::EDIT_TEST_MODE,
'CAPS_EDIT_UNINSTALL' => Roles::EDIT_UNINSTALL,
'CAPS_EDIT_USAGE_ANALYTICS' => Roles::EDIT_USAGE_ANALYTICS,
'CAPS_VIEW_ALERTS' => Roles::VIEW_ALERTS,
'CAPS_VIEW_ALERTS_SLACK_SETTINGS' => Roles::VIEW_ALERTS_SLACK_SETTINGS,
'CAPS_VIEW_ALERTS_TWILIO_SETTINGS' => Roles::VIEW_ALERTS_TWILIO_SETTINGS,
'CAPS_VIEW_DEBUG_LOG' => Roles::VIEW_DEBUG_LOG,
'CAPS_VIEW_EMAIL_LOG' => Roles::VIEW_EMAIL_LOG,
'CAPS_VIEW_EMAIL_LOG_DETAILS' => Roles::VIEW_EMAIL_LOG_DETAILS,
'CAPS_VIEW_EMAIL_LOG_PREVIEW' => Roles::VIEW_EMAIL_LOG_PREVIEW,
'CAPS_VIEW_EMAIL_LOG_SETTINGS' => Roles::VIEW_EMAIL_LOG_SETTINGS,
'CAPS_VIEW_DEBUG_LOG_SETTINGS' => Roles::VIEW_DEBUG_LOG_SETTINGS,
'CAPS_VIEW_EMAIL_MANAGEMENT_SETTINGS' => Roles::VIEW_EMAIL_MANAGEMENT_SETTINGS,
'CAPS_VIEW_GENERAL_SETTINGS' => Roles::VIEW_GENERAL_SETTINGS,
'CAPS_VIEW_INTEGRATIONS' => Roles::VIEW_INTEGRATIONS,
'CAPS_VIEW_LICENSE_KEY' => Roles::VIEW_LICENSE_KEY,
'CAPS_VIEW_EXPERIMENTAL_FEATURES' => Roles::VIEW_EXPERIMENTAL_FEATURES,
'CAPS_VIEW_NOTIFICATIONS_SETTINGS' => Roles::VIEW_NOTIFICATIONS_SETTINGS,
'CAPS_VIEW_TEST_MODE' => Roles::VIEW_TEST_MODE,
'CAPS_VIEW_TOOLS' => Roles::VIEW_TOOLS,
'CAPS_VIEW_TOOLS_SENDATEST' => Roles::VIEW_TOOLS_SENDATEST,
'CAPS_VIEW_TOOLS_SYSTEMREPORT' => Roles::VIEW_TOOLS_SYSTEMREPORT,
'CAPS_VIEW_UNINSTALL' => Roles::VIEW_UNINSTALL,
'CAPS_VIEW_USAGE_ANALYTICS' => Roles::VIEW_USAGE_ANALYTICS,
'CAPS_VIEW_DASHBOARD' => Roles::VIEW_DASHBOARD,
),
'debug_log_enabled' => $debug_log_enabled,
'experimental_features' => $experimental_features,
'param_keys' => array(
'alert_threshold_count' => Save_Alerts_Settings_Endpoint::PARAM_ALERT_THRESHOLD_COUNT,
'alert_threshold_interval' => Save_Alerts_Settings_Endpoint::PARAM_ALERT_THRESHOLD_INTERVAL,
'debug_log_enabled' => Save_Plugin_Settings_Endpoint::PARAM_DEBUG_LOG_ENABLED,
'debug_log_retention' => Save_Plugin_Settings_Endpoint::PARAM_DEBUG_LOG_RETENTION,
'enabled_experimental_features' => Experiment_Features_Handler::ENABLED_EXPERIMENTS_PARAM,
'event_log_enabled' => Save_Plugin_Settings_Endpoint::PARAM_EVENT_LOG_ENABLED,
'event_log_retention' => Save_Plugin_Settings_Endpoint::PARAM_EVENT_LOG_RETENTION,
'license_key' => Save_Plugin_Settings_Endpoint::PARAM_LICENSE_KEY,
'notifications_email_digest_enabled' => Save_Plugin_Settings_Endpoint::PARAM_NOTIFICATIONS_EMAIL_DIGEST_ENABLED,
'notifications_email_digest_frequency' => Save_Plugin_Settings_Endpoint::PARAM_NOTIFICATIONS_EMAIL_DIGEST_FREQUENCY,
'notify_when_email_sending_fails_enabled' => Save_Plugin_Settings_Endpoint::PARAM_NOTIFY_WHEN_EMAIL_SENDING_FAILS_ENABLED,
'save_attachments_enabled' => Save_Plugin_Settings_Endpoint::PARAM_SAVE_ATTACHMENTS_ENABLED,
'save_email_body_enabled' => Save_Plugin_Settings_Endpoint::PARAM_SAVE_EMAIL_BODY_ENABLED,
'slack_alerts' => Save_Alerts_Settings_Endpoint::PARAM_SLACK_ALERTS,
'slack_alerts_enabled' => Save_Plugin_Settings_Endpoint::PARAM_SLACK_ALERTS_ENABLED,
'test_mode' => Save_Plugin_Settings_Endpoint::PARAM_TEST_MODE,
'twilio_alerts' => Save_Alerts_Settings_Endpoint::PARAM_TWILIO_ALERTS,
'twilio_alerts_enabled' => Save_Plugin_Settings_Endpoint::PARAM_TWILIO_ALERTS_ENABLED,
'usage_analytics' => Save_Plugin_Settings_Endpoint::PARAM_USAGE_ANALYTICS,
),
'locked_settings' => $this->get_locked_settings(),
'test_mode_enabled' => $test_mode,
'usage_analytics_enabled' => $usage_analytics_enabled,
'usage_analytics_link' => 'https://docs.gravitysmtp.com/about-additional-data-collection/',
),
),
'hmr_dev' => defined( 'GRAVITYSMTP_ENABLE_HMR' ) && GRAVITYSMTP_ENABLE_HMR,
'public_path' => trailingslashit( Gravity_SMTP::get_base_url() ) . 'assets/js/dist/',
);
}
private function get_locked_settings() {
$return = array();
$defined_constants = array_filter( get_defined_constants(), function( $constant ) {
return strpos( $constant, 'GRAVITYSMTP_' ) !== false;
}, ARRAY_FILTER_USE_KEY );
foreach( $defined_constants as $constant => $constant_value ) {
$setting_name = strtolower( str_replace( 'GRAVITYSMTP_', '', $constant ) );
$return[] = $setting_name;
}
return $return;
}
}
@@ -0,0 +1,572 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Apps\Config;
use Gravity_Forms\Gravity_SMTP\Apps\App_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Apps\Endpoints\Get_Dashboard_Data_Endpoint;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Data_Store\Data_Store_Router;
use Gravity_Forms\Gravity_SMTP\Feature_Flags\Feature_Flag_Manager;
use Gravity_Forms\Gravity_SMTP\Gravity_SMTP;
use Gravity_Forms\Gravity_SMTP\Models\Event_Model;
use Gravity_Forms\Gravity_SMTP\Utils\Booliesh;
use Gravity_Forms\Gravity_Tools\Config;
use Gravity_Forms\Gravity_Tools\Config_Data_Parser;
class Dashboard_Config extends Config {
const DEFAULT_DATE_RANGE_INTERVAL = 90;
protected $script_to_localize = 'gravitysmtp_scripts_admin';
protected $name = 'gravitysmtp_admin_config';
protected $overwrite = false;
private $start;
private $end;
private $period;
/**
* @var Event_Model
*/
private $model;
public function __construct( Config_Data_Parser $parser ) {
parent::__construct( $parser );
/**
* @var Data_Store_Router $settings
*/
$settings = Gravity_SMTP::$container->get( Connector_Service_Provider::DATA_STORE_ROUTER );
$this->model = Gravity_SMTP::$container->get( Connector_Service_Provider::EVENT_MODEL );
}
public function should_enqueue() {
$enabled = Feature_Flag_Manager::is_enabled( App_Service_Provider::FEATURE_FLAG_DASHBOARD );
if ( ! $enabled ) {
return false;
}
$page = filter_input( INPUT_GET, 'page' );
if ( ! is_string( $page ) ) {
return false;
}
$page = htmlspecialchars( $page );
return $page === 'gravitysmtp-dashboard';
}
public function data() {
$mod_string = sprintf( '-%d days', self::DEFAULT_DATE_RANGE_INTERVAL );
// Default to Last 3 Months
$this->start = gmdate( 'Y-m-d 00:00:00', strtotime( $mod_string ) );
// Get minimum start date based on data.
$this->start = $this->get_min_start_date( true );
$this->end = gmdate( 'Y-m-d 23:59:59', strtotime( "+1 day") );
// Determine proper period to use.
$this->period = $this->get_period_from_ranges();
return array(
'common' => array(
'endpoints' => array(
Get_Dashboard_Data_Endpoint::ACTION_NAME => array(
'action' => array(
'value' => Get_Dashboard_Data_Endpoint::ACTION_NAME,
'default' => 'mock_endpoint',
),
'nonce' => array(
'value' => wp_create_nonce( Get_Dashboard_Data_Endpoint::ACTION_NAME ),
'default' => 'nonce',
),
),
)
),
'components' => array(
'dashboard' => array(
'i18n' => $this->i18n_values(),
'data' => $this->data_values(),
),
)
);
}
public function ajax_data( $start, $end, $period ) {
$this->start = $start;
$this->end = $end;
if ( is_numeric( $period ) ) {
switch( $period ) {
case 0:
default:
$period = $this->get_period_from_ranges();
break;
case 1:
$period = 'hour';
break;
case 7:
$period = 'day';
break;
case 30:
case 90:
case 180:
$period = 'day';
break;
case 365:
$period = 'month';
break;
}
}
$this->period = $period;
return $this->data_values();
}
protected function get_period_from_ranges() {
$start = date_create( $this->start );
$end = date_create( $this->end );
$interval = date_diff( $start, $end );
$diff = $interval->format( '%a' );
if ( $diff <= 1 ) {
return 'hour';
}
if ( $diff < 180 ) {
return 'day';
}
return 'month';
}
protected function i18n_values() {
return array(
'totals' => array(
'headings' => array(
'emails' => __( 'Processed', 'gravitysmtp' ),
'sent' => __( 'Sent', 'gravitysmtp' ),
'failed' => __( 'Failed', 'gravitysmtp' ),
),
),
'stats' => array(
'heading' => __( 'Email Overview', 'gravitystmp' ),
'no_data_heading' => __( 'This is where your email statistics will appear.', 'gravitysmtp' ),
'no_data_message' => __( 'No data for the selected date range.', 'gravitysmtp' ),
'checkboxes' => array(
'sent' => __( 'Sent', 'gravitysmtp' ),
'failed' => __( 'Failed', 'gravitysmtp' ),
),
'date_range_label' => __( 'Date Range', 'gravitysmtp' ),
'calendar_label' => __( 'Custom Date', 'gravitysmtp' ),
),
'rankings' => array(
'headings' => array(
'your_integrations' => __( 'Your Integrations', 'gravitysmtp' ),
'sources' => __( 'Top Sending Sources', 'gravitysmtp' ),
'recipients' => __( 'Top Email Recipients', 'gravitysmtp' ),
'quick_links' => __( 'Quick Links', 'gravitysmtp' ),
),
'email' => __( '%1$s Email', 'gravitysmtp' ),
'emails' => __( '%1$s Emails', 'gravitysmtp' ),
'tags' => array(
'primary' => __( 'Primary', 'gravitysmtp' ),
'backup' => __( 'Backup', 'gravitysmtp' ),
'connected' => __( 'Connected', 'gravitysmtp' ),
'configured' => __( 'Configured', 'gravitysmtp' ),
'not_configured' => __( 'Not Configured', 'gravitysmtp' ),
),
),
);
}
protected function data_values() {
$totals = $this->get_email_totals();
return array(
'totals' => $totals,
'chart' => $this->get_chart_data(),
'date_ranges' => array(
'options' => $this->get_date_options(),
'initial_value' => $this->get_initial_range_value_from_data( true ),
'min_start' => $this->model->get_earliest_event_date(),
'max_end' => get_date_from_gmt( $this->end ),
),
'integrations_url' => admin_url( 'admin.php?page=gravitysmtp-settings&tab=integrations&integration=%1$s' ),
'source_icons_url' => trailingslashit( GF_GRAVITY_SMTP_PLUGIN_URL ) . 'assets/images/plugin-icons/',
'rankings' => array(
'your_integrations' => $this->get_your_integrations_info(),
'sources' => $this->get_top_sending_sources(),
'recipients' => $this->get_top_email_recipients(),
'quick_links' => $this->get_quick_links(),
),
);
}
protected function get_initial_range_value_from_data( $respect_default = false ) {
$diff = $this->get_max_interval_diff();
$options = array( 1, 7, 30, 90, 180, 365 );
$value = 365;
foreach ( $options as $option ) {
if ( $diff <= $option ) {
$value = $option;
break;
}
}
if ( $respect_default && $value > self::DEFAULT_DATE_RANGE_INTERVAL ) {
return self::DEFAULT_DATE_RANGE_INTERVAL;
}
return $value;
}
protected function get_date_options() {
$diff = $this->get_max_interval_diff();
$options = array(
array(
'label' => __( 'Last Day', 'gravitysmtp' ),
'value' => 1,
),
array(
'label' => __( 'Last 7 Days', 'gravitysmtp' ),
'value' => 7,
),
array(
'label' => __( 'Last 30 Days', 'gravitysmtp' ),
'value' => 30,
),
array(
'label' => __( 'Last 90 Days', 'gravitysmtp' ),
'value' => 90,
),
array(
'label' => __( 'Last 180 Days', 'gravitysmtp' ),
'value' => 180,
),
array(
'label' => __( 'Last 365 Days', 'gravitysmtp' ),
'value' => 365,
),
);
if ( $diff <= 1 ) {
$options = array(
reset( $options ),
);
return $options;
}
$parsed_options = array();
foreach ( $options as $key => $option ) {
$value = $option['value'];
$next = isset( $options[ $key + 1 ] ) ? $options[ $key + 1 ]['value'] : - 1;
if ( $diff >= $value ) {
$parsed_options[] = $option;
} else {
continue;
}
if ( $diff < $next ) {
$parsed_options[] = $options[ $key + 1 ];
}
}
return array_values( $parsed_options );
}
private function get_max_interval_diff() {
$earliest_date = date_create( $this->model->get_earliest_event_date() );
$today = date_create( date( 'Y:m:d 23:59:59' ) );
$interval = date_diff( $earliest_date, $today );
return (int) $interval->format( '%a' );
}
protected function get_chart_data() {
$data = $this->model->get_chart_data( $this->start, $this->end );
list( $format ) = $this->get_date_format_and_interval();
$sorted = array_reduce(
$data,
function( $carry, $item ) use ( $format ) {
$key = get_date_from_gmt( $item['date_created'], $format );
if ( ! array_key_exists( $key , $carry ) ) {
$carry[ $key ] = array(
'sent' => 0,
'failed' => 0,
);
}
if ( $item['status'] === 'sent' ) {
$carry[ $key ]['sent'] += 1;
} elseif ( $item['status'] === 'failed' ) {
$carry[ $key ]['failed'] += 1;
}
return $carry;
},
array()
);
// $sorted = array();
//
// foreach( $data as $datum ) {
// if ( ! array_key_exists( $datum['date_created'], $sorted ) ) {
// $sorted[ $datum['date_created'] ] = array(
// 'sent' => 0,
// 'failed' => 0,
// );
// }
//
// if ( $datum['status'] !== 'sent' && $datum['status'] !== 'failed' ) {
// continue;
// }
//
// $sorted[ $datum['date_created'] ][ $datum['status'] ] += $datum['total'];
// }
$sorted = $this->pad_with_empty_values( $sorted );
$chart_data = array();
foreach ( $sorted as $date => $values ) {
$chart_data[] = array(
'xAxisKey' => $date,
'sent' => $values['sent'],
'failed' => $values['failed'],
);
}
return array(
'config' => array(
'start' => $this->get_min_start_date(),
'end' => get_date_from_gmt( $this->end ),
'period' => $this->period
),
'values' => $chart_data,
'datasets' => array(
array(
'label' => __( 'Sent', 'gravitysmtp' ),
'dataKey' => 'sent',
'color' => '#82ca9d',
'defaultChecked' => true
),
array(
'label' => __( 'Failed', 'gravitysmtp' ),
'dataKey' => 'failed',
'color' => '#ff6b6b',
'defaultChecked' => true
),
),
);
}
protected function pad_with_empty_values( $data ) {
// Don't pad empty results.
if ( empty( $data ) ) {
return $data;
}
list( $format, $interval ) = $this->get_date_format_and_interval();
$period = new \DatePeriod(
new \DateTime( get_date_from_gmt( $this->start ) ),
new \DateInterval( $interval ),
new \DateTime( get_date_from_gmt( $this->end ) )
);
$sorted_values = array();
foreach( $period as $key => $value ) {
$date = $value->format( $format );
if ( ! array_key_exists( $date, $data ) ) {
$sorted_values[ $date ] = array(
'sent' => 0,
'failed' => 0,
);
} else {
$sorted_values[ $date ] = $data[ $date ];
}
}
return $sorted_values;
}
protected function get_date_format_and_interval() {
switch( $this->period ) {
case 'day':
default:
$format = 'M d';
$interval = 'P1D';
break;
case 'month':
$format = 'M Y';
$interval = 'P1M';
break;
case 'hour':
$format = 'H:00 M d';
$interval = 'PT1H';
break;
}
return array( $format, $interval );
}
protected function get_email_totals() {
$stats = $this->model->get_event_stats( $this->start, $this->end );
$total = array_sum( $stats );
return array(
'emails' => $total,
'sent' => isset( $stats['sent'] ) ? $stats['sent'] : 0,
'failed' => isset( $stats['failed'] ) ? $stats['failed'] : 0,
);
}
protected function get_top_sending_sources() {
$sources = $this->model->get_top_sending_sources( $this->start, $this->end );
// Some old entries are missing the source param and return the `headers` instead.
$sources = array_filter( $sources, function ( $data ) {
return $data['source'] !== 'headers' && $data['source'] !== 'message_omitted';
} );
return array_values( $sources );
}
protected function get_top_email_recipients() {
$recipients = $this->model->get_top_recipients( $this->start, $this->end );
array_walk( $recipients, function ( &$item ) {
$item['hash'] = hash( 'sha256', $item['recipients'] );
} );
$recipients = array_filter( $recipients, function ( $data ) {
return $data['recipients'] !== 'headers' && $data['recipients'] !== 'message_omitted' && ! empty( $data['recipients'] );
} );
return array_values( $recipients );
}
protected function get_your_integrations_info() {
$connector_data = Gravity_SMTP::$container->get( Connector_Service_Provider::CONNECTOR_DATA_MAP );
$return = array();
$connector_data = array_filter( $connector_data, function ( $info ) {
return $info['data']['enabled'] && $info['data']['activated'];
} );
foreach ( $connector_data as $connector => $info ) {
$data = $info['data'];
$return[] = array(
'is_primary' => $data['is_primary'],
'is_backup' => $data['is_backup'],
'configured' => $data['configured'],
'name' => $connector,
'label' => $info['title'],
'logo' => $info['logo'],
);
}
usort( $return, function ( $a, $b ) {
if ( $a['is_primary'] && $b['is_primary'] ) {
return 0;
}
if ( $a['is_backup'] && $b['is_backup'] ) {
return 0;
}
if ( $a['is_primary'] && $b['is_backup'] ) {
return - 1;
}
if ( $a['is_backup'] && $b['is_primary'] ) {
return 1;
}
if ( $a['is_primary'] ) {
return - 1;
}
if ( $a['is_backup'] ) {
return - 1;
}
return 1;
} );
return $return;
}
protected function get_quick_links() {
// @todo - get actual values.
return array(
array(
'label' => __( 'Getting Started', 'gravitysmtp' ),
'href' => 'https://docs.gravitysmtp.com/category/getting-started/',
),
array(
'label' => __( 'Troubleshooting Gravity SMTP', 'gravitysmtp' ),
'href' => 'https://docs.gravitysmtp.com/troubleshooting-gravity-smtp/',
),
array(
'label' => __( 'Email Delivery Best Practices', 'gravitysmtp' ),
'href' => 'https://docs.gravitysmtp.com/email-delivery-best-practices/',
),
array(
'label' => __( 'An Overview of Gravity SMTP', 'gravitysmtp' ),
'href' => 'https://docs.gravitysmtp.com/using-gravity-smtp/',
),
array(
'label' => __( 'Integrations', 'gravitysmtp' ),
'href' => 'https://docs.gravitysmtp.com/category/integrations/',
),
array(
'label' => __( 'Frequently Asked Questions', 'gravitysmtp' ),
'href' => 'https://docs.gravitysmtp.com/frequently-asked-questions/',
),
array(
'label' => __( 'Gravity SMTP Changelog', 'gravitysmtp' ),
'href' => 'https://docs.gravitysmtp.com/gravity-smtp-changelog/',
),
array(
'label' => __( 'Open Support Ticket', 'gravitysmtp' ),
'href' => 'https://www.gravityforms.com/open-support-ticket/',
),
);
}
private function get_min_start_date( $restrict_to_range = false ) {
$earliest_date = $this->model->get_earliest_event_date();
$passed_start = strtotime( $this->start );
$calculated_start = strtotime( $earliest_date );
// Passed start is after the minimum retention period start, return it.
if ( $calculated_start <= $passed_start ) {
return get_date_from_gmt( $this->start );
}
if ( ! $restrict_to_range ) {
return $earliest_date;
}
// Passed start is *before* minimum retention period start, return retention period start.
$range_diff = $this->get_initial_range_value_from_data();
$mod_string = sprintf( '-%d days', ( $range_diff - 1 ) );
return gmdate( 'Y-m-d 00:00:00', strtotime( $mod_string ) );
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,196 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Apps\Config;
use Gravity_Forms\Gravity_SMTP\Apps\App_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Gravity_SMTP;
use Gravity_Forms\Gravity_Tools\Config;
class Email_Log_Single_Config extends Config {
protected $script_to_localize = 'gravitysmtp_scripts_admin';
protected $name = 'gravitysmtp_admin_config';
protected $overwrite = false;
public function should_enqueue() {
if ( ! is_admin() ) {
return false;
}
$page = filter_input( INPUT_GET, 'page' );
if ( ! is_string( $page ) ) {
return false;
}
$page = htmlspecialchars( $page );
$event_id = filter_input( INPUT_GET, 'event_id', FILTER_SANITIZE_NUMBER_INT );
if ( $page !== 'gravitysmtp-activity-log' || empty( $event_id ) ) {
return false;
}
return true;
}
public function get_i18n() {
return array(
'error_alert_title' => esc_html__( 'Error Saving', 'gravitysmtp' ),
'error_alert_generic_message' => esc_html__( 'Could not save; please check your logs.', 'gravitysmtp' ),
'error_alert_close_text' => esc_html__( 'Close', 'gravitysmtp' ),
'log_detail' => array(
'top_heading' => esc_html__( 'Email Log Details', 'gravitysmtp' ),
// 'top_content' => esc_html__( '', 'gravitysmtp' ),
'top_error' => esc_html__( 'The email could not be found, go back and try again.', 'gravitysmtp' ),
'action_button_view_email_label' => esc_html__( 'View Email', 'gravitysmtp' ),
'action_button_resend_label' => esc_html__( 'Resend', 'gravitysmtp' ),
'action_button_print_label' => esc_html__( 'Print', 'gravitysmtp' ),
'action_button_export_label' => esc_html__( 'Export', 'gravitysmtp' ),
'action_button_delete_label' => esc_html__( 'Delete Log Entry', 'gravitysmtp' ),
'back_button_label' => esc_html__( 'Back to Email Log', 'gravitysmtp' ),
'main_box_heading' => esc_html__( 'Email Details', 'gravitysmtp' ),
'main_box_bcc_label' => esc_html__( 'BCC', 'gravitysmtp' ),
'main_box_cc_label' => esc_html__( 'CC', 'gravitysmtp' ),
'main_box_date_label' => esc_html__( 'Date Sent', 'gravitysmtp' ),
'main_box_from_label' => esc_html__( 'From', 'gravitysmtp' ),
'main_box_to_label' => esc_html__( 'To', 'gravitysmtp' ),
'main_box_subject_label' => esc_html__( 'Subject', 'gravitysmtp' ),
'nav_button_next_title' => esc_html__( 'Navigate to the next log detail', 'gravitysmtp' ),
'nav_button_prev_title' => esc_html__( 'Navigate to the previous log detail', 'gravitysmtp' ),
'secondary_box_heading' => esc_html__( 'Technical Information', 'gravitysmtp' ),
'secondary_box_log_heading' => esc_html__( 'Log', 'gravitysmtp' ),
'secondary_box_headers_heading' => esc_html__( 'Headers', 'gravitysmtp' ),
'sidebar_status_heading' => esc_html__( 'Log Details', 'gravitysmtp' ),
'sidebar_status_label' => esc_html__( 'Status:', 'gravitysmtp' ),
'sidebar_service_label' => esc_html__( 'Service:', 'gravitysmtp' ),
'sidebar_has_attachment_label' => esc_html__( 'Has attachment:', 'gravitysmtp' ),
'sidebar_log_id_label' => esc_html__( 'Log ID:', 'gravitysmtp' ),
'sidebar_source_label' => esc_html__( 'Source:', 'gravitysmtp' ),
'sidebar_attachments_heading' => esc_html__( 'Attachments', 'gravitysmtp' ),
'view_email_desktop_mode' => esc_html__( 'Preview email in desktop mode', 'gravitysmtp' ),
'view_email_mobile_mode' => esc_html__( 'Preview email in mobile mode', 'gravitysmtp' ),
),
/* translators: %1$s is the body of the ajax request. */
'resending_email' => esc_html__( 'Resending email: %1$s', 'gravitysmtp' ),
/* translators: %1$s is the error message. */
'resending_error' => esc_html__( 'Error resending email: %1$s', 'gravitysmtp' ),
'snackbar_resend_error' => esc_html__( 'Error resending email', 'gravitysmtp' ),
'snackbar_resend_success' => esc_html__( 'Email successfully resent', 'gravitysmtp' ),
);
}
public function get_log_single_data() {
return array(
'log_detail' => array(
'default' => $this->get_default_log_details(),
'value' => $this->get_log_details(),
),
);
}
private function get_default_log_data() {
$headers = array(
'body' => array(
'to' => 'someuser@its.rochester.edu',
'subject' => 'My mail message is about.',
),
'headers' => array(
'from: somesender@mail.rochester.edu',
'content-type: text/html',
),
);
$text = 'Received: from antivirus1.its.rochester.edu (antivirus.its.rochester.edu [128.151.57.50])
by mail.rochester.edu (8.12.8/8.12.4) with ESMTP id h20GQs90002563;
Mon, 24 Mar 2003 11:26:54 -0500 (EST)
Received: from antivirus.its.rochester.edu (localhost [127.0.0.1])
by antivirus1.its.rochester.edu (8.12.8/8.12.4) with ESMTP id h20GOr0x003450;
Mon, 24 Mar 2003 11:26:54 -0500 (EST)
Received: from galileo.cc.rochester.edu (galileo.cc.rochester.edu [128.151.224.6])
by antivirus1.its.rochester.edu (8.12.8/8.12.4) with SMTP id h20GOrDC003447;
Mon, 24 Mar 2003 11:26:53 -0500 (EST)
Received: (from majord@localhost)
by galileo.cc.rochester.edu (8.12.8/8.12.4) id h20GQg91029757;
Mon, 24 Mar 2003 11:26:52 -0500 (EST)
Date: Mon, 24 Mar 2003 11:26:50 -0500 (EST)
From: somesender@mail.rochester.edu
Message-Id: <200303241626.h20GQoit002507@mail.rochester.edu>
To: someuser@its.rochester.edu
Subject: My mail message is about.';
$lines = explode( "\n", $text );
$temp_log_detail_techincal_data = array();
foreach ( $lines as $index => $line ) {
$temp_log_detail_techincal_data[ $index ] = $line;
}
return array(
'log' => $temp_log_detail_techincal_data,
'headers' => $headers,
);
}
private function get_default_log_details() {
return array(
'date' => 'March 7, 2023 at 8:07 pm',
'from' => 'carl@gmail.com',
'to' => 'carl@hancock.io',
'subject' => 'New WordPress User Registration',
'technical_information' => $this->get_default_log_data(),
'status' => array(
'label' => 'Sent',
'status' => 'active',
),
'service' => 'Amazon SES',
'has_attachment' => 3,
'attachments' => array(
array(
'file_name' => 'test.pdf',
'file_path' => 'http://example.com/wp-content/uploads/gravity_forms/2023/08/test.pdf',
'file_extension' => 'pdf',
),
array(
'file_name' => 'test2.pdf',
'file_path' => 'http://example.com/wp-content/uploads/gravity_forms/2023/08/test2.pdf',
'file_extension' => 'pdf',
),
array(
'file_name' => 'test3.pdf',
'file_path' => 'http://example.com/wp-content/uploads/gravity_forms/2023/08/test3.pdf',
'file_extension' => 'pdf',
),
),
'log_id' => '12',
'source' => 'Gravity Forms',
);
}
private function get_log_details() {
$id = filter_input( INPUT_GET, 'event_id', FILTER_SANITIZE_NUMBER_INT );
if ( empty( $id ) ) {
return array();
}
$container = Gravity_SMTP::container();
$logs = $container->get( Connector_Service_Provider::LOG_DETAILS_MODEL );
return $logs->full_details( $id );
}
public function data() {
$log_config = Gravity_SMTP::container()->get( App_Service_Provider::EMAIL_LOG_CONFIG );
return array(
'components' => array(
'activity_log' => array(
'data' => array_merge( $this->get_log_single_data(), $log_config->get_log_data() ),
'i18n' => array_merge( $this->get_i18n(), $log_config->get_i18n() ),
'endpoints' => array(),
),
),
);
}
}
@@ -0,0 +1,629 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Apps\Config;
use Gravity_Forms\Gravity_SMTP\Gravity_SMTP;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Save_Plugin_Settings_Endpoint;
use Gravity_Forms\Gravity_SMTP\Users\Roles;
use Gravity_Forms\Gravity_SMTP\Utils\Booliesh;
use Gravity_Forms\Gravity_Tools\Config;
use Gravity_Forms\Gravity_Tools\License\License_Statuses;
use Gravity_Forms\Gravity_Tools\Updates\Updates_Service_Provider;
class Settings_Config extends Config {
protected $script_to_localize = 'gravitysmtp_scripts_admin';
protected $name = 'gravitysmtp_admin_config';
protected $overwrite = false;
public function should_enqueue() {
if ( ! is_admin() ) {
return false;
}
$page = filter_input( INPUT_GET, 'page' );
if ( ! is_string( $page ) ) {
return false;
}
$page = htmlspecialchars( $page );
if ( $page !== 'gravitysmtp-settings' ) {
return false;
}
return true;
}
public function data() {
$container = Gravity_SMTP::container();
$plugin_data_store = $container->get( Connector_Service_Provider::DATA_STORE_ROUTER );
$license_key = $plugin_data_store->get_plugin_setting( Save_Plugin_Settings_Endpoint::PARAM_LICENSE_KEY, '' );
$key_is_empty = empty( $license_key );
$is_valid = null;
if ( ! $key_is_empty ) {
$license_info = $container->get( Updates_Service_Provider::LICENSE_API_CONNECTOR )->check_license( $license_key );
$is_valid = License_Statuses::VALID_KEY === $license_info->get_status();
}
$email_log_enabled = Booliesh::get( $plugin_data_store->get_plugin_setting( Save_Plugin_Settings_Endpoint::PARAM_EVENT_LOG_ENABLED, 'true' ) );
$save_email_body_enabled = Booliesh::get( $plugin_data_store->get_plugin_setting( Save_Plugin_Settings_Endpoint::PARAM_SAVE_EMAIL_BODY_ENABLED, 'true' ) );
$save_attachments_enabled = Booliesh::get( $plugin_data_store->get_plugin_setting( Save_Plugin_Settings_Endpoint::PARAM_SAVE_ATTACHMENTS_ENABLED, 'false' ) );
$email_log_retention = $plugin_data_store->get_plugin_setting( Save_Plugin_Settings_Endpoint::PARAM_EVENT_LOG_RETENTION, 7 );
$max_records_value = $plugin_data_store->get_plugin_setting( Save_Plugin_Settings_Endpoint::PARAM_MAX_EVENT_RECORDS, 0 );
$debug_log_enabled = $plugin_data_store->get_plugin_setting( Save_Plugin_Settings_Endpoint::PARAM_DEBUG_LOG_ENABLED, 'false' );
$debug_log_enabled = ! empty( $debug_log_enabled ) ? $debug_log_enabled !== 'false' : false;
$debug_log_retention = $plugin_data_store->get_plugin_setting( Save_Plugin_Settings_Endpoint::PARAM_DEBUG_LOG_RETENTION, 7 );
$notifications_email_digest_enabled = $plugin_data_store->get_plugin_setting( Save_Plugin_Settings_Endpoint::PARAM_NOTIFICATIONS_EMAIL_DIGEST_ENABLED, 'false' );
$notifications_email_digest_enabled = ! empty( $notifications_email_digest_enabled ) ? $notifications_email_digest_enabled !== 'false' : false;
$notifications_email_digest_frequency = $plugin_data_store->get_plugin_setting( Save_Plugin_Settings_Endpoint::PARAM_NOTIFICATIONS_EMAIL_DIGEST_FREQUENCY, 7 );
$primary_locked = defined( 'GRAVITYSMTP_INTEGRATION_PRIMARY' );
$backup_locked = defined( 'GRAVITYSMTP_INTEGRATION_BACKUP' );
// @translators: %d is an integer representing the maximum number of records to store in the log.
$max_records_message = esc_html__( 'The Email Log is set to store a maximum of %d records. Any records over that limit will be deleted, starting with oldest records first.', 'gravitysmtp' );
return array(
'components' => array(
'settings' => array(
'i18n' => array(
'error_alert_title' => esc_html__( 'Error Saving', 'gravitysmtp' ),
'error_alert_generic_message' => esc_html__( 'Could not save, please check your logs.', 'gravitysmtp' ),
'error_alert_close_text' => esc_html__( 'Close', 'gravitysmtp' ),
'debug_messages' => array(
/* translators: %1$s is the body of the ajax request. */
'uninstalling_plugin' => esc_html__( 'Uninstalling plugin: %1$s', 'gravitysmtp' ),
/* translators: %1$s is the error. */
'uninstalling_plugin_error' => esc_html__( 'Error uninstalling plugin: %1$s', 'gravitysmtp' ),
),
'unsaved_changes_title' => esc_html__( 'Unsaved Changes', 'gravitysmtp' ),
'unsaved_changes_message' => esc_html__( 'You have unsaved changes. Are you sure you want to leave this page?', 'gravitysmtp' ),
'settings' =>
array(
'top_heading' => esc_html__( 'Settings', 'gravitysmtp' ),
'top_content' => '',
'license_box_heading' => esc_html__( 'License', 'gravitysmtp' ),
'license_box_content' => esc_html__( 'A valid license key is required for access to automatic plugin upgrades and product support.', 'gravitysmtp' ),
'license_box_input_label' => esc_html__( 'License Key', 'gravitysmtp' ),
'license_box_input_help_text' => esc_html__( 'Enter your license key to gain access to plugin updates.', 'gravitysmtp' ),
'license_box_input_link_text' => esc_html__( 'Already purchased?', 'gravitysmtp' ),
'license_box_button_text' => esc_html__( 'Save License', 'gravitysmtp' ),
'license_valid' => esc_html__( 'License key successfully validated!', 'gravitysmtp' ),
'license_invalid' => esc_html__( 'Invalid license key entered. Please check your license key and try again.', 'gravitysmtp' ),
'experiments_box_heading' => esc_html__( 'Experimental Features', 'gravitysmtp' ),
'experiments_box_content' => esc_html__( 'These features are works-in-progress, so you may find some bugs along the way.', 'gravitysmtp' ),
'experiments_box_toggle_label' => esc_html__( 'Alerts', 'gravitysmtp' ),
'experiments_box_toggle_help_text' => esc_html__( 'Get notified via webhook or SMS (Twilio) when emails fail to send.', 'gravitysmtp' ),
'test_mode_box_heading' => esc_html__( 'Test Mode', 'gravitysmtp' ),
/* translators: %s: opening and closing anchor tags */
'test_mode_box_content_1' => esc_html__( 'When test mode is on, your site will not send out any emails. If you turn on %semail logging%s, all emails will be stored in the Email Logs.', 'gravitysmtp' ),
'test_mode_box_toggle_help_text' => esc_html__( 'Note: Some WordPress plugins use their own email delivery system instead of the standard wp_mail() function. Test mode might not block emails sent by these plugins. Consult their documentation to learn how to enable test emails.', 'gravitysmtp' ),
'test_mode_box_toggle_label' => esc_html__( 'Enable Test Mode', 'gravitysmtp' ),
'general_settings_box_heading' => esc_html__( 'General Settings', 'gravitysmtp' ),
'uninstall_box_heading' => esc_html__( 'Uninstall', 'gravitysmtp' ),
'uninstall_box_content' => esc_html__( 'This operation deletes ALL Gravity SMTP settings. If you continue, you will NOT be able to retrieve these settings.', 'gravitysmtp' ),
'uninstall_box_button_label' => esc_html__( 'Erase ALL Gravity SMTP Data', 'gravitysmtp' ),
'uninstall_dialog_confirm_change_heading' => esc_html__( 'Confirm Delete', 'gravitysmtp' ),
'uninstall_dialog_confirm_change_content' => esc_html__( 'This operation deletes ALL Gravity SMTP settings. If you continue, you will NOT be able to retrieve these settings.', 'gravitysmtp' ),
'uninstall_dialog_confirm_change_confirm' => esc_html__( 'Delete', 'gravitysmtp' ),
'error_uninstalling_message' => esc_html__( 'There was an error uninstalling Gravity SMTP', 'gravitysmtp' ),
),
'integrations' =>
array(
'top_heading' => esc_html__( 'Integrations', 'gravitysmtp' ),
'top_content' => esc_html__( 'Manage all your email connections. Click the + icon to add an integration; you can connect one or multiple services to handle your sites emails.', 'gravitysmtp' ),
'card_more_settings' => esc_html__( 'More Settings', 'gravitysmtp' ),
'card_settings' => esc_html__( 'Settings', 'gravitysmtp' ),
'card_primary' => esc_html__( 'Primary', 'gravitysmtp' ),
'card_backup' => esc_html__( 'Backup', 'gravitysmtp' ),
'integration_settings_error' => esc_html__( 'There was an error saving your settings', 'gravitysmtp' ),
/* translators: %1$s is the integration name */
'set_primary_integration' => esc_html__( '%1$s set as primary integration', 'gravitysmtp' ),
/* translators: %1$s is the integration name */
'set_backup_integration' => esc_html__( '%1$s set as backup integration', 'gravitysmtp' ),
'primary_disabled_heading' => esc_html__( 'Primary Integration Disabled', 'gravitysmtp' ),
'primary_disabled_content' => esc_html__( 'You have disabled your primary email integration. To continue sending emails via Gravity SMTP, please enable a backup integration or set and enable a new primary integration.', 'gravitysmtp' ),
/* translators: %1$s is the integration name */
'integration_disabled' => esc_html__( '%1$s integration has been disabled', 'gravitysmtp' ),
'flyout' => array(
'screen01' => array(
'heading' => esc_html__( 'New Connection', 'gravitysmtp' ),
/* translators: {{suggest_link}} tags are replaced by opening and closing tags for a link to our suggest integration page */
'description' => __( "Select and configure the integration you would like to use to send emails from this site. Don't see an integration you're looking for? {{suggest_link}}Suggest an integration.{{suggest_link}}", 'gravitysmtp' ),
'search_placeholder' => esc_html__( 'Search integration', 'gravitysmtp' ),
'search_label' => esc_html__( 'Search integration', 'gravitysmtp' ),
),
'screen02' => array(
'back_button_label' => esc_html__( 'Back', 'gravitysmtp' ),
'save_button_label' => esc_html__( 'Save Settings', 'gravitysmtp' ),
'save_enable_button_label' => __( 'Save & Enable', 'gravitysmtp' ),
),
),
),
'emails' =>
array(
'top_heading' => esc_html__( 'Email Management', 'gravitysmtp' ),
'top_content' => __( "WordPress, by default, will send out emails for many events on your site. Using the toggles below, you can decide exactly which emails you'd like enabled.", 'gravitysmtp' ),
'email_notifications_box_heading' => esc_html__( 'Manage Emails', 'gravitysmtp' ),
),
'logging' =>
array(
'top_heading' => esc_html__( 'Logging', 'gravitysmtp' ),
'top_content' => '',
'logging_box_heading' => esc_html__( 'Email Logging', 'gravitysmtp' ),
'logging_box_content' => esc_html__( 'Email logging keeps copies of all emails sent from your WordPress site, so you can review your sent emails and check their delivery status.', 'gravitysmtp' ),
'enable_log_label' => esc_html__( 'Enable Log', 'gravitysmtp' ),
'enable_log_helper_text' => esc_html__( 'Keep copies of all emails sent from your site.', 'gravitysmtp' ),
'save_email_body_label' => esc_html__( 'Save Email Body', 'gravitysmtp' ),
'save_email_body_helper_text' => esc_html__( 'Store the email body for all emails sent from your site.', 'gravitysmtp' ),
'save_attachments_label' => esc_html__( 'Save Attachments', 'gravitysmtp' ),
'save_attachments_helper_text' => esc_html__( 'Store attachments on the server in the uploads folder.', 'gravitysmtp' ),
'email_log_retention_label' => esc_html__( 'Log Retention Period', 'gravitysmtp' ),
'email_log_retention_helper_text' => esc_html__( 'Email logs older than the selected timeframe will be permanently deleted.', 'gravitysmtp' ),
'email_log_max_records_helper_text' => sprintf( $max_records_message, $max_records_value ),
/* translators: {{docs_link}} tags are replaced by opening and closing tags for a link to our log file retention periods documentation */
'email_log_resources_alert' => __( 'Large log files can quickly consume server resources and may impact site performance, especially on shared hosting. We recommend reviewing our {{docs_link}}log file retention periods article{{docs_link}} before enabling extended logging.', 'gravitysmtp' ),
'error_saving_snackbar_message' => esc_html__( 'There was an error saving the settings', 'gravitysmtp' ),
'debug_logging_box_heading' => esc_html__( 'Debug Logging', 'gravitysmtp' ),
'enable_debug_log_label' => esc_html__( 'Enable Debug Log', 'gravitysmtp' ),
'enable_debug_log_helper_text' => esc_html__( 'When enabled email sending errors debugging events will be logged, allowing you to detect email sending issues.', 'gravitysmtp' ),
'debug_log_retention_label' => esc_html__( 'Debug Log Retention Period', 'gravitysmtp' ),
'debug_log_retention_helper_text' => esc_html__( 'Debug events older than the selected period will be permanently deleted from the database.', 'gravitysmtp' ),
/* translators: {{docs_link}} tags are replaced by opening and closing tags for a link to our log file retention periods documentation */
'debug_log_resources_alert' => __( 'Debug logging should only be enabled temporarily when troubleshooting specific issues. Continuous logging can quickly consume server resources and may impact site performance, especially on shared hosting. We recommend reviewing our {{docs_link}}log file retention periods article{{docs_link}} before enabling debug logging.', 'gravitysmtp' ),
'view_activity_log_button_text' => esc_html__( 'View Email Log', 'gravitysmtp' ),
'delete_activity_log_button_text' => esc_html__( 'Delete Email Log', 'gravitysmtp' ),
'view_debug_log_button_text' => esc_html__( 'View Debug Log', 'gravitysmtp' ),
'copy_debug_log_button_text' => esc_html__( 'Copy Debug Log Link', 'gravitysmtp' ),
'delete_debug_log_button_text' => esc_html__( 'Delete Debug Log', 'gravitysmtp' ),
'delete_debug_log_dialog_confirm_change_heading' => esc_html__( 'Confirm Delete', 'gravitysmtp' ),
'delete_email_log_dialog_confirm_change_content' => esc_html__( 'This operation deletes ALL email logs. If you continue, you will NOT be able to retrieve these logs.', 'gravitysmtp' ),
'delete_debug_log_dialog_confirm_change_content' => esc_html__( 'This operation deletes ALL debug logs. If you continue, you will NOT be able to retrieve these logs.', 'gravitysmtp' ),
'delete_debug_log_dialog_confirm_change_confirm' => esc_html__( 'Delete', 'gravitysmtp' ),
),
'notifications' =>
array(
'email_digest_box_heading' => esc_html__( 'Email Activity Digest', 'gravitysmtp' ),
'email_digest_box_enabled_label' => esc_html__( 'Email Activity Digest', 'gravitysmtp' ),
'email_digest_box_enabled_helper_text' => __( 'Get a summary of your site\'s recent email activity delivered to your inbox. Includes key metrics like send volume, failures, and top emails.', 'gravitysmtp' ),
'email_digest_box_frequency_label' => esc_html__( 'Send Digest', 'gravitysmtp' ),
'email_digest_box_frequency_helper_text' => esc_html__( 'Select how often you want the email activity digest to be sent.', 'gravitysmtp' ),
'email_digest_box_send_preview_button_text' => esc_html__( 'Send Email Preview', 'gravitysmtp' ),
'error_sending_email_digest_preview_message' => esc_html__( 'Error sending email preview.', 'gravitysmtp' ),
'success_sending_email_digest_preview_message' => esc_html__( 'Email preview successfully sent!', 'gravitysmtp' ),
),
),
'data' => array(
'license_key' => $license_key,
'license_key_is_valid' => $is_valid,
'version' => GF_GRAVITY_SMTP_VERSION,
'email_log_settings' => array(
'email_log_enabled' => $email_log_enabled,
'email_log_retention' => $email_log_retention,
'email_log_url' => admin_url( 'admin.php?page=gravitysmtp-activity-log' ),
'log_retention_period_enabled' => ! Booliesh::get( $max_records_value ),
'max_records' => $max_records_value,
'max_records_set' => Booliesh::get( $max_records_value ),
'retention_options' => $this->get_email_log_retention_options( $email_log_retention ),
'save_attachments_enabled' => $save_attachments_enabled,
'save_email_body_enabled' => $save_email_body_enabled,
),
'debug_log_settings' => array(
'debug_log_enabled' => $debug_log_enabled,
'debug_log_retention' => $debug_log_retention,
'debug_log_url' => admin_url( 'admin.php?page=gravitysmtp-tools&tab=debug-log' ),
'retention_options' => $this->get_debug_log_retention_options( $debug_log_retention ),
),
'notifications_settings' => array(
'email_digest_enabled' => $notifications_email_digest_enabled,
'email_digest_frequency' => $notifications_email_digest_frequency,
'email_digest_frequency_options' => $this->get_notifications_email_digest_frequency_options(),
),
'caps' => array(
Roles::DELETE_DEBUG_LOG => current_user_can( Roles::DELETE_DEBUG_LOG ),
Roles::DELETE_EMAIL_LOG => current_user_can( Roles::DELETE_EMAIL_LOG ),
Roles::EDIT_ALERTS => current_user_can( Roles::EDIT_ALERTS ),
Roles::EDIT_ALERTS_SLACK_SETTINGS => current_user_can( Roles::EDIT_ALERTS_SLACK_SETTINGS ),
Roles::EDIT_ALERTS_TWILIO_SETTINGS => current_user_can( Roles::EDIT_ALERTS_TWILIO_SETTINGS ),
Roles::EDIT_DEBUG_LOG_SETTINGS => current_user_can( Roles::EDIT_DEBUG_LOG_SETTINGS ),
Roles::EDIT_EMAIL_LOG_SETTINGS => current_user_can( Roles::EDIT_EMAIL_LOG_SETTINGS ),
Roles::EDIT_EMAIL_MANAGEMENT_SETTINGS => current_user_can( Roles::EDIT_EMAIL_MANAGEMENT_SETTINGS ),
Roles::EDIT_INTEGRATIONS => current_user_can( Roles::EDIT_INTEGRATIONS ),
Roles::EDIT_LICENSE_KEY => current_user_can( Roles::EDIT_LICENSE_KEY ),
Roles::EDIT_EXPERIMENTAL_FEATURES => current_user_can( Roles::EDIT_EXPERIMENTAL_FEATURES ),
Roles::EDIT_NOTIFICATIONS_SETTINGS => current_user_can( Roles::EDIT_NOTIFICATIONS_SETTINGS ),
Roles::EDIT_TEST_MODE => current_user_can( Roles::EDIT_TEST_MODE ),
Roles::EDIT_UNINSTALL => current_user_can( Roles::EDIT_UNINSTALL ),
Roles::EDIT_USAGE_ANALYTICS => current_user_can( Roles::EDIT_USAGE_ANALYTICS ),
Roles::VIEW_ALERTS => current_user_can( Roles::VIEW_ALERTS ),
Roles::VIEW_ALERTS_SLACK_SETTINGS => current_user_can( Roles::VIEW_ALERTS_SLACK_SETTINGS ),
Roles::VIEW_ALERTS_TWILIO_SETTINGS => current_user_can( Roles::VIEW_ALERTS_TWILIO_SETTINGS ),
Roles::VIEW_DEBUG_LOG => current_user_can( Roles::VIEW_DEBUG_LOG ),
Roles::VIEW_DEBUG_LOG_SETTINGS => current_user_can( Roles::VIEW_DEBUG_LOG_SETTINGS ),
Roles::VIEW_EMAIL_LOG => current_user_can( Roles::VIEW_EMAIL_LOG ),
Roles::VIEW_EMAIL_LOG_SETTINGS => current_user_can( Roles::VIEW_EMAIL_LOG_SETTINGS ),
Roles::VIEW_EMAIL_MANAGEMENT_SETTINGS => current_user_can( Roles::VIEW_EMAIL_MANAGEMENT_SETTINGS ),
Roles::VIEW_INTEGRATIONS => current_user_can( Roles::VIEW_INTEGRATIONS ),
Roles::VIEW_LICENSE_KEY => current_user_can( Roles::VIEW_LICENSE_KEY ),
Roles::VIEW_EXPERIMENTAL_FEATURES => current_user_can( Roles::VIEW_EXPERIMENTAL_FEATURES ),
Roles::VIEW_NOTIFICATIONS_SETTINGS => current_user_can( Roles::VIEW_NOTIFICATIONS_SETTINGS ),
Roles::VIEW_TEST_MODE => current_user_can( Roles::VIEW_TEST_MODE ),
Roles::VIEW_UNINSTALL => current_user_can( Roles::VIEW_UNINSTALL ),
Roles::VIEW_USAGE_ANALYTICS => current_user_can( Roles::VIEW_USAGE_ANALYTICS ),
),
'email_digest_notifications' => array(
'email_digest_summary' => array(
'checked' => true,
'name' => 'email_digest_summary',
),
'notification_day' => array(
'options' => array(
array(
'label' => esc_html__( 'Every Day', 'gravitysmtp' ),
'value' => 'daily',
),
array(
'label' => esc_html__( 'Every Week', 'gravitysmtp' ),
'value' => 'weekly',
),
array(
'label' => esc_html__( 'Every Month', 'gravitysmtp' ),
'value' => 'monthly',
),
array(
'label' => esc_html__( 'Every Year', 'gravitysmtp' ),
'value' => 'yearly',
),
),
'name' => 'notification_day',
),
'notification_email_addresses' => array(
'value' => 'olivia@gravity.com, carl@hancock.io',
'name' => 'notification_email_addresses',
),
'enable_html_mode' => array(
'checked' => true,
'name' => 'enable_html_mode',
),
),
'route_path' => admin_url( 'admin.php' ),
'plugins_url' => admin_url( 'plugins.php' ),
'nav_item_param_key' => 'tab',
'nav_items' => array(
array(
'param' => 'settings',
'label' => esc_html__( 'Settings', 'gravitysmtp' ),
'icon' => 'settings',
),
array(
'param' => 'integrations',
'label' => esc_html__( 'Integrations', 'gravitysmtp' ),
'icon' => 'cloud1',
),
array(
'param' => 'alerts',
'label' => esc_html__( 'Alerts', 'gravitysmtp' ),
'icon' => 'exclamation-triangle',
),
array(
'param' => 'emails',
'label' => esc_html__( 'Emails', 'gravitysmtp' ),
'icon' => 'mail',
),
array(
'param' => 'logging',
'label' => esc_html__( 'Logging', 'gravitysmtp' ),
'icon' => 'circle-tool',
),
array(
'param' => 'routing',
'label' => esc_html__( 'Routing', 'gravitysmtp' ),
'icon' => 'routing',
),
),
'integrations_actions' => array(
0 =>
array(
'key' => 'edit',
'props' => array(
'element' => 'button',
'iconBefore' => 'api',
'iconPrefix' => 'gravity-admin-icon',
'label' => esc_html__( 'API Settings', 'gravitysmtp' ),
),
),
1 =>
array(
'key' => 'send-a-test',
'props' => array(
'customAttributes' => array(
'href' => admin_url( 'admin.php?page=gravitysmtp-tools&tab=send-a-test' ),
'data-test-id' => 'send-a-test-action'
),
'element' => 'link',
'iconBefore' => 'paper-plane',
'iconPrefix' => 'gravity-admin-icon',
'label' => esc_html__( 'Send A Test', 'gravitysmtp' ),
),
),
2 =>
array(
'key' => 'set-as-primary',
'props' => array(
'element' => 'button',
'iconBefore' => 'primary',
'iconPrefix' => 'gravity-admin-icon',
'label' => esc_html__( 'Set As Primary', 'gravitysmtp' ),
),
),
3 =>
array(
'key' => 'set-as-backup',
'props' => array(
'element' => 'button',
'iconBefore' => 'circle-lightning-bolt',
'iconPrefix' => 'gravity-admin-icon',
'label' => esc_html__( 'Set As Backup', 'gravitysmtp' ),
),
),
4 =>
array(
'key' => 'remove',
'props' => array(
'element' => 'button',
'iconBefore' => 'trash',
'iconPrefix' => 'gravity-admin-icon',
'label' => esc_html__( 'Remove Integration', 'gravitysmtp' ),
'style' => 'error',
),
),
),
'email_notifications' => array(
array(
'title' => esc_html__( 'Change of Admin Email', 'gravitysmtp' ),
'settings' => array(
array(
'label' => esc_html__( 'Site Admin Email Change Attempt', 'gravitysmtp' ),
'checked' => true,
'name' => 'site_admin_email_change_attempt',
),
array(
'label' => esc_html__( 'Site Admin Email Changed', 'gravitysmtp' ),
'checked' => false,
'name' => 'site_admin_email_changed',
),
),
),
array(
'title' => esc_html__( 'Change of User Email or Password', 'gravitysmtp' ),
'settings' => array(
array(
'label' => esc_html__( 'Reset Password Request', 'gravitysmtp' ),
'checked' => false,
'name' => 'reset_password_request',
),
array(
'label' => esc_html__( 'Password Reset Successfully', 'gravitysmtp' ),
'checked' => false,
'name' => 'password_reset_successfully',
),
array(
'label' => esc_html__( 'Password Changed', 'gravitysmtp' ),
'checked' => false,
'name' => 'password_changed',
),
array(
'label' => esc_html__( 'Email Change Attempt', 'gravitysmtp' ),
'checked' => false,
'name' => 'email_change_attempt',
),
array(
'label' => esc_html__( 'Email Changed', 'gravitysmtp' ),
'checked' => true,
'name' => 'email_changed',
),
),
),
array(
'title' => esc_html__( 'Personal Data Requests', 'gravitysmtp' ),
'settings' => array(
array(
'label' => esc_html__( 'User Confirmed Export / Erasure Request', 'gravitysmtp' ),
'checked' => true,
'name' => 'user_confirmed_export_erasure_request',
),
array(
'label' => esc_html__( 'Admin Erased Data', 'gravitysmtp' ),
'checked' => true,
'name' => 'admin_erased_data',
),
array(
'label' => esc_html__( 'Admin Sent Link to Export Data', 'gravitysmtp' ),
'checked' => false,
'name' => 'admin_sent_link_to_export_data',
),
),
),
array(
'title' => esc_html__( 'Automatic Updates', 'gravitysmtp' ),
'settings' => array(
array(
'label' => esc_html__( 'Plugin Status', 'gravitysmtp' ),
'checked' => true,
'name' => 'plugin_status',
),
array(
'label' => esc_html__( 'Theme Status', 'gravitysmtp' ),
'checked' => true,
'name' => 'theme_status',
),
array(
'label' => esc_html__( 'WP Core Status', 'gravitysmtp' ),
'checked' => true,
'name' => 'wp_core_status',
),
array(
'label' => esc_html__( 'Full Log', 'gravitysmtp' ),
'checked' => false,
'name' => 'full_log',
),
),
),
array(
'title' => esc_html__( 'New User', 'gravitysmtp' ),
'settings' => array(
array(
'label' => esc_html__( 'Created (Admin)', 'gravitysmtp' ),
'checked' => false,
'name' => 'created_admin',
),
array(
'label' => esc_html__( 'Created (User)', 'gravitysmtp' ),
'checked' => false,
'name' => 'created_user',
),
),
),
array(
'title' => esc_html__( 'Comments', 'gravitysmtp' ),
'settings' => array(
array(
'label' => esc_html__( 'Awaiting Moderation', 'gravitysmtp' ),
'checked' => false,
'name' => 'awaiting_moderation',
),
array(
'label' => esc_html__( 'Published', 'gravitysmtp' ),
'checked' => false,
'name' => 'published',
),
),
),
array(
'title' => esc_html__( 'WooCommerce', 'gravitysmtp' ),
'settings' => array(
array(
'label' => esc_html__( 'Purchase Receipt', 'gravitysmtp' ),
'checked' => true,
'name' => 'purchase_receipt',
),
array(
'label' => esc_html__( 'Password Change', 'gravitysmtp' ),
'checked' => true,
'name' => 'password_change',
),
),
),
),
'primary_locked' => $primary_locked,
'backup_locked' => $backup_locked,
),
'endpoints' => array(),
),
)
);
}
public function get_email_log_retention_options( $retention ) {
$options = array(
array(
'label' => esc_html__( '1 Day', 'gravitysmtp' ),
'value' => 1,
),
array(
'label' => esc_html__( '1 Week', 'gravitysmtp' ),
'value' => 7,
),
array(
'label' => esc_html__( '1 Month', 'gravitysmtp' ),
'value' => 30,
),
array(
'label' => esc_html__( '3 Months', 'gravitysmtp' ),
'value' => 90,
),
array(
'label' => esc_html__( '6 Months', 'gravitysmtp' ),
'value' => 180,
),
array(
'label' => esc_html__( '1 Year', 'gravitysmtp' ),
'value' => 365,
),
array(
'label' => esc_html__( 'Never Delete', 'gravitysmtp' ),
'value' => 0,
),
);
$values = array_column( $options, 'value' );
if ( in_array( $retention, $values ) ) {
return apply_filters( 'gravitysmtp_email_log_retention_options', $options );
}
return apply_filters(
'gravitysmtp_email_log_retention_options',
array(
array(
'label' => esc_html( sprintf( _n( '%s Day', '%s Days', $retention, 'gravitysmtp' ), $retention ) ),
'value' => $retention,
),
)
);
}
public function get_debug_log_retention_options( $retention ) {
$options = array(
array(
'label' => esc_html__( '1 Week', 'gravitysmtp' ),
'value' => 7,
),
array(
'label' => esc_html__( '1 Month', 'gravitysmtp' ),
'value' => 30,
),
);
$values = array_column( $options, 'value' );
if ( in_array( $retention, $values ) ) {
return apply_filters( 'gravitysmtp_debug_log_retention_options', $options );
}
return apply_filters(
'gravitysmtp_debug_log_retention_options',
array(
array(
'label' => esc_html( sprintf( _n( '%s Day', '%s Days', $retention, 'gravitysmtp' ), $retention ) ),
'value' => $retention,
),
)
);
}
public function get_notifications_email_digest_frequency_options() {
$options = array(
array(
'label' => esc_html__( 'Daily', 'gravitysmtp' ),
'value' => 1,
),
array(
'label' => esc_html__( 'Weekly (recommended)', 'gravitysmtp' ),
'value' => 7,
),
array(
'label' => esc_html__( 'Monthly', 'gravitysmtp' ),
'value' => 30,
),
);
return apply_filters( 'gravitysmtp_notifications_email_digest_frequency_options', $options );
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,73 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Apps\Endpoints;
use Gravity_Forms\Gravity_SMTP\Apps\Config\Dashboard_Config;
use Gravity_Forms\Gravity_Tools\Endpoints\Endpoint;
use Gravity_Forms\Gravity_SMTP\Data_Store\Plugin_Opts_Data_Store;
use Gravity_Forms\Gravity_SMTP\Users\Roles;
class Get_Dashboard_Data_Endpoint extends Endpoint {
const ACTION_NAME = 'get_dashboard_data';
const PARAM_START_DATE = 'start_date';
const PARAM_END_DATE = 'end_date';
const PARAM_DATE_RANGE = 'date_range';
/**
* @var Dashboard_Config;
*/
protected $dasbhoard_config;
protected $minimum_cap = Roles::VIEW_DASHBOARD;
public function __construct( $dashboard_config ) {
$this->dasbhoard_config = $dashboard_config;
}
protected function get_nonce_name() {
return self::ACTION_NAME;
}
public function handle() {
if ( ! $this->validate() ) {
wp_send_json_error( __( 'Missing required parameters.', 'gravitysmtp' ), 400 );
}
$date_range = FILTER_INPUT( INPUT_POST, self::PARAM_DATE_RANGE );
$start = FILTER_INPUT( INPUT_POST, self::PARAM_START_DATE );
$end = FILTER_INPUT( INPUT_POST, self::PARAM_END_DATE );
if ( ! empty( $date_range ) && ! empty( $start ) ) {
wp_send_json_error( __( 'Send either a date range value or start/end dates; do not send both.', 'gravitysmtp' ), 400 );
}
if ( ! empty( $date_range ) ) {
$data = $this->get_data_for_range( $date_range );
wp_send_json_success( $data );
}
if ( empty( $start ) || empty( $end ) ) {
wp_send_json_error( __( 'Must provide both start and end dates.', 'gravitysmtp' ), 400 );
}
$period = 0;
$start = get_gmt_from_date( $start );
$end = get_gmt_from_date( $end );
$data = $this->dasbhoard_config->ajax_data( $start, $end, $period );
wp_send_json_success( $data );
}
private function get_data_for_range( $date_range ) {
$mod_string = sprintf( "-%d days", ( $date_range - 1 ) );
$start = get_gmt_from_date( gmdate( 'Y-m-d 00:00:00', strtotime( $mod_string ) ) );
$end = get_gmt_from_date( gmdate( 'Y-m-d 23:59:59' ) );
$period = $date_range;
return $this->dasbhoard_config->ajax_data( $start, $end, $period );
}
}
@@ -0,0 +1,39 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Apps\Setup_Wizard;
use Gravity_Forms\Gravity_SMTP\Apps\Setup_Wizard\Config\Setup_Wizard_Config;
use Gravity_Forms\Gravity_SMTP\Apps\Setup_Wizard\Config\Setup_Wizard_Endpoints_Config;
use Gravity_Forms\Gravity_SMTP\Apps\Setup_Wizard\Endpoints\License_Check_Endpoint;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Migrate_Settings_Endpoint;
use Gravity_Forms\Gravity_Tools\Service_Container;
use Gravity_Forms\Gravity_Tools\Providers\Config_Service_Provider;
class Setup_Wizard_Service_Provider extends Config_Service_Provider {
const IMPORT_SETTINGS_ENDPOINT = 'import_settings_endpoint';
const LICENSE_CHECK_ENDPOINT = 'license_check_endpoint';
const SAVE_SETUP_PROGRESS_ENDPOINT = 'save_setup_progress_endpoint';
const SETUP_WIZARD_CONFIG = 'setup_wizard_config';
const SETUP_WIZARD_ENDPOINTS_CONFIG = 'setup_wizard_endpoints_config';
protected $configs = array(
self::SETUP_WIZARD_CONFIG => Setup_Wizard_Config::class,
self::SETUP_WIZARD_ENDPOINTS_CONFIG => Setup_Wizard_Endpoints_Config::class,
);
public function register( Service_Container $container ) {
parent::register( $container );
$this->container->add( self::LICENSE_CHECK_ENDPOINT, function () use ( $container ) {
return new License_Check_Endpoint();
} );
}
public function init( Service_Container $container ) {
add_action( 'wp_ajax_' . License_Check_Endpoint::ACTION_NAME, function () use ( $container ) {
$container->get( self::LICENSE_CHECK_ENDPOINT )->handle();
} );
}
}
@@ -0,0 +1,185 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Apps\Setup_Wizard\Config;
use Gravity_Forms\Gravity_SMTP\Apps\App_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Save_Plugin_Settings_Endpoint;
use Gravity_Forms\Gravity_SMTP\Gravity_SMTP;
use Gravity_Forms\Gravity_SMTP\Utils\Booliesh;
use Gravity_Forms\Gravity_Tools\Config;
use Gravity_Forms\Gravity_Tools\License\License_Statuses;
use Gravity_Forms\Gravity_Tools\Updates\Updates_Service_Provider;
use Gravity_Forms\Gravity_Tools\Utils\Utils_Service_Provider;
class Setup_Wizard_Config extends Config {
protected $script_to_localize = 'gravitysmtp_scripts_admin';
protected $name = 'gravitysmtp_admin_config';
protected $overwrite = false;
public function should_enqueue() {
$should_enqueue = Gravity_SMTP::container()->get( App_Service_Provider::SHOULD_ENQUEUE_SETUP_WIZARD );
return is_callable( $should_enqueue ) ? $should_enqueue() : $should_enqueue;
}
public function data() {
$container = Gravity_SMTP::container();
$plugin_data_store = $container->get( Connector_Service_Provider::DATA_STORE_ROUTER );
$rg_forms_key = get_option( 'rg_gforms_key', '' );
$smtp_plugin_key = $plugin_data_store->get_plugin_setting( Save_Plugin_Settings_Endpoint::PARAM_LICENSE_KEY, '' );
$license_key = ! empty( $smtp_plugin_key ) ? $smtp_plugin_key : $rg_forms_key;
$is_valid = null;
if ( ! empty( $license_key ) ) {
$license_info = $container->get( Updates_Service_Provider::LICENSE_API_CONNECTOR )->check_license( $license_key );
$is_valid = License_Statuses::VALID_KEY === $license_info->get_status();
}
// should display logic check
$should_display = Booliesh::get( $plugin_data_store->get_plugin_setting( Save_Plugin_Settings_Endpoint::PARAM_SETUP_WIZARD_SHOULD_DISPLAY, 'true' ) );
$setup_wizard_page = filter_input( INPUT_GET, 'setup-wizard-page' );
$is_wizard_open = $should_display;
if ( is_string( $setup_wizard_page ) ) {
$setup_wizard_page = htmlspecialchars( $setup_wizard_page );
$is_wizard_open = true;
} else {
$setup_wizard_page = 1;
}
$connectors_to_migrate = $container->get( Utils_Service_Provider::IMPORT_DATA_CHECKER )->connectors_to_migrate();
return array(
'components' => array(
'setup_wizard' => array(
'i18n' => array(
'debug_messages' => array(
/* translators: %1$s is the request data. */
'checking_license_key' => esc_html__( 'Setup Wizard Screen 01: Checking license key: %1$s', 'gravitysmtp' ),
/* translators: %1$s is the error data. */
'checking_license_key_error' => esc_html__( 'Setup Wizard Screen 01: Error checking license key: %1$s', 'gravitysmtp' ),
/* translators: %1$s is the request data. */
'migrating_data' => esc_html__( 'Setup Wizard Screen 02: Migrating data: %1$s', 'gravitysmtp' ),
/* translators: %1$s is the error data. */
'migrating_data_error' => esc_html__( 'Setup Wizard Screen 02: Error migrating data: %1$s', 'gravitysmtp' ),
/* translators: %1$s is the request data. */
'saving_license_key' => esc_html__( 'Setup Wizard Screen 01: Saving license key: %1$s', 'gravitysmtp' ),
/* translators: %1$s is the error data. */
'saving_license_key_error' => esc_html__( 'Setup Wizard Screen 01: Error saving license key: %1$s', 'gravitysmtp' ),
/* translators: %1$s is the error data. */
'saving_should_display_error' => esc_html__( 'Setup Wizard Screen 01: Error saving should display: %1$s', 'gravitysmtp' ),
/* translators: %1$s is the settings data. */
'starting_first_run' => esc_html__( 'Setup Wizard Screen 01: Starting wizard for first run: %1$s', 'gravitysmtp' ),
/* translators: %1$s is the settings data. */
'starting_subsequent_run' => esc_html__( 'Setup Wizard Screen 01: Starting wizard from the settings screen: %1$s', 'gravitysmtp' ),
/* translators: %1$s is the request data. */
'setting_should_display_false' => esc_html__( 'Setup Wizard Screen 01: Setting should display to false: %1$s', 'gravitysmtp' ),
/* translators: %1$s is the request data. */
'updating_usage_analytics' => esc_html__( 'Setup Wizard Screen 01: Updating usage analytics: %1$s', 'gravitysmtp' ),
/* translators: %1$s is the error data. */
'updating_usage_analytics_error' => esc_html__( 'Setup Wizard Screen 01: Error updating usage analytics: %1$s', 'gravitysmtp' ),
),
'setup_wizard_welcome_title' => esc_html__( 'Welcome to Gravity SMTP', 'gravitysmtp' ),
'setup_wizard_welcome_copy' => __( "You're only minutes away from sending emails with confidence! Use the setup wizard to get started if this is your first time using Gravity SMTP.", 'gravitysmtp' ),
'setup_wizard_next' => esc_html__( 'Next', 'gravitysmtp' ),
'setup_wizard_welcome_list_01' => esc_html__( 'The Most Popular WordPress SMTP Plugin', 'gravitysmtp' ),
'setup_wizard_welcome_list_02' => __( 'Advanced Open & Click Tracking', 'gravitysmtp' ),
'setup_wizard_welcome_list_03' => esc_html__( 'Weekly Email Summaries', 'gravitysmtp' ),
'setup_wizard_welcome_list_04' => esc_html__( 'Text Alerts For Service Interruptions', 'gravitysmtp' ),
'setup_wizard_get_started' => __( 'Let\'s Get Started', 'gravitysmtp' ),
'setup_wizard_verify_license' => esc_html__( 'Verify License', 'gravitysmtp' ),
'setup_wizard_checking_license' => esc_html__( 'Checking License', 'gravitysmtp' ),
'setup_wizard_license_input_label' => esc_html__( 'Enter License Key', 'gravitysmtp' ),
'setup_wizard_license_input_placeholder' => esc_html__( 'Enter your license key here', 'gravitysmtp' ),
'setup_wizard_close_button' => esc_html__( 'Close', 'gravitysmtp' ),
'setup_wizard_back_button' => esc_html__( 'Back', 'gravitysmtp' ),
'setup_wizard_skip_button' => esc_html__( 'Skip This Step', 'gravitysmtp' ),
'setup_wizard_next_button' => esc_html__( 'Next', 'gravitysmtp' ),
'setup_wizard_dashboard_button' => esc_html__( 'Return to Dashboard', 'gravitysmtp' ),
'setup_wizard_import_data_title' => esc_html__( 'Migrate Your SMTP Settings', 'gravitysmtp' ),
'setup_wizard_import_data_copy' => __( "Gravity SMTP is compatible with multiple SMTP plugins. Weve detected other SMTP plugins installed on your website. Choose which plugins data you want to import to Gravity SMTP for a seamless migration experience.", 'gravitysmtp' ),
'setup_wizard_integration_title' => esc_html__( 'Choose Your SMTP Mail Solution', 'gravitysmtp' ),
'setup_wizard_integration_copy_1' => esc_html__( 'Which SMTP mail solution would you like to use to send emails?', 'gravitysmtp' ),
'setup_wizard_integration_copy_2' => esc_html__( 'Not sure which to choose? Check out our Ultimate Gravity SMTP Guide for details on each option.', 'gravitysmtp' ),
'setup_wizard_mail_settings_title' => esc_html__( 'Configure Mail Settings', 'gravitysmtp' ),
/* translators: %s: integration name. */
'setup_wizard_mail_settings_copy' => esc_html__( 'Get Started With %s', 'gravitysmtp' ),
'setup_wizard_setup_skipped_title' => esc_html__( 'Setup Skipped', 'gravitysmtp' ),
'setup_wizard_setup_skipped_copy' => __( "Congratulations, you're ready to start reliably and securely sending email from your site using Gravity SMTP. Head on over to the plugin dashboard to check out all the features Gravity SMTP has to offer.", 'gravitysmtp' ),
'setup_wizard_setup_success_title' => esc_html__( 'Setup Complete', 'gravitysmtp' ),
'setup_wizard_setup_success_copy' => __( "Congratulations, you're ready to start reliably and securely sending email from your site using Gravity SMTP. Head on over to the plugin dashboard to check out all the features Gravity SMTP has to offer.", 'gravitysmtp' ),
'setup_wizard_setup_failed_title' => __( "Whoops, looks like things aren't configured properly.", 'gravitysmtp' ),
'setup_wizard_setup_failed_copy' => esc_html__( 'We just tried to send a test email, but something prevented that from working. To see more details about the issue we detected, as well as our suggestions to fix it, please start troubleshooting.', 'gravitysmtp' ),
'setup_wizard_integration_settings_error' => esc_html__( 'There was an error saving your settings', 'gravitysmtp' ),
/* translators: %s: integration name. */
'setup_wizard_activate_integration_button' => esc_html__( 'Activate %s Integration', 'gravitysmtp' ),
),
'data' => array(
'admin_url' => array(
'default' => '',
'value' => admin_url(),
),
'integrations_url' => array(
'default' => '',
'value' => admin_url( 'admin.php?page=gravitysmtp-settings&tab=integrations' ),
),
'connectors_to_migrate' => array(
'default' => array(),
'value' => $connectors_to_migrate,
),
'defaults' => array(
'activeNavBarStep' => array(
'default' => 1,
'value' => (int) $setup_wizard_page,
),
'activeStep' => array(
'default' => 1,
'value' => (int) $setup_wizard_page,
),
'isOpen' => array(
'default' => true,
'value' => $is_wizard_open,
),
),
'import_data' => array(
array(
'logo' => 'GravityFormsStacked',
'title' => 'Gravity Forms',
'id' => 'gravityforms',
'activated' => true,
),
array(
'logo' => 'WPMailSMTPFull',
'title' => 'WP Mail SMTP',
'id' => 'wpmailsmtp',
'activated' => true,
'initialChecked' => in_array( 'wpmailsmtp', $connectors_to_migrate ), // @aaron set to true for one of these to make it checked by default
),
),
'integrations' => array(
'default' => array(),
'value' => array(),
),
'license_key' => array(
'default' => '',
'value' => $is_valid ? $license_key : '',
),
'license_key_is_valid' => array(
'default' => false,
'value' => $is_valid,
),
'should_display' => array(
'default' => true,
'value' => $should_display,
),
),
)
)
);
}
}
@@ -0,0 +1,43 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Apps\Setup_Wizard\Config;
use Gravity_Forms\Gravity_SMTP\Apps\App_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Apps\Setup_Wizard\Endpoints\License_Check_Endpoint;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Save_Plugin_Settings_Endpoint;
use Gravity_Forms\Gravity_SMTP\Gravity_SMTP;
use Gravity_Forms\Gravity_Tools\Config;
class Setup_Wizard_Endpoints_Config extends Config {
protected $script_to_localize = 'gravitysmtp_scripts_admin';
protected $name = 'gravitysmtp_admin_config';
public function should_enqueue() {
$should_enqueue = Gravity_SMTP::container()->get( App_Service_Provider::SHOULD_ENQUEUE_SETUP_WIZARD );
return is_callable( $should_enqueue ) ? $should_enqueue() : $should_enqueue;
}
public function data() {
return array(
'components' => array(
'setup_wizard' => array(
'endpoints' => array(
License_Check_Endpoint::ACTION_NAME => array(
'action' => array(
'value' => License_Check_Endpoint::ACTION_NAME,
'default' => 'mock_endpoint',
),
'nonce' => array(
'value' => wp_create_nonce( License_Check_Endpoint::ACTION_NAME ),
'default' => 'nonce',
),
),
),
),
),
);
}
}
@@ -0,0 +1,58 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Apps\Setup_Wizard\Endpoints;
use Gravity_Forms\Gravity_SMTP\Gravity_SMTP;
use Gravity_Forms\Gravity_SMTP\Users\Roles;
use Gravity_Forms\Gravity_Tools\Endpoints\Endpoint;
use Gravity_Forms\Gravity_Tools\License\License_Statuses;
use Gravity_Forms\Gravity_Tools\Updates\Updates_Service_Provider;
class License_Check_Endpoint extends Endpoint {
const PARAM_LICENSE_KEY = 'license_key';
const ACTION_NAME = 'check_license';
protected $minimum_cap = Roles::EDIT_LICENSE_KEY;
protected function get_nonce_name() {
return self::ACTION_NAME;
}
public function handle() {
if ( ! $this->validate() ) {
wp_send_json_error( __( 'Missing required parameters.', 'gravitysmtp' ), 400 );
}
$license_key = filter_input( INPUT_POST, self::PARAM_LICENSE_KEY );
$license_key = htmlspecialchars( $license_key );
$container = Gravity_SMTP::container();
$key_is_empty = empty( $license_key );
$is_valid = false;
if ( ! $key_is_empty ) {
$license_info = $container->get( Updates_Service_Provider::LICENSE_API_CONNECTOR )->check_license( $license_key );
$is_valid = License_Statuses::VALID_KEY === $license_info->get_status();
}
if ( ! $is_valid ) {
wp_send_json_error( __( 'Invalid license key.', 'gravitysmtp' ), 400 );
}
wp_send_json_success( array( 'license_key' => $license_key ) );
}
protected function validate() {
if ( ! parent::validate() ) {
return false;
}
if ( empty( $_REQUEST[ self::PARAM_LICENSE_KEY ] ) ) {
return false;
}
return true;
}
}
@@ -0,0 +1,108 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Assets;
use Gravity_Forms\Gravity_SMTP\Environment\Environment_Details;
use Gravity_Forms\Gravity_Tools\Assets\Asset_Processor;
use Gravity_Forms\Gravity_Tools\Service_Container;
use Gravity_Forms\Gravity_Tools\Service_Provider;
use Gravity_Forms\Gravity_Tools\Utils\Utils_Service_Provider;
class Assets_Service_Provider extends Service_Provider {
const ENVIRONMENT_DETAILS = 'environment_details';
const HASH_MAP_JS = 'hash_map_js';
const HASH_MAP_CSS = 'hash_map_css';
const ASSET_PROCESSOR = 'asset_processor';
protected $plugin_url;
protected $dev_plugin_url;
protected $plugin_path;
public function __construct( $plugin_url, $dev_plugin_url, $plugin_path ) {
$this->plugin_url = $plugin_url;
$this->dev_plugin_url = $dev_plugin_url;
$this->plugin_path = $plugin_path;
}
public function register( Service_Container $container ) {
$container->add( self::ENVIRONMENT_DETAILS, function () {
return new Environment_Details();
} );
$container->add( self::HASH_MAP_JS, function () use ( $container ) {
if ( ! file_exists( $this->plugin_path . 'assets/js/dist/assets.php' ) ) {
return array();
}
$map = require( $this->plugin_path . 'assets/js/dist/assets.php' );
$common = $container->get( Utils_Service_Provider::COMMON );
return $common->rgar( $map, 'hash_map', array() );
} );
$container->add( self::HASH_MAP_CSS, function () use ( $container ) {
if ( ! file_exists( $this->plugin_path . 'assets/css/dist/assets.php' ) ) {
return array();
}
$map = require( $this->plugin_path . 'assets/css/dist/assets.php' );
$common = $container->get( Utils_Service_Provider::COMMON );
return $common->rgar( $map, 'hash_map', array() );
} );
$container->add( self::ASSET_PROCESSOR, function () use ( $container ) {
$js_map = $container->get( self::HASH_MAP_JS );
$js_asset_path = sprintf( '%sassets/js/dist/', $this->plugin_path );
$js_pattern = 'gravitysmtp/assets/js/dist';
$css_map = $container->get( self::HASH_MAP_CSS );
$css_asset_path = sprintf( '%sassets/css/dist/', $this->plugin_path );
$css_pattern = 'gravitysmtp/assets/css/dist';
$processor = new Asset_Processor( $js_map, $css_map, $js_asset_path, $css_asset_path, $js_pattern, $css_pattern, 'GRAVITYSMTP_DEV_TIME_AS_VER' );
return $processor;
} );
}
public function is_smtp_page() {
$page = filter_input( INPUT_GET, 'page' );
if ( ! is_string( $page ) ) {
return false;
}
$page = htmlspecialchars( $page );
return strncmp( $page, 'gravitysmtp', 11 ) === 0;
}
public function init( Service_Container $container ) {
$version = $container->get( self::ENVIRONMENT_DETAILS )->get_version();
$min = $container->get( self::ENVIRONMENT_DETAILS )->get_min();
wp_register_script( 'gravitysmtp_vendor_admin', $this->plugin_url . "/assets/js/dist/vendor-admin{$min}.js", array(), $version, true );
wp_register_script( 'gravitysmtp_scripts_admin', $this->dev_plugin_url . "/scripts-admin{$min}.js", array( 'gravitysmtp_vendor_admin' ), $version, true );
wp_register_style( 'gravitysmtp_styles_admin_components', $this->plugin_url . "/assets/css/dist/admin-components{$min}.css", array(), $version );
wp_register_style( 'gravitysmtp_styles_admin', $this->plugin_url . "/assets/css/dist/admin{$min}.css", array(), $version );
wp_register_style( 'gravitysmtp_styles_admin_icons', $this->plugin_url . "/assets/css/dist/admin-icons{$min}.css", array( 'gravitysmtp_styles_admin' ), $version );
wp_register_style( 'gravitysmtp_styles_base', $this->plugin_url . "/assets/css/dist/base{$min}.css", array( 'gravitysmtp_styles_admin_components' ), $version );
if ( $this->is_smtp_page() ) {
add_action( 'admin_enqueue_scripts', function () {
wp_enqueue_script( 'gravitysmtp_scripts_admin' );
wp_enqueue_style( 'gravitysmtp_styles_admin_icons' );
} );
add_action( 'admin_enqueue_scripts', function () use ( $container ) {
$container->get( self::ASSET_PROCESSOR )->process_assets();
}, 9999 );
}
}
}
@@ -0,0 +1,398 @@
<?php
namespace Gravity_Forms\Gravity_SMTP;
use Gravity_Forms\Gravity_SMTP\Alerts\Alerts_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Apps\App_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Apps\Setup_Wizard\Setup_Wizard_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Assets\Assets_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Base;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Save_Connector_Settings_Endpoint;
use Gravity_Forms\Gravity_SMTP\Data_Store\Const_Data_Store;
use Gravity_Forms\Gravity_SMTP\Data_Store\Data_Store_Router;
use Gravity_Forms\Gravity_SMTP\Data_Store\Opts_Data_Store;
use Gravity_Forms\Gravity_SMTP\Data_Store\Plugin_Opts_Data_Store;
use Gravity_Forms\Gravity_SMTP\Email_Management\Email_Management_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Environment\Environment_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Experimental_Features\Experimental_Features_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Feature_Flags\Feature_Flag_Manager;
use Gravity_Forms\Gravity_SMTP\Feature_Flags\Feature_Flags_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Errors\Error_Handler_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Handler\Handler_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Logging\Logging_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Migration\Migration_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Notifications\Notifications_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Pages\Page_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Routing\Routing_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Suppression\Suppression_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Telemetry\Telemetry_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Translations\Translations_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Users\Users_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Utils\Booliesh;
use Gravity_Forms\Gravity_Tools\Service_Container;
use Gravity_Forms\Gravity_Tools\Providers\Config_Collection_Service_Provider;
use Gravity_Forms\Gravity_Tools\Updates\Updates_Service_Provider;
use Gravity_Forms\Gravity_Tools\Upgrades\Upgrade_Routines;
use Gravity_Forms\Gravity_Tools\Utils\Utils_Service_Provider;
/**
* Loads Gravity SMTP.
*
* @since 1.0
*/
class Gravity_SMTP {
/**
* @var Service_Container $container
*/
public static $container;
public static function pre_init() {
self::handle_feature_flags();
self::load_early_providers();
}
/**
* Loads the required files.
*
* @since 1.0
*/
public static function load_plugin() {
self::clear_cache_for_oauth();
self::load_providers();
}
/**
* Run upgrade routines on plugins_loaded to ensure users have the most-up-to-date system when updating.
*
* @return void
*/
public static function run_upgrade_routines() {
// Allow upgrades to be skipped if needed.
if ( defined( 'GRAVITYSMTP_SKIP_UPGRADE_CHECK' ) && GRAVITYSMTP_SKIP_UPGRADE_CHECK ) {
return;
}
$routines = new Upgrade_Routines( 'gravitysmtp' );
// Ensure tables are set up properly
$routines->add( 'emails_tables', array( self::class, 'create_emails_tables' ) );
// Ensure a primary connection exists
$routines->add( 'primary_connection', array( self::class, 'set_primary_connection' ) );
// Ensure suppression table is set up properly
$routines->add( 'suppression_tables', array( self::class, 'create_suppression_table' ) );
add_action( 'plugins_loaded', function() use ( $routines ) {
$routines->handle();
}, 10 );
}
private static function clear_cache_for_oauth() {
$payload = filter_input( INPUT_POST, 'auth_payload' );
if ( ! empty( $payload ) ) {
$configured_key = sprintf( 'gsmtp_connector_configured_%s', 'google' );
delete_transient( $configured_key );
}
}
public static function set_primary_connection() {
$const = new Const_Data_Store();
$opts = new Opts_Data_Store();
$plugin = new Plugin_Opts_Data_Store();
$router = new Data_Store_Router( $const, $opts, $plugin );
$primaries = $router->get_plugin_setting( Save_Connector_Settings_Endpoint::SETTING_PRIMARY_CONNECTOR, array() );
$selected = array_filter( $primaries );
if ( ! empty( $selected ) ) {
return;
}
$enabled = $router->get_plugin_setting( Save_Connector_Settings_Endpoint::SETTING_ENABLED_CONNECTOR, array() );
$selected = array_filter( $enabled );
if ( empty( $selected ) ) {
return;
}
$keys = array_keys( $selected );
$enabled_connector = reset( $keys );
$primaries[ $enabled_connector ] = true;
$opts->save( Connector_Base::SETTING_IS_PRIMARY, true, $enabled_connector );
$plugin->save( Save_Connector_Settings_Endpoint::SETTING_PRIMARY_CONNECTOR, $primaries );
}
public static function flush_rewrite_rules() {
flush_rewrite_rules( true );
}
public static function create_emails_tables() {
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
global $wpdb;
$table_name = $wpdb->prefix . 'gravitysmtp_events';
$charset_collate = $wpdb->get_charset_collate();
$sql = "
CREATE TABLE $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
date_created datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
date_updated datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
status varchar(100) NOT NULL,
service varchar(100) NOT NULL,
subject varchar(100) NOT NULL,
message text NOT NULL,
extra mediumtext NOT NULL,
PRIMARY KEY (id)
) $charset_collate;
";
dbDelta( $sql );
$log_table_name = $wpdb->prefix . 'gravitysmtp_event_logs';
$sql = "
CREATE TABLE $log_table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
event_id mediumint(9) NOT NULL,
action_name varchar(100) NOT NULL,
log_value text NOT NULL,
date_created datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
date_updated datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
PRIMARY KEY (id)
) $charset_collate;
";
dbDelta( $sql );
$debug_log_table_name = $wpdb->prefix . 'gravitysmtp_debug_log';
$sql = "
CREATE TABLE $debug_log_table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
priority varchar(100) NOT NULL,
line text NOT NULL,
date_created datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
date_updated datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
PRIMARY KEY (id)
) $charset_collate;
";
dbDelta( $sql );
}
public static function create_suppression_table() {
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
global $wpdb;
$table_name = $wpdb->prefix . 'gravitysmtp_suppressed_emails';
$charset_collate = $wpdb->get_charset_collate();
$sql = "
CREATE TABLE $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
email varchar(100) NOT NULL,
reason varchar(100) NOT NULL,
notes text,
date_created datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
PRIMARY KEY (id),
FULLTEXT(email, notes)
) $charset_collate;
";
dbDelta( $sql );
}
/**
* Get a list of all custom table names for the plugin.
*
* @since 1.9.5
*
* @return string[]
*/
public static function get_table_names() {
return array(
'gravitysmtp_events',
'gravitysmtp_event_logs',
'gravitysmtp_debug_log',
'gravitysmtp_suppressed_emails',
);
}
public static function container() {
if ( is_null( self::$container ) ) {
self::load_providers();
}
return self::$container;
}
/**
* Enable Feature Flags once they are ready for production.
*
* @return void
*/
public static function handle_feature_flags() {
// Enable Email Management Feature
add_action( 'plugins_loaded', function() {
Feature_Flag_Manager::add( 'wp_email_management', 'WP Email Management' );
Feature_Flag_Manager::enable_flag( 'wp_email_management' );
Feature_Flag_Manager::add( 'gravitysmtp_dashboard_app', 'Dashboard App Screen' );
Feature_Flag_Manager::enable_flag( 'gravitysmtp_dashboard_app' );
Feature_Flag_Manager::add( 'amazon_ses_integration', 'Amazon SES Integration' );
Feature_Flag_Manager::enable_flag( 'amazon_ses_integration' );
Feature_Flag_Manager::add( 'gravityforms_entry_note', 'Gravity Forms Entry Note' );
Feature_Flag_Manager::enable_flag( 'gravityforms_entry_note' );
Feature_Flag_Manager::add( 'mailchimp_integration', 'Mailchimp Integration' );
Feature_Flag_Manager::enable_flag( 'mailchimp_integration' );
Feature_Flag_Manager::add( 'email_suppression', 'Email Suppression' );
Feature_Flag_Manager::enable_flag( 'email_suppression' );
Feature_Flag_Manager::add( 'zoho_integration', 'Zoho Integration' );
Feature_Flag_Manager::enable_flag( 'zoho_integration' );
Feature_Flag_Manager::add( 'experimental_features_setting', 'Experimental Features Setting' );
Feature_Flag_Manager::enable_flag( 'experimental_features_setting' );
Feature_Flag_Manager::add( 'alerts_management', 'Alerts Management' );
Feature_Flag_Manager::add( 'mailersend_integration', 'MailerSend Integration' );
Feature_Flag_Manager::enable_flag( 'mailersend_integration' );
Feature_Flag_Manager::add( 'elasticemail_integration', 'Elastic Email Integration' );
Feature_Flag_Manager::enable_flag( 'elasticemail_integration' );
Feature_Flag_Manager::add( 'smtp2go_integration', 'SMTP2GO Integration' );
Feature_Flag_Manager::enable_flag( 'smtp2go_integration' );
Feature_Flag_Manager::add( 'mailjet_integration', 'Mailjet Integration' );
Feature_Flag_Manager::enable_flag( 'mailjet_integration' );
Feature_Flag_Manager::add( 'sparkpost_integration', 'SparkPost Integration' );
Feature_Flag_Manager::enable_flag( 'sparkpost_integration' );
Feature_Flag_Manager::add( 'resend_integration', 'Resend Integration' );
Feature_Flag_Manager::enable_flag( 'resend_integration' );
Feature_Flag_Manager::add( 'emailit_integration', 'Emailit Integration' );
Feature_Flag_Manager::enable_flag( 'emailit_integration' );
Feature_Flag_Manager::add( 'smtpcom_integration', 'SMTP.com Integration' );
Feature_Flag_Manager::enable_flag( 'smtpcom_integration' );
Feature_Flag_Manager::add( 'mailtrap_integration', 'Mailtrap Integration' );
Feature_Flag_Manager::enable_flag( 'mailtrap_integration' );
Feature_Flag_Manager::add( 'cloudflare_integration', 'Cloudflare Integration' );
Feature_Flag_Manager::enable_flag( 'cloudflare_integration' );
} );
}
public static function load_early_providers() {
$full_path = __FILE__;
self::$container = new Service_Container();
self::$container->add_provider( new Users_Service_Provider() );
self::$container->add_provider( new Utils_Service_Provider() );
self::$container->add_provider( new Updates_Service_Provider( $full_path ) );
self::$container->add_provider( new Translations_Service_Provider() );
self::$container->add_provider( new Config_Collection_Service_Provider( 'gravitysmtp/v1' ) );
self::$container->add_provider( new Feature_Flags_Service_Provider() );
}
protected static function load_providers() {
if ( is_null( self::$container ) ) {
self::load_early_providers();
}
// Has already initialized.
if ( ! empty( self::$container->get( Connector_Service_Provider::EVENT_MODEL ) ) ) {
return;
}
if ( Feature_Flag_Manager::is_enabled( 'email_suppression' ) ) {
self::$container->add_provider( new Suppression_Service_Provider() );
}
// Common Providers
self::$container->add_provider( new Connector_Service_Provider() );
self::$container->add_provider( new Assets_Service_Provider( self::get_base_url(), self::get_local_dev_base_url(), self::get_base_dir() ) );
self::$container->add_provider( new App_Service_Provider( self::get_base_url() ) );
self::$container->add_provider( new Logging_Service_Provider() );
if ( Feature_Flag_Manager::is_enabled( 'experimental_features_setting' ) ) {
self::$container->add_provider( new Experimental_Features_Service_Provider() );
}
self::$container->add_provider( new Handler_Service_Provider() );
self::$container->add_provider( new Page_Service_Provider( self::get_base_url() ) );
self::$container->add_provider( new Setup_Wizard_Service_Provider() );
self::$container->add_provider( new Telemetry_Service_Provider() );
self::$container->add_provider( new Environment_Service_Provider() );
self::$container->add_provider( new Routing_Service_Provider() );
self::$container->add_provider( new Migration_Service_Provider() );
self::$container->add_provider( new Notifications_Service_Provider() );
self::$container->add_provider( new Error_Handler_Service_Provider() );
if ( Feature_Flag_Manager::is_enabled( 'wp_email_management' ) ) {
self::$container->add_provider( new Email_Management_Service_Provider() );
}
if ( Feature_Flag_Manager::is_enabled( 'alerts_management' ) ) {
self::$container->add_provider( new Alerts_Service_Provider() );
}
}
public static function get_base_url() {
return plugins_url( '', dirname( __FILE__ ) );
}
public static function get_base_dir() {
return plugin_dir_path( dirname( __FILE__ ) );
}
public static function get_local_dev_base_url() {
$url = self::get_base_url();
if ( ! defined( 'GRAVITYSMTP_ENABLE_HMR' ) || ! GRAVITYSMTP_ENABLE_HMR ) {
return $url . '/assets/js/dist';
}
$config = dirname( dirname( __FILE__ ) ) . '/local-config.json';
if ( ! file_exists( $config ) ) {
return $url . '/assets/js/dist';
}
// Get port info from local-config.json
$json = file_get_contents( $config );
$data = json_decode( $json, true );
$port = isset( $data['hmr_port'] ) ? $data['hmr_port'] : '9003';
// Set up the base URL and path.
$base = parse_url( $url, PHP_URL_HOST );
$scheme = parse_url( $url, PHP_URL_SCHEME );
return sprintf( '%s://%s:%s', $scheme, $base, $port );
}
public static function activation_hook() {
self::load_providers();
self::create_emails_tables();
do_action( 'gravitysmtp_post_activation' );
}
}
@@ -0,0 +1,857 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors;
use Gravity_Forms\Gravity_SMTP\Data_Store\Data_Store_Router;
use Gravity_Forms\Gravity_SMTP\Logging\Debug\Debug_Logger;
use Gravity_Forms\Gravity_SMTP\Logging\Log\Logger;
use Gravity_Forms\Gravity_SMTP\Data_Store\Data_Store;
use Gravity_Forms\Gravity_SMTP\Models\Event_Model;
use Gravity_Forms\Gravity_SMTP\Utils\Header_Parser;
use Gravity_Forms\Gravity_SMTP\Utils\Recipient_Parser;
/**
* Connector_Base
*
* The base class for any connector registered to the system. Handles defining sending logic,
* settings fields for the connector, and data handling.
*
* @since 1.0
*/
abstract class Connector_Base {
const SETTING_ENABLED = 'enabled';
const SETTING_ACTIVATED = 'activated';
const SETTING_CONFIGURED = 'configured';
const SETTING_FROM_EMAIL = 'from_email';
const SETTING_FROM_NAME = 'from_name';
const SETTING_FORCE_FROM_EMAIL = 'force_from_email';
const SETTING_FORCE_FROM_NAME = 'force_from_name';
const SETTING_REPLY_TO_EMAIL = 'reply_to_email';
const SETTING_FORCE_REPLY_TO_EMAIL = 'force_reply_to_email';
const SETTING_IS_PRIMARY = 'is_primary';
const SETTING_IS_BACKUP = 'is_backup';
const OBFUSCATED_STRING = '****************';
protected static $configured = null;
/**
* @var string
*/
protected $name;
/**
* @var string
*/
protected $logo;
/**
* @var string
*/
protected $full_logo;
/**
* @var string
*/
protected $title;
/**
* @var string
*/
protected $description;
/**
* @var bool
*/
protected $disabled;
/**
* @var \PHPMailer
*/
protected $php_mailer;
/**
* @var Data_Store_Router $data_store
*/
protected $data_store;
/**
* @var Logger $logger
*/
protected $logger;
/**
* @var Event_Model $emails
*/
protected $emails;
/**
* @var array
*/
protected $events;
/**
* @var array
*/
protected $atts;
/**
* @var Header_Parser
*/
protected $header_parser;
/**
* @var Recipient_Parser
*/
protected $recipient_parser;
/**
* @var Debug_Logger
*/
protected $debug_logger;
/**
* @var int
*/
protected $email;
/**
* If populated, these fields will be obfuscated when they are displayed. Useful for API keys, etc.
*
* @var array
*/
protected $sensitive_fields = array();
/**
* Calls to wp_mail() will be routed to this method if this connector is enabled. Parameters
* are a match for wp_mail().
*
* @since 1.0
*
* @return mixed
*/
abstract public function send();
/**
* Define the settings fields for this connector, matching the field types and props to those in
* the React components.
*
* @since 1.0
*
* @return array
*/
abstract public function settings_fields();
/**
* Define the data that should be saved and loaded for this connector when dealing with its
* functionality. Typically this will be the values being modified via the Settings Fields, but
* can include other data as well.
*
* @since 1.0
*
* @return array
*/
abstract public function connector_data();
/**
* Get the description for this connector. Override in each connector to translate.
*
* @return string
*/
public function get_description() {
return $this->description;
}
/**
* Define any i18n strings needed for this connector. Defaults to noop.
*
* @since 1.0
*
* @return array
*/
public function connector_i18n() {
return array();
}
/**
* A map to handle migrating existing settings to this connector. Should
* return an array of arrays containing the following values:
*
* - original_key: The key for the setting in the existing add-on.
*
* - new_key: The new key to map the value to in our system.
*
* - sub_key: The optional sub-key to search for in a multidimensional array of
* options. Arrays can be navigated using '/', e.g. 'key/subkey/subsubkey'.
*
* - transform: An optional callback to apply to the value before saving.
*
* @since 1.0
*
* @return array
*/
public function migration_map() {
return array();
}
/**
* Constructor.
*
* @since 1.0
*
* @param $php_mailer
* @param $data_store
* @param $logger
* @param $events
* @param $header_parser
* @param $recipient_parser
* @param $debug_logger
*
* @return void
*/
public function __construct( $php_mailer, $data_store, $logger, $events, $header_parser, $recipient_parser, $debug_logger ) {
$this->php_mailer = $php_mailer;
$this->data_store = $data_store;
$this->logger = $logger;
$this->events = $events;
$this->header_parser = $header_parser;
$this->recipient_parser = $recipient_parser;
$this->debug_logger = $debug_logger;
}
public function handle_suppressed_email( $email, $source ) {
$atts = $this->get_atts();
$this->set_email_log_data( $atts['subject'], $atts['message'], $email, $atts['from'], $atts['headers'], $atts['attachments'], $source, array() );
$this->events->update( array( 'status' => 'suppressed' ), $this->email );
$this->logger->log( $this->email, 'failed', 'Recipient email address ' . $email . ' is suppressed.' );
$this->debug_logger->log_error( $this->wrap_debug_with_details( __FUNCTION__, $this->email, 'Recipient email address ' . $email . ' is suppressed.' ) );
}
/**
* Initialize the connector and map attributes as necessary.
*
* @since 1.0
*
* @param $to
* @param $subject
* @param $message
* @param $headers
* @param $attachments
*
* @return void
*/
public function init( $to, $subject, $message, $headers = '', $attachments = array(), $source = '' ) {
$service_name = $this->name === 'phpmail' ? 'wp_mail' : $this->name;
$this->email = $this->events->create(
$service_name,
'pending',
'',
'',
'',
'',
array(),
);
// Set to blank values to avoid warnings.
$from = '';
$from_name = '';
/**
* Filters the wp_mail() arguments.
*
* @since 2.2.0
*
* @param array $args A compacted array of wp_mail() arguments, including the "to" email,
* subject, message, headers, and attachments values.
*/
$atts = apply_filters( 'wp_mail', compact( 'to', 'subject', 'message', 'headers', 'attachments', 'from', 'from_name', 'source' ) );
$atts['to'] = $this->recipient_parser->parse( $atts['to'] );
$parsed_headers = $this->get_parsed_headers( $atts['headers'] );
if ( isset( $parsed_headers['from'] ) ) {
$from_data = $this->get_email_from_header( 'From', $parsed_headers['from'] );
$atts['from'] = $from_data->recipients()[0]->email();
$atts['from_name'] = $from_data->recipients()[0]->name();
} else {
$atts['from'] = '';
$atts['from_name'] = '';
}
$this->atts = $atts;
do_action( 'gravitysmtp_after_connector_init', $this->email, $this );
}
/**
* Get all of the attributes for this connector.
*
* @since 1.5.0
*
* @return array
*/
public function get_atts() {
return $this->atts;
}
protected function set_email_log_data( $subject, $message, $to, $from, $headers, $attachments, $source, $params = array() ) {
$params = $this->strip_sensitive_log_data( $params );
$this->events->update(
array(
'subject' => $subject,
'message' => $message,
'extra' => serialize(
array(
'to' => $to,
'from' => $from,
'headers' => array(),
'attachments' => $attachments,
'source' => $source,
'params' => $params,
)
)
),
$this->email
);
}
private function strip_sensitive_log_data( $params ) {
unset( $params['body'] );
unset( $params['headers'] );
return $params;
}
/**
* Get an attribute, passing it through necessary filters.
*
* @since 1.0
*
* @param $att_name
* @param $default
*
* @return mixed|null
*/
public function get_att( $att_name, $default = '' ) {
$value = isset( $this->atts[ $att_name ] ) ? $this->atts[ $att_name ] : $default;
$wp_mail_filters = array( 'from', 'from_name', 'content_type', 'charset' );
if ( in_array( $att_name, $wp_mail_filters ) ) {
$value = apply_filters( 'wp_mail_' . $att_name, $value );
}
return apply_filters( 'gravitysmtp_email_attribute_' . $att_name, $value );
}
/**
* Set an attribute.
*
* @since 1.5.0
*
* @param $att_name
* @param $value
*
* @return void
*/
public function set_att( $att_name, $value ) {
$this->atts[ $att_name ] = $value;
}
/**
* Get the From email.
*
* @since 1.0
*
* @param bool $return_array Wether to return an array containing the individual parts of the from address ( 'email', 'name' and 'from') or just the From string.
*
* @return string | array
*/
protected function get_from( $return_array = false ) {
$force_from_email = $this->get_setting( self::SETTING_FORCE_FROM_EMAIL, false );
$force_from_name = $this->get_setting( self::SETTING_FORCE_FROM_NAME, false );
if ( empty( $force_from_email ) && empty( $force_from_name ) ) {
$from = $this->get_att( 'from', '' );
if ( empty( $from ) ) {
$from = $this->get_setting( self::SETTING_FROM_EMAIL, '' );
}
$from_name = $this->get_att( 'from_name', '' );
if ( empty( $from_name ) ) {
$from_name = $this->get_setting( self::SETTING_FROM_NAME, '' );
}
} else {
$from = ! empty( $force_from_email )
? $this->get_setting( self::SETTING_FROM_EMAIL, '' )
: $this->get_att( 'from', '' );
$from_name = ! empty( $force_from_name )
? $this->get_setting( self::SETTING_FROM_NAME, '' )
: $this->get_att( 'from_name', '' );
}
// From was not passed; use admin email
if ( empty( $from ) ) {
$from = get_option( 'admin_email' );
}
// RFC 5322: quote display names that contain specials so parsers
// don't misinterpret them (e.g. parentheses treated as comments).
if ( ! empty( $from_name ) && preg_match( '/[()<>\[\]:;@\\\\",.]/', $from_name ) ) {
$from_name_quoted = '"' . str_replace( array( '\\', '"' ), array( '\\\\', '\\"' ), $from_name ) . '"';
} else {
$from_name_quoted = $from_name;
}
$from_str = ! empty( $from_name ) ? $from_name_quoted . ' <' . $from . '>' : $from;
if ( $return_array ) {
$return = array(
'email' => $from,
'from' => $from_str,
);
if ( ! empty( $from_name ) ) {
$return['name'] = $from_name;
}
return $return;
}
return $from_str;
}
/**
* Get the Reply-To email.
*
* @since 1.0
*
* @param bool $return_as_array Wether to return an array containing the individual parts of the reply-to address or just the Reply-To string.
*
* @return string | array
*/
public function get_reply_to( $return_as_array = false ) {
$force_reply_to_setting = $this->get_setting( self::SETTING_FORCE_REPLY_TO_EMAIL, false );
$default_reply_to_setting = $this->get_setting( self::SETTING_REPLY_TO_EMAIL, '' );
$parsed_headers = $this->get_parsed_headers( $this->atts['headers'] );
$forcing_reply_to = $force_reply_to_setting && ! empty( $default_reply_to_setting );
$defaulting_reply_to = ( ! isset( $parsed_headers['reply-to'] ) || empty( $parsed_headers['reply-to'] ) ) && ! empty( $default_reply_to_setting );
// If we're forcing the reply-to email or the reply-to header is empty, use the default reply-to email.
if ( $forcing_reply_to || $defaulting_reply_to ) {
return $return_as_array ? array( array( 'email' => $default_reply_to_setting ) ) : $default_reply_to_setting;
}
if ( ! isset( $parsed_headers['reply-to'] ) || empty( $parsed_headers['reply-to'] ) ) {
return $return_as_array ? array() : '';
}
$email_data = $this->get_email_from_header( 'Reply-To', $parsed_headers['reply-to'] );
return $return_as_array ? $email_data->as_array() : $email_data->as_string();
}
/**
* Get the sensitive fields array for this connector
*
* @since 1.9.0
*
* @return array
*/
public function get_sensitive_fields() {
return $this->sensitive_fields;
}
public function get_request_params() {
return array();
}
/**
* Get the default From settings fields.
*
* @since 1.0
*
* @return array[] Returns an array of settings fields.
*/
protected function get_from_settings_fields() {
return array(
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'Default From Email', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'name' => self::SETTING_FROM_EMAIL,
'spacing' => 6,
'size' => 'size-l',
'value' => $this->get_setting( self::SETTING_FROM_EMAIL, '' ),
),
),
array(
'component' => 'Toggle',
'props' => array(
'initialChecked' => (bool) $this->get_setting( self::SETTING_FORCE_FROM_EMAIL, false ),
'labelAttributes' => array(
'label' => esc_html__( 'Force From Email', 'gravitysmtp' ),
),
'helpTextAttributes' => array(
'content' => esc_html__( 'If Force Email is enabled, the Default From Email address will override other plugin settings for all outgoing emails.', 'gravitysmtp' ),
'size' => 'text-xs',
'spacing' => array( 2, 0, 0, 0 ),
'weight' => 'regular',
),
'helpTextWidth' => 'full',
'labelPosition' => 'left',
'name' => self::SETTING_FORCE_FROM_EMAIL,
'size' => 'size-m',
'spacing' => 6,
'width' => 'full',
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'Default From Name', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'name' => self::SETTING_FROM_NAME,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_FROM_NAME, '' ),
),
),
array(
'component' => 'Toggle',
'props' => array(
'initialChecked' => (bool) $this->get_setting( self::SETTING_FORCE_FROM_NAME, false ),
'labelAttributes' => array(
'label' => esc_html__( 'Force From Name', 'gravitysmtp' ),
),
'helpTextAttributes' => array(
'content' => esc_html__( 'If Force Name is enabled, the Default From Name will override other plugin settings for all outgoing emails.', 'gravitysmtp' ),
'size' => 'text-xs',
'spacing' => array( 2, 0, 0, 0 ),
'weight' => 'regular',
),
'helpTextWidth' => 'full',
'labelPosition' => 'left',
'name' => self::SETTING_FORCE_FROM_NAME,
'size' => 'size-m',
'spacing' => 6,
'width' => 'full',
),
),
);
}
/**
* Get the default Reply-To settings fields.
*
* @since 1.0
*
* @return array[] Returns an array of settings fields.
*/
protected function get_reply_to_settings_fields() {
return array(
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'Default Reply-To Email', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'name' => self::SETTING_REPLY_TO_EMAIL,
'spacing' => 6,
'size' => 'size-l',
'value' => $this->get_setting( self::SETTING_REPLY_TO_EMAIL, '' ),
),
),
array(
'component' => 'Toggle',
'props' => array(
'initialChecked' => (bool) $this->get_setting( self::SETTING_FORCE_REPLY_TO_EMAIL, false ),
'labelAttributes' => array(
'label' => esc_html__( 'Force Reply-To Email', 'gravitysmtp' ),
),
'helpTextAttributes' => array(
'content' => esc_html__( 'If Force Reply-To Email is enabled, the Default Reply-To Email address will override other plugin settings for all outgoing emails.', 'gravitysmtp' ),
'size' => 'text-xs',
'spacing' => array( 2, 0, 0, 0 ),
'weight' => 'regular',
),
'helpTextWidth' => 'full',
'labelPosition' => 'left',
'name' => self::SETTING_FORCE_REPLY_TO_EMAIL,
'size' => 'size-m',
'spacing' => 6,
'width' => 'full',
),
),
);
}
/**
* Retrieve any additional message headers that may have been added, whether through filters or
* custom code.
*
* @since 1.0
*
* @return array
*/
public function get_filtered_message_headers() {
$headers = $this->get_parsed_headers( $this->get_att( 'headers', array() ) );
foreach( $this->header_parser->standard_headers as $header ) {
unset( $headers[ $header ] );
}
return array_unique( $headers );
}
/**
* Get parsed/normalized headers for use in PHP Mailer.
*
* @since 1.0
*
* @param $headers
*
* @return array
*/
protected function get_parsed_headers( $headers ) {
$parsed_headers = $this->header_parser->parse( $headers );
if ( ! isset( $parsed_headers['content-type'] ) ) {
$parsed_headers['content-type'] = 'text/plain';
}
return $parsed_headers;
}
protected function get_header_from_string( $string ) {
return $this->header_parser->get_header_from_string( $string );
}
protected function get_formatted_cc( $values ) {
return $this->header_parser->get_formatted_cc( $values );
}
/**
* Get the email address info from the Header strings.
*
* @sicne 1.0
*
* @param $header_name
* @param $header_string
*
* @return array|array[]
*/
protected function get_email_from_header( $header_name, $header_string ) {
return $this->header_parser->get_email_from_header( $header_name, $header_string );
}
/**
* Helper method for retrieving plugin settings (i.e., settings for the plugin globally
* and not specific to this connector).
*
* @since 1.0
*
* @param $setting_name
* @param $default
*
* @return mixed|null
*/
protected function get_plugin_setting( $setting_name, $default = null ) {
return $this->data_store->get_plugin_setting( $setting_name, $default );
}
/**
* Helper method to retrieve a saved setting specifically for this connector.
*
* @since 1.0
*
* @param $setting_name
* @param $default
*
* @return mixed
*/
protected function get_setting( $setting_name, $default = null ) {
if ( $setting_name === self::SETTING_IS_BACKUP || $setting_name === self::SETTING_IS_PRIMARY ) {
$const_setting = $this->check_for_connector_status_flag( $setting_name );
if ( ! empty( $const_setting ) ) {
return $const_setting === $this->name;
}
}
return $this->data_store->get_setting( $this->name, $setting_name, $default );
}
protected function setting_should_be_obfuscated( $setting_name ) {
if ( ! in_array( $setting_name, $this->sensitive_fields ) ) {
return false;
}
return true;
}
protected function get_locked_settings() {
$return = array();
$defined_constants = array_filter( get_defined_constants(), function( $constant ) {
return strpos( $constant, 'GRAVITYSMTP_' ) !== false;
}, ARRAY_FILTER_USE_KEY );
foreach( $defined_constants as $constant => $constant_value ) {
$setting_name = strtolower( str_replace( 'GRAVITYSMTP_', '', $constant ) );
$return[] = $setting_name;
}
return $return;
}
private function check_for_connector_status_flag( $setting_name ) {
$const_check = $setting_name === self::SETTING_IS_PRIMARY ? 'GRAVITYSMTP_INTEGRATION_PRIMARY' : 'GRAVITYSMTP_INTEGRATION_BACKUP';
if ( defined( $const_check ) ) {
return constant( $const_check );
}
return false;
}
/**
* Get the mapped data for this connector to use in a Config.
*
* @since 1.0
*
* @return array
*/
public function get_data() {
$fields = $this->settings_fields();
$data = $this->get_merged_data();
if ( ! empty( $fields['fields'] ) ) {
foreach( $fields['fields'] as $idx => $field_data ) {
if ( ! array_key_exists( 'value', $field_data['props'] ) ) {
continue;
}
$name = $field_data['props']['name'];
if ( ! $this->setting_should_be_obfuscated( $name ) ) {
continue;
}
if ( empty( $fields['fields'][ $idx ]['props']['value'] ) ) {
continue;
}
$fields['fields'][$idx]['props']['value'] = self::OBFUSCATED_STRING;
}
}
foreach( $data as $key => $value ) {
if ( ! $this->setting_should_be_obfuscated( $key ) ) {
continue;
}
if ( empty( $value ) ) {
continue;
}
$data[ $key ] = self::OBFUSCATED_STRING;
}
return array(
'fields' => $fields,
'data' => $data,
'i18n' => $this->connector_i18n(),
'name' => $this->name,
'logo' => $this->logo,
'full_logo' => $this->full_logo,
'title' => $this->title,
'description' => $this->get_description(),
);
}
/**
* Get the unique data for this connector, merged with the default/common data for all
* connectors in the system.
*
* @since 1.0
*
* @return array
*/
protected function get_merged_data() {
// @todo - we might want to refactor this to use the Cache class in the future.
$configured_key = sprintf( 'gsmtp_connector_configured_%s', $this->name );
$cached = get_transient( $configured_key );
if ( $cached === false ) {
$is_configured = $this->is_configured();
$configured = ( ! is_wp_error( $is_configured ) && $is_configured !== false );
set_transient( $configured_key, array( 'configured' => $configured ), DAY_IN_SECONDS );
} else {
$configured = $cached['configured'];
}
$defaults = array(
self::SETTING_ACTIVATED => $this->get_setting( self::SETTING_ACTIVATED, true ),
self::SETTING_CONFIGURED => $configured,
self::SETTING_ENABLED => $this->get_setting( self::SETTING_ENABLED, false ),
self::SETTING_IS_PRIMARY => $this->get_setting( self::SETTING_IS_PRIMARY, false ),
self::SETTING_IS_BACKUP => $this->get_setting( self::SETTING_IS_BACKUP, false ),
);
return array_merge( $this->connector_data(), $defaults );
}
/**
* Whether this connector has been configured by the user. Defaults to checking for stored
* settings values, but can be overridden for other logic.
*
* @since 1.0
*
* @return bool
*/
public function is_configured() {
$configured = $this->get_setting( self::SETTING_CONFIGURED, null );
if ( ! is_null( $configured ) ) {
return $configured;
}
return false;
}
/**
* Whether test mode setting is enabled for the plugin.
*
* @since 1.0
*
* @return bool
*/
protected function is_test_mode() {
$test_mode = $this->get_plugin_setting( 'test_mode', 'false' );
if ( empty( $test_mode ) ) {
$test_mode = false;
} else {
$test_mode = $test_mode !== 'false';
}
return $test_mode;
}
protected function wrap_debug_with_details( $function, $email, $message ) {
return sprintf( '%s(): [EMAIL ID %s] - %s', $function, $email, $message );
}
}
@@ -0,0 +1,55 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors;
class Connector_Factory {
protected $php_mailer;
protected $data_store;
protected $logger;
protected $emails;
protected $header_parser;
protected $recipient_parser;
protected $debug_logger;
public function __construct( $php_mailer, $data_store, $logger, $emails, $header_parser, $recipient_parser, $debug_logger ) {
$this->php_mailer = $php_mailer;
$this->data_store = $data_store;
$this->logger = $logger;
$this->emails = $emails;
$this->header_parser = $header_parser;
$this->recipient_parser = $recipient_parser;
$this->debug_logger = $debug_logger;
}
public function create( $type ) {
if ( $type === 'amazon-ses' ) {
$type = 'Amazon_SES';
}
if ( $type === 'mailersend' ) {
$type = 'MailerSend';
}
if ( $type === 'elastic_email' ) {
$type = 'Elastic_Email';
}
if( $type === 'SMTP2GO' ) {
$type = 'smtp2go';
}
if ( $type === 'smtpcom' ) {
$type = 'SMTPCom';
}
$classname = sprintf( '%s\Types\Connector_%s', __NAMESPACE__, ucfirst( $type ) );
if ( ! class_exists( $classname ) ) {
throw new \InvalidArgumentException( 'Connector type for type ' . $type . ' with class ' . $classname . ' does not exist.' );
}
return new $classname( $this->php_mailer, $this->data_store, $this->logger, $this->emails, $this->header_parser, $this->recipient_parser, $this->debug_logger );
}
}
@@ -0,0 +1,645 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors;
use Gravity_Forms\Gravity_SMTP\Apps\Config\Tools_Config;
use Gravity_Forms\Gravity_SMTP\Connectors\Config\Connector_Config;
use Gravity_Forms\Gravity_SMTP\Connectors\Config\Connector_Endpoints_Config;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Check_Background_Tasks_Endpoint;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Cleanup_Data_Endpoint;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Get_Connector_Emails;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Get_Single_Email_Data_Endpoint;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Save_Connector_Settings_Endpoint;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Save_Plugin_Settings_Endpoint;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Send_Test_Endpoint;
use Gravity_Forms\Gravity_SMTP\Connectors\Oauth\Google_Oauth_Handler;
use Gravity_Forms\Gravity_SMTP\Connectors\Oauth\Microsoft_Oauth_Handler;
use Gravity_Forms\Gravity_SMTP\Connectors\Oauth\Zoho_Oauth_Handler;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_Amazon;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_Brevo;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_Cloudflare;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_Elastic_Email;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_Emailit;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_Generic;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_Google;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_Mailchimp;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_Mailersend;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_Mailgun;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_Mailjet;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_Mailtrap;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_Microsoft;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_PHPMail;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_Postmark;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_Resend;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_Sendgrid;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_SMTP2GO;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_Sparkpost;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_SMTPCom;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_Zoho;
use Gravity_Forms\Gravity_SMTP\Data_Store\Const_Data_Store;
use Gravity_Forms\Gravity_SMTP\Data_Store\Data_Store_Router;
use Gravity_Forms\Gravity_SMTP\Data_Store\Opts_Data_Store;
use Gravity_Forms\Gravity_SMTP\Data_Store\Plugin_Opts_Data_Store;
use Gravity_Forms\Gravity_SMTP\Logging\Debug\Debug_Logger;
use Gravity_Forms\Gravity_SMTP\Logging\Log\Logger;
use Gravity_Forms\Gravity_SMTP\Logging\Logging_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Models\Debug_Log_Model;
use Gravity_Forms\Gravity_SMTP\Models\Event_Model;
use Gravity_Forms\Gravity_SMTP\Models\Hydrators\Hydrator_Factory;
use Gravity_Forms\Gravity_SMTP\Models\Log_Details_Model;
use Gravity_Forms\Gravity_SMTP\Models\Notifications_Model;
use Gravity_Forms\Gravity_SMTP\Users\Roles;
use Gravity_Forms\Gravity_SMTP\Utils\Booliesh;
use Gravity_Forms\Gravity_Tools\Logging\DB_Logging_Provider;
use Gravity_Forms\Gravity_Tools\Providers\Config_Collection_Service_Provider;
use Gravity_Forms\Gravity_Tools\Providers\Config_Service_Provider;
use Gravity_Forms\Gravity_Tools\Updates\Updates_Service_Provider;
use Gravity_Forms\Gravity_Tools\Utils\Utils_Service_Provider;
class Connector_Service_Provider extends Config_Service_Provider {
const CONNECTOR_FACTORY = 'connector_factory';
const PHPMAILER = 'phpmailer';
const DATA_STORE_CONST = 'data_store_const';
const DATA_STORE_OPTS = 'data_store_opts';
const DATA_STORE_PLUGIN_OPTS = 'data_store_plugin_opts';
const DATA_STORE_ROUTER = 'data_store_router';
const EVENT_MODEL = 'event_model';
const LOG_DETAILS_MODEL = 'log_details_model';
const NOTIFICATIONS_MODEL = 'notifications_model';
const HYDRATOR_FACTORY = 'hydrator_factory';
const NAME_MAP = 'name_map';
const REGISTERED_CONNECTORS = 'registered_connectors';
const CONNECTOR_DATA_MAP = 'connector_data_map';
const OAUTH_DATA_HANDLER = 'oauth_data_handler';
const GOOGLE_OAUTH_HANDLER = 'google_oauth_handler';
const MICROSOFT_OAUTH_HANDLER = 'microsoft_oauth_handler';
const ZOHO_OAUTH_HANDLER = 'zoho_oauth_handler';
const SEND_TEST_ENDPOINT = 'send_test_endpoint';
const CLEANUP_DATA_ENDPOINT = 'cleanup_data_endpoint';
const SAVE_CONNECTOR_SETTINGS_ENDPOINT = 'save_connector_settings_endpoint';
const SAVE_PLUGIN_SETTINGS_ENDPOINT = 'save_plugin_settings_endpoint';
const GET_SINGLE_EMAIL_DATA_ENDPOINT = 'get_single_email_data_endpoint';
const CHECK_BACKGROUND_TASKS_ENDPOINT = 'check_background_tasks_endpoint';
const GET_CONNECTOR_EMAILS_ENDPOINT = 'get_connector_emails_endpoint';
const CONNECTOR_ENDPOINTS_CONFIG = 'connector_endpoints_config';
const CONNECTOR_AMAZON_SES = 'Amazon';
const CONNECTOR_BREVO = 'Brevo';
const CONNECTOR_CLOUDFLARE = 'Cloudflare';
const CONNECTOR_ELASTIC_EMAIL = 'Elastic_Email';
const CONNECTOR_EMAILIT = 'Emailit';
const CONNECTOR_GENERIC = 'Generic';
const CONNECTOR_GOOGLE = 'Google';
const CONNECTOR_MAILCHIMP = 'Mailchimp';
const CONNECTOR_MAILERSEND = 'MailerSend';
const CONNECTOR_MAILGUN = 'Mailgun';
const CONNECTOR_MAILJET = 'Mailjet';
const CONNECTOR_MAILTRAP = 'Mailtrap';
const CONNECTOR_MICROSOFT = 'Microsoft';
const CONNECTOR_PHPMAIL = 'Phpmail';
const CONNECTOR_POSTMARK = 'Postmark';
const CONNECTOR_RESEND = 'Resend';
const CONNECTOR_SENDGRID = 'Sendgrid';
const CONNECTOR_SMTPCOM = 'SMTPCom';
const CONNECTOR_SMTP2GO = 'SMTP2GO';
const CONNECTOR_SPARKPOST = 'Sparkpost';
const CONNECTOR_ZOHO = 'Zoho';
protected $connectors = array(
self::CONNECTOR_AMAZON_SES => Connector_Amazon::class,
self::CONNECTOR_BREVO => Connector_Brevo::class,
self::CONNECTOR_CLOUDFLARE => Connector_Cloudflare::class,
self::CONNECTOR_ELASTIC_EMAIL => Connector_Elastic_Email::class,
self::CONNECTOR_EMAILIT => Connector_Emailit::class,
self::CONNECTOR_GENERIC => Connector_Generic::class,
self::CONNECTOR_GOOGLE => Connector_Google::class,
self::CONNECTOR_MAILCHIMP => Connector_Mailchimp::class,
self::CONNECTOR_MAILERSEND => Connector_Mailersend::class,
self::CONNECTOR_MAILGUN => Connector_Mailgun::class,
self::CONNECTOR_MAILJET => Connector_Mailjet::class,
self::CONNECTOR_MAILTRAP => Connector_Mailtrap::class,
self::CONNECTOR_MICROSOFT => Connector_Microsoft::class,
self::CONNECTOR_PHPMAIL => Connector_PHPMail::class,
self::CONNECTOR_POSTMARK => Connector_Postmark::class,
self::CONNECTOR_RESEND => Connector_Resend::class,
self::CONNECTOR_SENDGRID => Connector_Sendgrid::class,
self::CONNECTOR_SMTPCOM => Connector_SMTPCom::class,
self::CONNECTOR_SMTP2GO => Connector_SMTP2GO::class,
self::CONNECTOR_SPARKPOST => Connector_Sparkpost::class,
self::CONNECTOR_ZOHO => Connector_Zoho::class,
);
protected $configs = array(
self::CONNECTOR_ENDPOINTS_CONFIG => Connector_Endpoints_Config::class,
);
public function register( \Gravity_Forms\Gravity_Tools\Service_Container $container ) {
parent::register( $container );
$self = $this;
$this->container->add( self::PHPMAILER, function () {
global $phpmailer;
// (Re)create it, if it's gone missing.
if ( ! ( $phpmailer ) ) {
if ( file_exists( ABSPATH . WPINC . '/PHPMailer/PHPMailer.php' ) ) {
require_once ABSPATH . WPINC . '/PHPMailer/PHPMailer.php';
require_once ABSPATH . WPINC . '/PHPMailer/SMTP.php';
require_once ABSPATH . WPINC . '/PHPMailer/Exception.php';
$phpmailer = new \PHPMailer\PHPMailer\PHPMailer( true );
} elseif ( file_exists( ABSPATH . WPINC . '/class-phpmailer.php' ) ) {
require_once ABSPATH . WPINC . '/class-phpmailer.php';
require_once ABSPATH . WPINC . '/class-smtp.php';
$phpmailer = new PHPMailer( true );
}
$phpmailer::$validator = static function ( $email ) {
return (bool) is_email( $email );
};
}
return $phpmailer;
} );
$this->container->add( self::HYDRATOR_FACTORY, function () {
return new Hydrator_Factory();
} );
$this->container->add( self::DATA_STORE_CONST, function () {
return new Const_Data_Store();
} );
$this->container->add( self::DATA_STORE_OPTS, function () {
return new Opts_Data_Store();
} );
$this->container->add( self::DATA_STORE_PLUGIN_OPTS, function () {
return new Plugin_Opts_Data_Store();
} );
$this->container->add( self::EVENT_MODEL, function () use ( $container ) {
return new Event_Model( $container->get( self::HYDRATOR_FACTORY ), $container->get( self::DATA_STORE_ROUTER ), $container->get( Utils_Service_Provider::RECIPIENT_PARSER ), $container->get( Utils_Service_Provider::FILTER_PARSER ) );
} );
$this->container->add( self::LOG_DETAILS_MODEL, function () use ( $container ) {
return new Log_Details_Model( $container->get( self::DATA_STORE_PLUGIN_OPTS ) );
} );
$this->container->add( self::NOTIFICATIONS_MODEL, function () use ( $container ) {
return new Notifications_Model();
} );
$this->container->add( Logging_Service_Provider::LOGGER, function () use ( $container ) {
return new Logger( $container->get( self::LOG_DETAILS_MODEL ) );
} );
$this->container->add( Logging_Service_Provider::DEBUG_LOG_MODEL, function () use ( $container ) {
return new Debug_Log_Model();
} );
$this->container->add( Logging_Service_Provider::DB_LOGGING_PROVIDER, function () use ( $container ) {
return new DB_Logging_Provider( $container->get( Logging_Service_Provider::DEBUG_LOG_MODEL ) );
} );
$this->container->add( Logging_Service_Provider::DEBUG_LOGGER, function () use ( $container ) {
$data = $container->get( self::DATA_STORE_ROUTER );
$log_level = $data->get_plugin_setting( Tools_Config::SETTING_DEBUG_LOG_LEVEL, DB_Logging_Provider::DEBUG );
return new Debug_Logger( $container->get( Logging_Service_Provider::DB_LOGGING_PROVIDER ), $log_level );
} );
$this->container->add( self::DATA_STORE_ROUTER, function () use ( $container ) {
return new Data_Store_Router( $container->get( self::DATA_STORE_CONST ), $container->get( self::DATA_STORE_OPTS ), $container->get( self::DATA_STORE_PLUGIN_OPTS ) );
} );
$this->container->add( self::CONNECTOR_FACTORY, function () use ( $container ) {
return new Connector_Factory(
$container->get( self::PHPMAILER ),
$container->get( self::DATA_STORE_ROUTER ),
$container->get( Logging_Service_Provider::LOGGER ),
$container->get( self::EVENT_MODEL ),
$container->get( Utils_Service_Provider::HEADER_PARSER ),
$container->get( Utils_Service_Provider::RECIPIENT_PARSER ),
$container->get( Logging_Service_Provider::DEBUG_LOGGER )
);
} );
$this->container->add( self::SAVE_CONNECTOR_SETTINGS_ENDPOINT, function () use ( $container ) {
return new Save_Connector_Settings_Endpoint( $container->get( self::DATA_STORE_OPTS ), $container->get( self::DATA_STORE_PLUGIN_OPTS ), $container->get( self::CONNECTOR_FACTORY ) );
} );
$this->container->add( self::CLEANUP_DATA_ENDPOINT, function () use ( $container ) {
return new Cleanup_Data_Endpoint( $container->get( self::DATA_STORE_PLUGIN_OPTS ) );
} );
$this->container->add( self::SAVE_PLUGIN_SETTINGS_ENDPOINT, function () use ( $container ) {
return new Save_Plugin_Settings_Endpoint( $container->get( self::DATA_STORE_PLUGIN_OPTS ), $container->get( Updates_Service_Provider::LICENSE_API_CONNECTOR ) );
} );
$this->container->add( self::GET_SINGLE_EMAIL_DATA_ENDPOINT, function () use ( $container ) {
return new Get_Single_Email_Data_Endpoint( $container->get( self::LOG_DETAILS_MODEL ), $container->get( self::EVENT_MODEL ) );
} );
$this->container->add( self::CHECK_BACKGROUND_TASKS_ENDPOINT, function () {
return new Check_Background_Tasks_Endpoint();
} );
$this->container->add( self::SEND_TEST_ENDPOINT, function () use ( $container ) {
return new Send_Test_Endpoint( $container->get( self::CONNECTOR_FACTORY ), $container->get( self::DATA_STORE_ROUTER ), $container->get( self::EVENT_MODEL ), $container->get( self::LOG_DETAILS_MODEL ), $container->get( self::GET_SINGLE_EMAIL_DATA_ENDPOINT ) );
} );
$this->container->add( self::GET_CONNECTOR_EMAILS_ENDPOINT, function () use ( $container ) {
return new Get_Connector_Emails( $container->get( self::NOTIFICATIONS_MODEL ) );
} );
$this->container->add( self::OAUTH_DATA_HANDLER, function () use ( $container ) {
return new Oauth_Data_Handler( $container->get( self::DATA_STORE_ROUTER ), $container->get( self::DATA_STORE_OPTS ) );
} );
$this->container->add( self::GOOGLE_OAUTH_HANDLER, function () use ( $container ) {
return new Google_Oauth_Handler( $container->get( self::OAUTH_DATA_HANDLER ) );
} );
$this->container->add( self::MICROSOFT_OAUTH_HANDLER, function () use ( $container ) {
return new Microsoft_Oauth_Handler( $container->get( self::OAUTH_DATA_HANDLER ) );
} );
$this->container->add( self::ZOHO_OAUTH_HANDLER, function () use ( $container ) {
return new Zoho_Oauth_Handler( $container->get( self::OAUTH_DATA_HANDLER ) );
} );
$this->container->add( self::REGISTERED_CONNECTORS, function () use ( $self ) {
return $self->connectors;
} );
$this->register_connector_data();
}
public function init( \Gravity_Forms\Gravity_Tools\Service_Container $container ) {
add_action( 'init', function () use ( $container ) {
$page = filter_input( INPUT_GET, 'page' );
if ( $page !== 'gravitysmtp-settings' ) {
return;
}
$connectors = $container->get( self::REGISTERED_CONNECTORS );
foreach ( $connectors as $service => $class ) {
$configured_key = sprintf( 'gsmtp_connector_configured_%s', strtolower( $service ) );
delete_transient( $configured_key );
}
}, 11 );
// @todo - replace this with some AJAX action via JS
add_action( 'admin_post_smtp_disconnect_google', function () use ( $container ) {
check_admin_referer( 'gsmtp_disconnect_google' );
// Bail if current user does not have the permissions to be here.
if ( ! current_user_can( Roles::EDIT_INTEGRATIONS ) ) {
return;
}
$configured_key = sprintf( 'gsmtp_connector_configured_%s', 'google' );
delete_transient( $configured_key );
/**
* @var Opts_Data_Store $data
*/
$data = $container->get( self::DATA_STORE_OPTS );
/**
* @var Data_Store_Router
*/
$data_router = $container->get( self::DATA_STORE_ROUTER );
/**
* @var Plugin_Opts_Data_Store
*/
$plugin_data_store = $container->get( self::DATA_STORE_PLUGIN_OPTS );
$data->delete_all( 'google' );
$connector_values = $data_router->get_plugin_setting( Save_Connector_Settings_Endpoint::SETTING_PRIMARY_CONNECTOR, array() );
if ( ! is_array( $connector_values ) ) {
$connector_values = array();
}
$connector_values['google'] = 'false';
$plugin_data_store->save( Save_Connector_Settings_Endpoint::SETTING_PRIMARY_CONNECTOR, $connector_values );
$connector_values = $data_router->get_plugin_setting( Save_Connector_Settings_Endpoint::SETTING_BACKUP_CONNECTOR, array() );
if ( ! is_array( $connector_values ) ) {
$connector_values = array();
}
$connector_values['google'] = 'false';
$plugin_data_store->save( Save_Connector_Settings_Endpoint::SETTING_BACKUP_CONNECTOR, $connector_values );
$connector_values = $data_router->get_plugin_setting( Save_Connector_Settings_Endpoint::SETTING_ENABLED_CONNECTOR, array() );
if ( ! is_array( $connector_values ) ) {
$connector_values = array();
}
$connector_values['google'] = 'false';
$plugin_data_store->save( Save_Connector_Settings_Endpoint::SETTING_ENABLED_CONNECTOR, $connector_values );
/**
* @var Google_Oauth_Handler $oauth_handler
*/
$oauth_handler = $container->get( self::GOOGLE_OAUTH_HANDLER );
$return_url = urldecode( $oauth_handler->get_return_url( false ) );
wp_safe_redirect( $return_url );
} );
add_action( 'admin_post_smtp_disconnect_microsoft', function () use ( $container ) {
check_admin_referer( 'gsmtp_disconnect_microsoft' );
// Bail if current user does not have the permissions to be here.
if ( ! current_user_can( Roles::EDIT_INTEGRATIONS ) ) {
return;
}
$configured_key = sprintf( 'gsmtp_connector_configured_%s', 'microsoft' );
delete_transient( $configured_key );
/**
* @var Opts_Data_Store $data
*/
$data = $container->get( self::DATA_STORE_OPTS );
/**
* @var Data_Store_Router
*/
$data_router = $container->get( self::DATA_STORE_ROUTER );
/**
* @var Plugin_Opts_Data_Store
*/
$plugin_data_store = $container->get( self::DATA_STORE_PLUGIN_OPTS );
$data->delete_all( 'microsoft' );
$connector_values = $data_router->get_plugin_setting( Save_Connector_Settings_Endpoint::SETTING_PRIMARY_CONNECTOR, array() );
if ( ! is_array( $connector_values ) ) {
$connector_values = array();
}
$connector_values['microsoft'] = 'false';
$plugin_data_store->save( Save_Connector_Settings_Endpoint::SETTING_PRIMARY_CONNECTOR, $connector_values );
$connector_values = $data_router->get_plugin_setting( Save_Connector_Settings_Endpoint::SETTING_BACKUP_CONNECTOR, array() );
if ( ! is_array( $connector_values ) ) {
$connector_values = array();
}
$connector_values['microsoft'] = 'false';
$plugin_data_store->save( Save_Connector_Settings_Endpoint::SETTING_BACKUP_CONNECTOR, $connector_values );
$connector_values = $data_router->get_plugin_setting( Save_Connector_Settings_Endpoint::SETTING_ENABLED_CONNECTOR, array() );
if ( ! is_array( $connector_values ) ) {
$connector_values = array();
}
$connector_values['microsoft'] = 'false';
$plugin_data_store->save( Save_Connector_Settings_Endpoint::SETTING_ENABLED_CONNECTOR, $connector_values );
/**
* @var Microsoft_Oauth_Handler $oauth_handler
*/
$oauth_handler = $container->get( self::MICROSOFT_OAUTH_HANDLER );
$return_url = urldecode( $oauth_handler->get_return_url( 'settings' ) );
wp_safe_redirect( $return_url );
} );
add_action( 'admin_post_smtp_disconnect_zoho', function () use ( $container ) {
check_admin_referer( 'gsmtp_disconnect_zoho' );
// Bail if current user does not have the permissions to be here.
if ( ! current_user_can( Roles::EDIT_INTEGRATIONS ) ) {
return;
}
$configured_key = sprintf( 'gsmtp_connector_configured_%s', 'zoho' );
delete_transient( $configured_key );
/**
* @var Opts_Data_Store $data
*/
$data = $container->get( self::DATA_STORE_OPTS );
/**
* @var Data_Store_Router
*/
$data_router = $container->get( self::DATA_STORE_ROUTER );
/**
* @var Plugin_Opts_Data_Store
*/
$plugin_data_store = $container->get( self::DATA_STORE_PLUGIN_OPTS );
$data->delete_all( 'zoho' );
$connector_values = $data_router->get_plugin_setting( Save_Connector_Settings_Endpoint::SETTING_PRIMARY_CONNECTOR, array() );
if ( ! is_array( $connector_values ) ) {
$connector_values = array();
}
$connector_values['zoho'] = 'false';
$plugin_data_store->save( Save_Connector_Settings_Endpoint::SETTING_PRIMARY_CONNECTOR, $connector_values );
$connector_values = $data_router->get_plugin_setting( Save_Connector_Settings_Endpoint::SETTING_BACKUP_CONNECTOR, array() );
if ( ! is_array( $connector_values ) ) {
$connector_values = array();
}
$connector_values['zoho'] = 'false';
$plugin_data_store->save( Save_Connector_Settings_Endpoint::SETTING_BACKUP_CONNECTOR, $connector_values );
$connector_values = $data_router->get_plugin_setting( Save_Connector_Settings_Endpoint::SETTING_ENABLED_CONNECTOR, array() );
if ( ! is_array( $connector_values ) ) {
$connector_values = array();
}
$connector_values['zoho'] = 'false';
$plugin_data_store->save( Save_Connector_Settings_Endpoint::SETTING_ENABLED_CONNECTOR, $connector_values );
/**
* @var Zoho_Oauth_Handler $oauth_handler
*/
$oauth_handler = $container->get( self::ZOHO_OAUTH_HANDLER );
$return_url = urldecode( $oauth_handler->get_return_url( false ) );
wp_safe_redirect( $return_url );
} );
add_action( 'wp_ajax_' . Cleanup_Data_Endpoint::ACTION_NAME, function () use ( $container ) {
$container->get( self::CLEANUP_DATA_ENDPOINT )->handle();
} );
add_action( 'wp_ajax_' . Send_Test_Endpoint::ACTION_NAME, function () use ( $container ) {
$container->get( self::SEND_TEST_ENDPOINT )->handle();
} );
add_action( 'wp_ajax_' . Save_Connector_Settings_Endpoint::ACTION_NAME, function () use ( $container ) {
$container->get( self::SAVE_CONNECTOR_SETTINGS_ENDPOINT )->handle();
} );
add_action( 'wp_ajax_' . Save_Plugin_Settings_Endpoint::ACTION_NAME, function () use ( $container ) {
$container->get( self::SAVE_PLUGIN_SETTINGS_ENDPOINT )->handle();
} );
add_action( 'wp_ajax_' . Get_Single_Email_Data_Endpoint::ACTION_NAME, function () use ( $container ) {
$container->get( self::GET_SINGLE_EMAIL_DATA_ENDPOINT )->handle();
} );
add_action( 'wp_ajax_' . Check_Background_Tasks_Endpoint::ACTION_NAME, function () use ( $container ) {
$container->get( self::CHECK_BACKGROUND_TASKS_ENDPOINT )->handle();
} );
add_action( 'wp_ajax_' . Get_Connector_Emails::ACTION_NAME, function () use ( $container ) {
$container->get( self::GET_CONNECTOR_EMAILS_ENDPOINT )->handle();
} );
add_filter( 'gform_localized_script_data_gravitysmtp_admin_config', function ( $data ) {
if (
empty( $data['components']['settings']['data']['integrations'] ) &&
empty( $data['components']['setup_wizard']['data']['integrations'] ) &&
empty( $data['components']['tools']['data']['integrations'] )
) {
return $data;
}
$order = array(
'amazon-ses',
'brevo',
'cloudflare',
'elastic_email',
'emailit',
'generic',
'google-gmail',
'mailchimp',
'mailersend',
'mailgun',
'mailjet',
'mailtrap',
'microsoft',
'phpmail',
'postmark',
'sendgrid',
'smtpcom',
'smtp2go',
'sparkpost',
'zoho-mail',
);
// todo: setup wizard data should only be injected if should display is true for the app: includes/apps/setup-wizard/config/class-setup-wizard-config.php:18
foreach ( array( 'settings', 'setup_wizard', 'tools' ) as $app ) {
if ( empty( $data['components'][ $app ]['data']['integrations'] ) ) {
continue;
}
$integrations = $data['components'][ $app ]['data']['integrations'];
usort( $integrations, function ( $a, $b ) use ( $order ) {
$a_pos = array_search( $a['id'], $order );
$b_pos = array_search( $b['id'], $order );
if ( $a_pos === $b_pos ) {
return 0;
}
return $a_pos < $b_pos ? - 1 : 1;
} );
$data['components'][ $app ]['data']['integrations'] = $integrations;
}
return $data;
} );
}
private function register_connector_data() {
$is_ajax = defined( 'DOING_AJAX' ) && DOING_AJAX;
$page = filter_input( INPUT_GET, 'page' );
if ( ! $is_ajax && ! is_string( $page ) ) {
return;
}
if ( ! empty( $page ) ) {
$page = htmlspecialchars( $page );
}
if ( is_null( $page ) ) {
$page = '';
}
$plugin_data_store = $this->container->get( self::DATA_STORE_PLUGIN_OPTS );
$should_display = Booliesh::get( $plugin_data_store->get( Save_Plugin_Settings_Endpoint::PARAM_SETUP_WIZARD_SHOULD_DISPLAY, 'config', 'true' ) );
$should_register = $should_display ? strpos( $page, 'gravitysmtp-' ) !== false : in_array( $page, array(
'gravitysmtp-activity-log',
'gravitysmtp-dashboard',
'gravitysmtp-settings',
'gravitysmtp-suppression',
'gravitysmtp-tools',
) );
if ( $is_ajax ) {
$action = filter_input( INPUT_POST, 'action' );
if ( $action === 'migrate_settings' || $action === 'get_dashboard_data' ) {
$should_register = true;
}
}
if ( empty( $should_register ) ) {
return;
}
$connectors = apply_filters( 'gravitysmtp_connector_types', $this->connectors );
$config_collection = $this->container->get( Config_Collection_Service_Provider::CONFIG_COLLECTION );
$parser = $this->container->get( Config_Collection_Service_Provider::DATA_PARSER );
/**
* @var Connector_Factory $factory
*/
$factory = $this->container->get( self::CONNECTOR_FACTORY );
$name_map = array();
$data_map = array();
foreach ( $connectors as $connector_name => $connector ) {
$instance = $factory->create( $connector_name );
$config = new Connector_Config( $parser );
$connector_data = $instance->get_data();
$config->set_data( $connector_data );
$config_collection->add_config( $config );
$name_map[ $connector_data['name'] ] = $connector_data['title'];
$data_map[ $connector_data['name'] ] = $connector_data;
}
$this->container->add( self::NAME_MAP, $name_map );
$this->container->add( self::CONNECTOR_DATA_MAP, $data_map );
}
}
@@ -0,0 +1,35 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors;
use Gravity_Forms\Gravity_SMTP\Data_Store\Data_Store_Router;
use Gravity_Forms\Gravity_SMTP\Data_Store\Opts_Data_Store;
use Gravity_Forms\Gravity_SMTP\Data_Store\Plugin_Opts_Data_Store;
use Gravity_Forms\Gravity_Tools\Data\Oauth_Data_Handler as Oauth_Data_Handler_Base;
class Oauth_Data_Handler implements Oauth_Data_Handler_Base {
/**
* @var Data_Store_Router $data
*/
protected $data;
/**
* @var Opts_Data_Store
*/
protected $opts_store;
public function __construct( $data_router, $opts_store ) {
$this->data = $data_router;
$this->opts_store = $opts_store;
}
public function get( $key, $connector = 'config' ) {
return $this->data->get_setting( $connector, $key );
}
public function save( $key, $value, $connector = 'config' ) {
return $this->opts_store->save( $key, $value, $connector );
}
}
@@ -0,0 +1,93 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Config;
use Gravity_Forms\Gravity_SMTP\Apps\App_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Gravity_SMTP;
use Gravity_Forms\Gravity_Tools\Config;
class Connector_Config extends Config {
protected $script_to_localize = 'gravitysmtp_scripts_admin';
protected $name = 'gravitysmtp_admin_config';
protected $overwrite = false;
protected $fields;
protected $logo;
protected $full_logo;
protected $title;
protected $description;
protected $short_name;
protected $data;
protected $i18n;
public function set_data( $data ) {
$this->fields = $data['fields'];
$this->short_name = $data['name'];
$this->logo = $data['logo'];
$this->full_logo = $data['full_logo'];
$this->title = $data['title'];
$this->description = $data['description'];
$this->data = $data['data'];
$this->i18n = $data['i18n'];
}
public function should_enqueue() {
return is_admin();
}
/**
* Config data.
*
* @return array[]
*/
public function data() {
$connector_data = array(
'title' => $this->title,
'description' => $this->description,
'id' => $this->short_name,
'logo' => $this->logo,
'full_logo' => $this->full_logo,
'settings' => $this->fields,
'data' => $this->data,
'i18n' => $this->i18n,
);
$components = array(
'settings' => array(
'data' => array(
'integrations' => array(
$connector_data,
),
),
),
'tools' => array(
'data' => array(
'integrations' => array(
$connector_data,
),
),
),
);
if ( $this->should_enqueue_setup_wizard() ) {
$components['setup_wizard'] = array(
'data' => array(
'integrations' => array(
$connector_data,
),
),
);
}
return array(
'components' => $components,
);
}
private function should_enqueue_setup_wizard() {
$should_enqueue = Gravity_SMTP::container()->get( App_Service_Provider::SHOULD_ENQUEUE_SETUP_WIZARD );
return is_callable( $should_enqueue ) ? $should_enqueue() : $should_enqueue;
}
}
@@ -0,0 +1,81 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Config;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Get_Single_Email_Data_Endpoint;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Cleanup_Data_Endpoint;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Migrate_Settings_Endpoint;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Save_Connector_Settings_Endpoint;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Save_Plugin_Settings_Endpoint;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Send_Test_Endpoint;
use Gravity_Forms\Gravity_Tools\Config;
class Connector_Endpoints_Config extends Config {
protected $script_to_localize = 'gravitysmtp_scripts_admin';
protected $name = 'gravitysmtp_admin_config';
public function should_enqueue() {
return is_admin();
}
public function data() {
return array(
'common' => array(
'endpoints' => array(
Send_Test_Endpoint::ACTION_NAME => array(
'action' => array(
'value' => Send_Test_Endpoint::ACTION_NAME,
'default' => 'mock_endpoint',
),
'nonce' => array(
'value' => wp_create_nonce( Send_Test_Endpoint::ACTION_NAME ),
'default' => 'nonce',
),
),
Save_Connector_Settings_Endpoint::ACTION_NAME => array(
'action' => array(
'value' => Save_Connector_Settings_Endpoint::ACTION_NAME,
'default' => 'mock_endpoint',
),
'nonce' => array(
'value' => wp_create_nonce( Save_Connector_Settings_Endpoint::ACTION_NAME ),
'default' => 'nonce',
),
),
Save_Plugin_Settings_Endpoint::ACTION_NAME => array(
'action' => array(
'value' => Save_Plugin_Settings_Endpoint::ACTION_NAME,
'default' => 'mock_endpoint',
),
'nonce' => array(
'value' => wp_create_nonce( Save_Plugin_Settings_Endpoint::ACTION_NAME ),
'default' => 'nonce',
),
),
Get_Single_Email_Data_Endpoint::ACTION_NAME => array(
'action' => array(
'value' => Get_Single_Email_Data_Endpoint::ACTION_NAME,
'default' => 'mock_endpoint',
),
'nonce' => array(
'value' => wp_create_nonce( Get_Single_Email_Data_Endpoint::ACTION_NAME ),
'default' => 'nonce',
),
),
Cleanup_Data_Endpoint::ACTION_NAME => array(
'action' => array(
'value' => Cleanup_Data_Endpoint::ACTION_NAME,
'default' => 'mock_endpoint',
),
'nonce' => array(
'value' => wp_create_nonce( Cleanup_Data_Endpoint::ACTION_NAME ),
'default' => 'nonce',
),
),
)
),
);
}
}
@@ -0,0 +1,24 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Endpoints;
use Gravity_Forms\Gravity_Tools\Endpoints\Endpoint;
class Check_Background_Tasks_Endpoint extends Endpoint {
const ACTION_NAME = 'gravitysmtp_check_background_tasks';
protected $minimum_cap = 'manage_options';
protected function get_nonce_name() {
return self::ACTION_NAME;
}
public function handle() {
if ( $this->validate() ) {
echo 'ok';
}
die();
}
}
@@ -0,0 +1,70 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Endpoints;
use Gravity_Forms\Gravity_Tools\Endpoints\Endpoint;
use Gravity_Forms\Gravity_SMTP\Users\Roles;
class Cleanup_Data_Endpoint extends Endpoint {
const PARAM_TARGET = 'target';
const ACTION_NAME = 'cleanup_data';
protected $minimum_cap = Roles::EDIT_INTEGRATIONS;
/**
* @var Plugin_Opts_Data_Store;
*/
protected $data_store;
public function __construct( $data_store ) {
$this->data_store = $data_store;
}
protected function get_nonce_name() {
return self::ACTION_NAME;
}
private function reset_setup_wizard_data() {
$this->data_store->save( Save_Plugin_Settings_Endpoint::PARAM_SETUP_WIZARD_SHOULD_DISPLAY, 'true' );
$this->data_store->save( Save_Plugin_Settings_Endpoint::PARAM_LICENSE_KEY, '' );
update_option( 'gravitysmtp_generic', '' );
update_option( 'gravitysmtp_mailgun', '' );
update_option( 'gravitysmtp_postmark', '' );
update_option( 'gravitysmtp_sendgrid', '' );
wp_send_json_success( __( 'Setup wizard data reset.', 'gravitysmtp' ) );
}
public function handle() {
if ( ! $this->validate() ) {
wp_send_json_error( __( 'Missing required parameters.', 'gravitysmtp' ), 400 );
}
$target = filter_input( INPUT_POST, self::PARAM_TARGET );
$target = htmlspecialchars( $target );
// handle data clean up or resets here
switch( $target ) {
case 'setup_wizard':
$this->reset_setup_wizard_data();
break;
default:
break;
}
}
protected function validate() {
if ( ! parent::validate() ) {
return false;
}
if ( empty( $_REQUEST[ self::PARAM_TARGET ] ) ) {
return false;
}
return true;
}
}
@@ -0,0 +1,65 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Endpoints;
use Gravity_Forms\Gravity_Tools\Endpoints\Endpoint;
use Gravity_Forms\Gravity_SMTP\Models\Notifications_Model;
use Gravity_Forms\Gravity_SMTP\Users\Roles;
class Get_Connector_Emails extends Endpoint {
const PARAM_CONNECTOR_NAME = 'connector_name';
const ACTION_NAME = 'get_connector_emails';
/**
* @var Notifications_Model
*/
protected $notifications;
protected $minimum_cap = Roles::VIEW_NOTIFICATIONS_SETTINGS;
protected $required_params = array(
self::PARAM_CONNECTOR_NAME,
);
public function __construct( $notifications ) {
$this->notifications = $notifications;
}
protected function get_nonce_name() {
return self::ACTION_NAME;
}
public function handle() {
if ( ! $this->validate() ) {
wp_send_json_error( __( 'Missing required parameters.', 'gravitysmtp' ), 400 );
}
$connector = rgpost( self::PARAM_CONNECTOR_NAME );
$notifications_for_connector = $this->notifications->by_service( $connector );
$emails = array();
if ( empty( $notifications_for_connector ) ) {
wp_send_json_success( $emails );
}
$notifications_for_connector = array_map( function ( $row ) use ( $connector ) {
$notifications = rgar( $row, 'notifications' );
$notifications = json_decode( $notifications, true );
$filtered = array_filter( $notifications, function ( $notification ) use ( $connector ) {
return rgar( $notification, 'service' ) == $connector && is_email( rgar( $notification, 'from' ) );
} );
return array_values( wp_list_pluck( $filtered, 'from' ) );
}, $notifications_for_connector );
foreach ( $notifications_for_connector as $found_emails ) {
$emails = array_merge( $emails, $found_emails );
}
wp_send_json_success( $emails );
}
}
@@ -0,0 +1,119 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Endpoints;
use Gravity_Forms\Gravity_SMTP\Logging\Debug\Debug_Logger;
use Gravity_Forms\Gravity_SMTP\Models\Event_Model;
use Gravity_Forms\Gravity_SMTP\Models\Log_Details_Model;
use Gravity_Forms\Gravity_SMTP\Users\Roles;
use Gravity_Forms\Gravity_Tools\Endpoints\Endpoint;
class Get_Single_Email_Data_Endpoint extends Endpoint {
const PARAM_EVENT_ID = 'event_id';
const ACTION_NAME = 'get_single_email';
protected $minimum_cap = Roles::VIEW_EMAIL_LOG_DETAILS;
/**
* @var Log_Details_Model
*/
protected $logs;
/**
* @var Event_Model
*/
protected $emails;
protected $required_params = array(
self::PARAM_EVENT_ID,
);
public function __construct( $logs, $email ) {
$this->logs = $logs;
$this->emails = $email;
}
protected function get_nonce_name() {
return self::ACTION_NAME;
}
public function handle() {
if ( ! $this->validate() ) {
wp_send_json_error( __( 'Missing required parameters.', 'gravitysmtp' ), 400 );
}
$email = filter_input( INPUT_POST, self::PARAM_EVENT_ID, FILTER_SANITIZE_NUMBER_INT );
$data = $this->data( $email );
if ( ! empty( $data ) ) {
wp_send_json_success( $data );
}
Debug_Logger::log_message(
sprintf(
/* translators: %d: event ID */
__( 'Error retrieving data for event ID: %d.', 'gravitysmtp' ),
$email
),
'error'
);
wp_send_json_error(
/* translators: %d: email ID */
sprintf( __( 'Could not send get data for event ID: %d.', 'gravitysmtp' ), $email ),
500
);
}
private function get_i18n() {
return array(
'error_alert_title' => esc_html__( 'Error Saving', 'gravitysmtp' ),
'error_alert_generic_message' => esc_html__( 'Could not save; please check your logs.', 'gravitysmtp' ),
'error_alert_close_text' => esc_html__( 'Close', 'gravitysmtp' ),
'log_detail' => array(
'top_heading' => esc_html__( 'View Email', 'gravitysmtp' ),
'top_content' => esc_html__( 'Detailed log information for this email.', 'gravitysmtp' ),
'action_button_view_email_label' => esc_html__( 'View Email', 'gravitysmtp' ),
'action_button_resend_label' => esc_html__( 'Resend', 'gravitysmtp' ),
'action_button_print_label' => esc_html__( 'Print', 'gravitysmtp' ),
'action_button_export_label' => esc_html__( 'Export', 'gravitysmtp' ),
'action_button_delete_label' => esc_html__( 'Delete Log Entry', 'gravitysmtp' ),
'main_box_heading' => esc_html__( 'Email Log', 'gravitysmtp' ),
'main_box_created_label' => esc_html__( 'Created', 'gravitysmtp' ),
'main_box_from_label' => esc_html__( 'From', 'gravitysmtp' ),
'main_box_to_label' => esc_html__( 'To', 'gravitysmtp' ),
'main_box_subject_label' => esc_html__( 'Subject', 'gravitysmtp' ),
'secondary_box_heading' => esc_html__( 'Technical Information', 'gravitysmtp' ),
'sidebar_heading' => esc_html__( 'Status', 'gravitysmtp' ),
'sidebar_status_label' => esc_html__( 'Status', 'gravitysmtp' ),
'sidebar_date_service_label' => esc_html__( 'Service:', 'gravitysmtp' ),
'sidebar_has_attachment_label' => esc_html__( 'Has attachment:', 'gravitysmtp' ),
'sidebar_log_is_label' => esc_html__( 'Log ID:', 'gravitysmtp' ),
'sidebar_source_label' => esc_html__( 'Source:', 'gravitysmtp' ),
'sidebar_attachments_heading' => esc_html__( 'Attachments', 'gravitysmtp' ),
),
);
}
public function get_log_details( $id ) {
return $this->logs->full_details( $id );
}
public function data( $email_id ) {
$details = $this->get_log_details( $email_id );
if ( empty( $details ) ) {
return array();
}
return array(
'log_detail' => $details,
'i18n' => $this->get_i18n(),
'endpoints' => array(),
);
}
}
@@ -0,0 +1,131 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Endpoints;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Base;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Factory;
use Gravity_Forms\Gravity_SMTP\Logging\Debug\Debug_Logger;
use Gravity_Forms\Gravity_SMTP\Data_Store\Plugin_Opts_Data_Store;
use Gravity_Forms\Gravity_SMTP\Users\Roles;
use Gravity_Forms\Gravity_Tools\Endpoints\Endpoint;
class Save_Connector_Settings_Endpoint extends Endpoint {
const PARAM_SETTINGS = 'settings';
const PARAM_CONNECTOR_TYPE = 'connector_type';
const PARAM_NO_VALIDATE = 'no_validate';
const SETTING_ENABLED_CONNECTOR = 'enabled_connector';
const SETTING_PRIMARY_CONNECTOR = 'primary_connector';
const SETTING_BACKUP_CONNECTOR = 'backup_connector';
const ACTION_NAME = 'save_connector_settings';
protected $minimum_cap = Roles::EDIT_INTEGRATIONS;
/**
* @var Connector_Factory $connector_factory
*/
protected $connector_factory;
/**
* @var Opts_Data_Store;
*/
protected $data_store;
/**
* @var Plugin_Opts_Data_Store
*/
protected $plugin_data_store;
protected $required_params = array(
self::PARAM_SETTINGS,
self::PARAM_CONNECTOR_TYPE,
);
public function __construct( $data_store, $plugin_data_store, $connector_factory ) {
$this->data_store = $data_store;
$this->plugin_data_store = $plugin_data_store;
$this->connector_factory = $connector_factory;
}
protected function get_nonce_name() {
return self::ACTION_NAME;
}
public function handle() {
if ( ! $this->validate() ) {
wp_send_json_error( __( 'Missing required parameters.', 'gravitysmtp' ), 400 );
}
$settings = filter_input( INPUT_POST, self::PARAM_SETTINGS, FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
$type = filter_input( INPUT_POST, self::PARAM_CONNECTOR_TYPE );
$no_validate = filter_has_var( INPUT_POST, self::PARAM_NO_VALIDATE );
$type = htmlspecialchars( $type );
$configured_key = sprintf( 'gsmtp_connector_configured_%s', $type );
$this->data_store->save_all( $settings, $type );
delete_transient( $configured_key );
// Only continue if this connector needs to be validated/enabled in some way.
if (
! isset( $settings[ Connector_Base::SETTING_ENABLED ] ) &&
! isset( $settings[ Connector_Base::SETTING_IS_PRIMARY ] ) &&
! isset( $settings[ Connector_Base::SETTING_IS_BACKUP ] )
) {
wp_send_json_success( $settings );
}
if ( isset( $settings[ Connector_Base::SETTING_ENABLED ] ) ) {
$this->save_connector_status( $type, self::SETTING_ENABLED_CONNECTOR, $settings[ Connector_Base::SETTING_ENABLED ] );
}
if ( isset( $settings[ Connector_Base::SETTING_IS_PRIMARY ] ) ) {
$this->save_connector_status( $type, self::SETTING_PRIMARY_CONNECTOR, $settings[ Connector_Base::SETTING_IS_PRIMARY ] );
}
if ( isset( $settings[ Connector_Base::SETTING_IS_BACKUP ] ) ) {
$this->save_connector_status( $type, self::SETTING_BACKUP_CONNECTOR, $settings[ Connector_Base::SETTING_IS_BACKUP ] );
}
/**
* @var Connector_Base $connector
*/
$connector = $this->connector_factory->create( $type );
$valid = $no_validate ? true : $connector->is_configured();
if ( is_wp_error( $valid ) ) {
$error_message = $valid->get_error_message();
Debug_Logger::log_message( sprintf(
/* translators: %1$s is the connector, eg: SendGrid, %2$s is the error message */
__( 'Error saving settings for %1$s: %2$s', 'gravitysmtp' ),
$type,
$error_message
), 'error' );
wp_send_json_error( $error_message, 500 );
}
wp_send_json_success( $settings );
}
/**
* Save a connector's status (enabled, primary, backup) in the settings array.
*
* @param $type
* @param $status_type
* @param $enabled
*
* @return void
*/
protected function save_connector_status( $type, $status_type, $enabled ) {
$connector_values = $this->plugin_data_store->get( $status_type, array() );
if ( ! is_array( $connector_values ) ) {
$connector_values = array();
}
$connector_values[ $type ] = $enabled;
$this->plugin_data_store->save( $status_type, $connector_values );
}
}
@@ -0,0 +1,144 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Endpoints;
use Gravity_Forms\Gravity_SMTP\Users\Roles;
use Gravity_Forms\Gravity_Tools\Endpoints\Endpoint;
use Gravity_Forms\Gravity_Tools\License\License_Statuses;
class Save_Plugin_Settings_Endpoint extends Endpoint {
const PARAM_SETTINGS = 'settings';
const PARAM_SETTING_KEY = 'key';
const PARAM_SETTING_VALUE = 'value';
const PARAM_LICENSE_KEY = 'license_key';
const PARAM_TEST_MODE = 'test_mode';
const PARAM_EVENT_LOG_ENABLED = 'event_log_enabled';
const PARAM_SAVE_EMAIL_BODY_ENABLED = 'save_email_body_enabled';
const PARAM_SAVE_ATTACHMENTS_ENABLED = 'save_attachments_enabled';
const PARAM_EVENT_LOG_RETENTION = 'event_log_retention';
const PARAM_DEBUG_LOG_ENABLED = 'debug_log_enabled';
const PARAM_DEBUG_LOG_RETENTION = 'debug_log_retention';
const PARAM_USAGE_ANALYTICS = 'usage_analytics';
const PARAM_PER_PAGE = 'activity_log_per_page';
const PARAM_MAX_EVENT_RECORDS = 'max_event_records';
const PARAM_NOTIFY_WHEN_EMAIL_SENDING_FAILS_ENABLED = 'notify_when_email_sending_fails_enabled';
const PARAM_SLACK_ALERTS_ENABLED = 'slack_alerts_enabled';
const PARAM_TWILIO_ALERTS_ENABLED = 'twilio_alerts_enabled';
const PARAM_NOTIFICATIONS_EMAIL_DIGEST_ENABLED = 'notifications_email_digest_enabled';
const PARAM_NOTIFICATIONS_EMAIL_DIGEST_FREQUENCY = 'notifications_email_digest_frequency';
const PARAM_SETUP_WIZARD_SHOULD_DISPLAY = 'setup_wizard_should_display';
const ACTION_NAME = 'save_plugin_settings';
protected $minimum_cap = Roles::EDIT_GENERAL_SETTINGS;
/**
* @var Plugin_Opts_Data_Store;
*/
protected $data_store;
/**
* @var License_API_Connector;
*/
protected $api_connector;
protected $required_params = array();
public function __construct( $data_store, $api_connector ) {
$this->data_store = $data_store;
$this->api_connector = $api_connector;
}
protected function get_nonce_name() {
return self::ACTION_NAME;
}
public function handle() {
if ( ! $this->validate() ) {
wp_send_json_error( __( 'Request must contain either an array of values to update, or a key and value to update individually.', 'gravitysmtp' ), 400 );
}
$settings = filter_input( INPUT_POST, self::PARAM_SETTINGS, FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
if ( ! empty( $settings ) ) {
$this->handle_bulk_settings( $settings );
} else {
$this->handle_individual_setting();
}
}
protected function handle_bulk_settings( $settings ) {
$this->data_store->save_all( $settings );
$data = $settings;
if ( isset( $settings[ self::PARAM_LICENSE_KEY ] ) ) {
$data = array_merge( $data, $this->handle_license_key( $settings[ self::PARAM_LICENSE_KEY ] ) );
}
wp_send_json_success( $data );
}
protected function handle_individual_setting() {
$key = htmlspecialchars( filter_input( INPUT_POST, self::PARAM_SETTING_KEY ) );
$value = isset( $_POST[ self::PARAM_SETTING_VALUE ] ) ? $_POST[ self::PARAM_SETTING_VALUE ] : null;
if ( is_array( $value ) ) {
$value = filter_input( INPUT_POST, self::PARAM_SETTING_VALUE, FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
} else {
$value = htmlspecialchars( $value );
}
switch ( $key ) {
case self::PARAM_LICENSE_KEY:
$data = $this->handle_license_key_setting( $key, $value );
break;
default:
$this->data_store->save( $key, $value );
$data = array( $key => $value );
break;
}
do_action( 'gravitysmtp_save_plugin_setting', $key, $value );
wp_send_json_success( $data );
}
protected function handle_license_key_setting( $key, $value ) {
$this->data_store->save( $key, $value );
$data = array( $key => $value );
return array_merge( $data, $this->handle_license_key( $value ) );
}
protected function handle_license_key( $license_key ) {
$key_is_empty = empty( $license_key );
if ( $key_is_empty ) {
return array( 'license_is_valid' => null );
}
$license_info = $this->api_connector->check_license( $license_key );
return array( 'license_is_valid' => License_Statuses::VALID_KEY === $license_info->get_status() );
}
protected function validate() {
if ( ! parent::validate() ) {
return false;
}
if (
! isset( $_REQUEST[ self::PARAM_SETTINGS ] ) &&
( ! isset( $_REQUEST[ self::PARAM_SETTING_KEY ] ) || ! isset( $_REQUEST[ self::PARAM_SETTING_VALUE ] ) )
) {
return false;
}
return true;
}
}
@@ -0,0 +1,258 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Endpoints;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Factory;
use Gravity_Forms\Gravity_SMTP\Data_Store\Plugin_Opts_Data_Store;
use Gravity_Forms\Gravity_SMTP\Logging\Debug\Debug_Logger;
use Gravity_Forms\Gravity_SMTP\Models\Event_Model;
use Gravity_Forms\Gravity_SMTP\Models\Log_Details_Model;
use Gravity_Forms\Gravity_SMTP\Users\Roles;
use Gravity_Forms\Gravity_Tools\Endpoints\Endpoint;
class Send_Test_Endpoint extends Endpoint {
const PARAM_EMAIL = 'email';
const PARAM_CONNECTOR_TYPE = 'connector_type';
const PARAM_AS_HTML = 'as_html';
const PARAM_FROM_EMAIL = 'from_email';
const ACTION_NAME = 'send_test';
protected $minimum_cap = Roles::VIEW_TOOLS_SENDATEST;
public $last_email_id = 0;
/**
* @var Connector_Factory $connector_factory
*/
protected $connector_factory;
/**
* @var Plugin_Opts_Data_Store
*/
protected $plugin_data;
/**
* @var Event_Model
*/
protected $emails;
/**
* @var Log_Details_Model
*/
protected $logs;
/**
* @var Get_Single_Email_Data_Endpoint
*/
protected $email_endpoint;
protected $required_params = array(
self::PARAM_EMAIL,
self::PARAM_CONNECTOR_TYPE,
self::PARAM_AS_HTML,
self::PARAM_FROM_EMAIL,
);
public function __construct( $connector_factory, $plugin_data_store, $emails_model, $log_model, $email_endpoint ) {
$this->connector_factory = $connector_factory;
$this->plugin_data = $plugin_data_store;
$this->emails = $emails_model;
$this->logs = $log_model;
$this->email_endpoint = $email_endpoint;
}
protected function get_nonce_name() {
return self::ACTION_NAME;
}
protected function get_test_email_markup( $as_html ) {
if ( empty( $as_html ) ) {
return esc_html__( 'Test Successful', 'gravitysmtp' ) . "\r\n\r\n" .
esc_html__( 'Congratulations! Gravity SMTP is sending emails correctly!', 'gravitysmtp' ) . "\r\n" .
esc_html__( 'Gravity SMTP is taking care of sending your emails, so now you can focus on the content of your emails and leave the technical details to us.', 'gravitysmtp' );
}
$image_base_url = \Gravity_Forms\Gravity_SMTP\Gravity_SMTP::get_base_url() . '/assets/images/email-templates/';
return '<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Email Template</title>
<style>
body {
margin: 0;
padding: 0;
background: #fff;
font-family: inter, -apple-system, blinkmacsystemfont, \'Segoe UI\', roboto, oxygen-sans, ubuntu, cantarell, \'Helvetica Neue\', sans-serif;
}
img {
border: 0 none;
height: auto;
line-height: 100%;
outline: none;
text-decoration: none;
}
a img {
border: 0 none;
}
table, td {
border-collapse: collapse;
}
#bodyTable {
height: 100% !important;
margin: 0;
padding: 0;
width: 100% !important;
}
.wrapper {
max-width: 680px;
margin: 0 auto;
}
.content {
padding: 20px 20px 200px;
}
@media only screen and (max-width: 480px) {
.content {
padding: 20px 20px 120px;
}
}
</style>
</head>
<body>
<table id="bodyTable" role="presentation" width="100%" align="center"
style="background: url(\'' . $image_base_url . 'gravitysmtp-arrow-bg.png\') no-repeat top right / 514px 647px #fff; margin: 0;">
<tr>
<td>
<table class="wrapper" role="presentation">
<!-- Header with Logo -->
<tr>
<td style="padding: 70px 20px 32px; text-align: center;">
<img src="' . $image_base_url . 'gravitysmtp-email-logo.png" alt="' . esc_html__( 'Logo', 'gravitysmtp' ) . '"
style="display: block; margin: 0 auto; max-width: 200px">
</td>
</tr>
<!-- Content Area -->
<tr>
<td class="content">
<img src="' . $image_base_url . 'send-test/gravitysmtp-success.png" alt="' . esc_html__( 'Mail Icon', 'gravitysmtp' ) . '"
style="display: block; margin: 0 auto; max-width: 308px">
<h1 style="color: #242748; text-align: center; font-family: inter, -apple-system, blinkmacsystemfont, \'Segoe UI\', roboto, oxygen-sans, ubuntu, cantarell, \'Helvetica Neue\', sans-serif; font-size: 30px; font-style: normal; font-weight: 600; line-height: 30px; padding: 20px 0 32px; margin: 0;">' . esc_html__( 'Test Successful', 'gravitysmtp' ) . '</h1>
<div
style="border-radius: 3px; border: 1px solid #d5d7e9; box-shadow: 0px 2px 2px 0px rgba(58, 58, 87, 0.06);">
<p style="margin: 0; padding: 12px 24px; background: #f6f9fc; font-family: inter, -apple-system, blinkmacsystemfont, \'Segoe UI\', roboto, oxygen-sans, ubuntu, cantarell, \'Helvetica Neue\', sans-serif; border-bottom: 1px solid #d5d7e9; color: #242748; font-size: 14px; font-style: normal; font-weight: 500; line-height: 18px;">' . esc_html__( 'Congratulations! Gravity SMTP is sending emails correctly!', 'gravitysmtp' ) . '</p>
<p style="color: #5b5e80; background: #fff; margin: 0; padding: 16px 24px; font-family: inter, -apple-system, blinkmacsystemfont, \'Segoe UI\', roboto, oxygen-sans, ubuntu, cantarell, \'Helvetica Neue\', sans-serif; font-size: 14px; font-style: normal; font-weight: 400; line-height: 20px">' . esc_html__( 'Gravity SMTP is taking care of sending your emails, so now you can focus on the content of your emails and leave the technical details to us.', 'gravitysmtp' ) . '</p>
</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>';
}
public function handle() {
if ( ! $this->validate() ) {
wp_send_json_error( __( 'Missing required parameters.', 'gravitysmtp' ), 400 );
}
$this->override_error_handling();
$self = $this;
add_action( 'gravitysmtp_after_mail_created', function( $created_id ) use ( $self ) {
$self->last_email_id = $created_id;
}, 10, 1 );
$email = filter_input( INPUT_POST, self::PARAM_EMAIL, FILTER_SANITIZE_EMAIL );
$connector = filter_input( INPUT_POST, self::PARAM_CONNECTOR_TYPE );
$as_html = filter_input( INPUT_POST, self::PARAM_AS_HTML );
$from_email = filter_input( INPUT_POST, self::PARAM_FROM_EMAIL, FILTER_SANITIZE_EMAIL );
$connector = htmlspecialchars( $connector );
$as_html = htmlspecialchars( $as_html ) !== 'false';
$from_email = $from_email ? $from_email : get_option( 'admin_email' );
$content_type = $as_html ? 'text/html' : 'text/plain';
$headers = array(
'content-type' => 'Content-type: ' . $content_type,
'from' => 'From: ' . $from_email,
);
add_filter( 'gravitysmtp_connector_for_sending', function( $current_connector, $email_args ) use ( $connector ) {
return array( 'force' => true, 'connector' => $connector );
}, 8, 2 );
$success = wp_mail( array( 'email' => $email ), __( 'Test Email from Gravity SMTP', 'gravitysmtp' ), $this->get_test_email_markup( $as_html ), $headers, array() );
if ( $success === true ) {
wp_send_json_success( array( 'email' => $email ) );
}
$full_log = $this->get_full_log_data( $this->last_email_id );
$issues = array();
$log_copy = '';
if ( isset( $full_log['technical_information'] ) && is_array( $full_log['technical_information']['log'] ) ) {
array_push( $issues, end( $full_log['technical_information']['log'] ) );
$log_copy = implode( "\r\n", $full_log['technical_information']['log'] );
}
$reasons = array();
$steps = array();
if ( empty( $issues ) ) {
$reasons = array(
__( 'Incorrect plugin settings, such as invalid SMTP credentials or expired API key.', 'gravitysmtp' ),
__( 'The SMTP server blocking the incoming connection.', 'gravitysmtp' ),
__( 'Your web host rejecting the connection.', 'gravitysmtp' ),
);
$steps = array(
__( 'Triple check the plugin settings and ensure they are accurate, especially if you copy-pasted the values.', 'gravitysmtp' ),
__( 'Contact your web hosting provider to verify if your server allows outside connections and if any firewall or security policies are in place that could interfere.', 'gravitysmtp' ),
__( 'Consider using one of the other available integration types.', 'gravitysmtp' ),
);
}
$error_data = array(
'error_message' => __( 'There was a problem sending the test email.', 'gravitysmtp' ),
'issues' => $issues,
'full_log' => $full_log,
'log_copy' => $log_copy,
'possible_reasons' => $reasons,
'recommended_steps' => $steps,
);
Debug_Logger::log_message(
sprintf(
__( 'Send a test error: %1$s', 'gravitysmtp' ),
json_encode( $error_data )
),
'error'
);
wp_send_json_error( $error_data, 500 );
}
private function override_error_handling() {
ini_set( 'display_errors', 0 );
unset( $GLOBALS['wp_locale'] );
}
private function get_full_log_data( $email_id ) {
return $this->email_endpoint->get_log_details( $email_id );
}
}
@@ -0,0 +1,209 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Oauth;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_Google;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_Microsoft;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Save_Plugin_Settings_Endpoint;
use Gravity_Forms\Gravity_Tools\API\Oauth_Handler as Oauth_Handler_Base;
use Gravity_Forms\Gravity_Tools\Utils\Utils_Service_Provider;
class Google_Oauth_Handler extends Oauth_Handler_Base {
protected $supports_refresh_token = true;
protected $response_payload_name = 'code';
protected $namespace = 'google';
public function handle_response() {
if ( ! $this->is_response() ) {
return;
}
$url = 'https://oauth2.googleapis.com/token';
// Require code and state, and valid mode; otherwise redirect back.
if ( ! isset( $_GET['code'] ) ) { //phpcs:ignore
return;
}
$code = FILTER_INPUT( INPUT_GET, 'code', FILTER_DEFAULT );
$body = array(
'client_id' => $this->data->get( Connector_Google::SETTING_CLIENT_ID, $this->namespace ),
'client_secret' => $this->data->get( Connector_Google::SETTING_CLIENT_SECRET, $this->namespace ),
'grant_type' => 'authorization_code',
'code' => $code,
'redirect_uri' => urldecode( $this->get_return_url( 'settings', false ) ),
);
$request = wp_remote_post( $url, array( 'body' => $body ) );
if ( (int) wp_remote_retrieve_response_code( $request ) !== 200 ) { //phpcs:ignore
return;
}
$response = wp_remote_retrieve_body( $request );
$response = json_decode( $response, true );
if ( isset( $response[ $this->payload_access_token_name ] ) ) {
$this->store_access_token( $response[ $this->payload_access_token_name ] );
}
if ( isset( $response[ $this->payload_refresh_token_name ] ) ) {
$this->store_refresh_token( $response[ $this->payload_refresh_token_name ] );
}
}
protected function refresh_expired_token() {
$refresh_token = $this->get_refresh_token();
if ( empty( $refresh_token ) ) {
return new \WP_Error( __( 'Token is invalid or expired.', 'gravitysmtp' ) );
}
$refresh_url = $this->get_refresh_url();
$body = array(
'refresh_token' => $refresh_token,
'client_id' => $this->data->get( Connector_Google::SETTING_CLIENT_ID, $this->namespace ),
'client_secret' => $this->data->get( Connector_Google::SETTING_CLIENT_SECRET, $this->namespace ),
'grant_type' => 'refresh_token',
);
$response = wp_remote_post( $refresh_url, array( 'body' => $body ) );
$code = wp_remote_retrieve_response_code( $response );
if ( (int) $code !== 200 ) {
return new \WP_Error( __( 'Token is invalid or expired.', 'gravitysmtp' ) );
}
$response_body = json_decode( wp_remote_retrieve_body( $response ), true );
if ( empty( $response_body['access_token'] ) ) {
return new \WP_Error( __( 'Token is invalid or expired.', 'gravitysmtp' ) );
}
$new_token = $response_body['access_token'];
$this->store_access_token( $new_token );
return $new_token;
}
protected function is_response() {
$page = filter_input( INPUT_GET, 'page' );
$tab = filter_input( INPUT_GET, 'tab' );
$integration = filter_input( INPUT_GET, 'integration' );
$wizard_screen = filter_input( INPUT_GET, 'setup-wizard-page', FILTER_SANITIZE_NUMBER_INT );
$payload = filter_input( INPUT_GET, $this->response_payload_name );
// Valid screens are a specific integration tab, or the setup wizard page.
$is_valid_screen = $page === 'gravitysmtp-settings' &&
(
( $tab === 'integrations' && $integration === $this->namespace ) ||
( ! empty( $wizard_screen ) )
);
return ! empty( $payload ) && $is_valid_screen;
}
public function get_return_url( $context = 'settings' ) {
$base = admin_url( 'admin.php' );
$args = array(
'page' => 'gravitysmtp-settings',
);
if ( $context === 'settings' ) {
$args['integration'] = $this->namespace;
$args['tab'] = 'integrations';
}
if ( $context === 'wizard' ) {
$args['tab'] = 'integrations';
$args['setup-wizard-page'] = 4;
}
return urlencode( add_query_arg( $args, $base ) );
}
public function get_refresh_url() {
return esc_url('https://oauth2.googleapis.com/token' );
}
public function get_oauth_url( $context = 'settings' ) {
$state = array(
'url' => admin_url( 'admin.php' ),
'page' => 'gravitysmtp-settings',
'nonce' => wp_create_nonce( 'gravitysmtp' ),
);
if ( $context === 'settings' ) {
$state['tab'] = 'integrations';
$state['integration'] = $this->namespace;
}
$auth_url = add_query_arg(
array(
'redirect_to' => $this->get_return_url( $context ),
'state' => base64_encode(
json_encode(
$state
)
),
'license' => $this->data->get( Save_Plugin_Settings_Endpoint::PARAM_LICENSE_KEY ),
),
trailingslashit( GRAVITY_API_URL ) . 'auth/gmail'
);
return esc_url( $auth_url );
}
protected function is_valid_token( $token ) {
static $is_valid;
if ( ! is_null( $is_valid ) ) {
return $is_valid;
}
if ( empty( $token ) ) {
return false;
}
$check_url = 'https://gmail.googleapis.com/gmail/v1/users/me/profile';
$headers = array(
'Authorization' => 'Bearer ' . $token,
);
$response = wp_remote_get( $check_url, array( 'headers' => $headers ) );
$code = wp_remote_retrieve_response_code( $response );
$is_valid = (int) $code === 200;
return $is_valid;
}
public function get_connection_details() {
$token = $this->data->get( 'access_token', $this->namespace );
$check_url = 'https://gmail.googleapis.com/gmail/v1/users/me/profile';
$headers = array(
'Authorization' => 'Bearer ' . $token,
);
$response = wp_remote_get( $check_url, array( 'headers' => $headers ) );
$code = wp_remote_retrieve_response_code( $response );
if ( (int) $code !== 200 ) {
return array(
'email' => __( 'Unable to retrieve associated email.', 'gravitysmtp' ),
);
}
$body = json_decode( wp_remote_retrieve_body( $response ), true );
return array(
'email' => $body['emailAddress'],
);
}
}
@@ -0,0 +1,235 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Oauth;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_Google;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_Microsoft;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Save_Plugin_Settings_Endpoint;
use Gravity_Forms\Gravity_Tools\API\Oauth_Handler as Oauth_Handler_Base;
use Gravity_Forms\Gravity_Tools\Utils\Utils_Service_Provider;
class Microsoft_Oauth_Handler extends Oauth_Handler_Base {
protected $supports_refresh_token = true;
protected $namespace = 'microsoft';
protected $response_payload_name = 'code';
public function handle_response() {
if ( ! $this->is_response() ) {
return;
}
$url = 'https://login.microsoftonline.com/common/oauth2/v2.0/token';
$state = $this->get_state();
// Require code and state, and valid mode; otherwise redirect back.
if ( ! isset( $_GET['code'] ) || empty( $state ) ) { //phpcs:ignore
return;
}
$code = FILTER_INPUT( INPUT_GET, 'code', FILTER_DEFAULT );
$body = array(
'client_id' => $this->data->get( Connector_Microsoft::SETTING_CLIENT_ID, $this->namespace ),
'grant_type' => 'authorization_code',
'scope' => $this->get_scope(),
'code' => $code,
'redirect_uri' => $this->get_return_url( 'settings', false ),
'client_secret' => $this->data->get( Connector_Microsoft::SETTING_CLIENT_SECRET, $this->namespace )
);
$request = wp_remote_post( $url, array( 'body' => $body ) );
if ( (int) wp_remote_retrieve_response_code( $request ) !== 200 ) { //phpcs:ignore
return;
}
$response = wp_remote_retrieve_body( $request );
$response = json_decode( $response, true );
if ( isset( $response[ $this->payload_access_token_name ] ) ) {
$this->store_access_token( $response[ $this->payload_access_token_name ] );
}
if ( isset( $response[ $this->payload_refresh_token_name ] ) ) {
$this->store_refresh_token( $response[ $this->payload_refresh_token_name ] );
}
}
public function get_scope() {
return 'email Mail.Send User.Read profile openid offline_access';
}
protected function refresh_expired_token() {
$refresh_token = $this->get_refresh_token();
if ( empty( $refresh_token ) ) {
return new \WP_Error( __( 'Token is invalid or expired.', 'gravitysmtp' ) );
}
$refresh_url = $this->get_refresh_url();
$body = array(
'refresh_token' => $refresh_token,
'client_id' => $this->data->get( Connector_Microsoft::SETTING_CLIENT_ID, $this->namespace ),
'client_secret' => $this->data->get( Connector_Microsoft::SETTING_CLIENT_SECRET, $this->namespace ),
'grant_type' => 'refresh_token',
'scope' => $this->get_scope(),
);
$response = wp_remote_post( $refresh_url, array( 'body' => $body ) );
$code = wp_remote_retrieve_response_code( $response );
if ( (int) $code !== 200 ) {
return new \WP_Error( __( 'Token is invalid or expired.', 'gravitysmtp' ) );
}
$response_body = json_decode( wp_remote_retrieve_body( $response ), true );
if ( empty( $response_body['access_token'] ) ) {
return new \WP_Error( __( 'Token is invalid or expired.', 'gravitysmtp' ) );
}
$new_token = $response_body['access_token'];
$refresh_token = $response_body['refresh_token'];
$this->store_access_token( $new_token );
$this->store_refresh_token( $refresh_token );
return $new_token;
}
protected function is_response() {
$page = filter_input( INPUT_GET, 'page' );
$tab = filter_input( INPUT_GET, 'tab' );
$integration = filter_input( INPUT_GET, 'integration' );
$wizard_screen = filter_input( INPUT_GET, 'setup-wizard-page', FILTER_SANITIZE_NUMBER_INT );
$payload = filter_input( INPUT_GET, $this->response_payload_name );
// Valid screens are a specific integration tab, or the setup wizard page.
$is_valid_screen = $page === 'gravitysmtp-settings' &&
(
( $tab === 'integrations' && $integration === $this->namespace ) ||
( ! empty( $wizard_screen ) )
);
return ! empty( $payload ) && $is_valid_screen;
}
public function get_return_url( $context = 'settings', $encode = true ) {
$base = admin_url( 'admin.php' );
if ( $context === 'copy' ) {
return $base;
}
$args = array(
'page' => 'gravitysmtp-settings',
);
if ( $context === 'settings' ) {
$args['integration'] = $this->namespace;
$args['tab'] = 'integrations';
}
if ( $context === 'wizard' ) {
$args['tab'] = 'integrations';
$args['setup-wizard-page'] = 4;
}
$value = add_query_arg( $args, $base );
if ( ! $encode ) {
return $value;
}
return urlencode( $value );
}
public function get_refresh_url() {
return esc_url( 'https://login.microsoftonline.com/common/oauth2/v2.0/token' );
}
private function get_state( $context = 'settings' ) {
$state = array(
'url' => admin_url( 'admin.php' ),
'page' => 'gravitysmtp-settings',
'nonce' => wp_create_nonce( 'gravitysmtp' ),
);
if ( $context === 'settings' ) {
$state['tab'] = 'integrations';
$state['integration'] = $this->namespace;
}
return $state;
}
public function get_oauth_url( $context = 'settings' ) {
$state = $this->get_state( $context );
$auth_url = add_query_arg(
array(
'redirect_to' => $this->get_return_url( $context ),
'state' => base64_encode(
json_encode(
$state
)
),
'license' => $this->data->get( Save_Plugin_Settings_Endpoint::PARAM_LICENSE_KEY ),
),
trailingslashit( GRAVITY_API_URL ) . 'auth/microsoft'
);
return esc_url( $auth_url );
}
protected function is_valid_token( $token ) {
static $is_valid;
if ( ! is_null( $is_valid ) ) {
return $is_valid;
}
if ( empty( $token ) ) {
return false;
}
$check_url = 'https://graph.microsoft.com/v1.0/me';
$headers = array(
'Authorization' => 'Bearer ' . $token,
);
$response = wp_remote_get( $check_url, array( 'headers' => $headers ) );
$code = wp_remote_retrieve_response_code( $response );
$is_valid = (int) $code === 200;
return $is_valid;
}
public function get_connection_details() {
$token = $this->data->get( 'access_token', $this->namespace );
$check_url = 'https://graph.microsoft.com/v1.0/me';
$headers = array(
'Authorization' => 'Bearer ' . $token,
);
$response = wp_remote_get( $check_url, array( 'headers' => $headers ) );
$code = wp_remote_retrieve_response_code( $response );
if ( (int) $code !== 200 ) {
return array(
'email' => __( 'Unable to retrieve associated email.', 'gravitysmtp' ),
);
}
$body = json_decode( wp_remote_retrieve_body( $response ), true );
return array(
'email' => $body['mail'],
);
}
}
@@ -0,0 +1,237 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Oauth;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_Google;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Save_Plugin_Settings_Endpoint;
use Gravity_Forms\Gravity_SMTP\Connectors\Types\Connector_Zoho;
use Gravity_Forms\Gravity_SMTP\Enums\Zoho_Datacenters_Enum;
use Gravity_Forms\Gravity_Tools\API\Oauth_Handler as Oauth_Handler_Base;
use Gravity_Forms\Gravity_Tools\Utils\Utils_Service_Provider;
class Zoho_Oauth_Handler extends Oauth_Handler_Base {
protected $supports_refresh_token = true;
protected $namespace = 'zoho';
protected $response_payload_name = 'code';
public function get_connection_details() {
return array(
'account_id' => $this->data->get( Connector_Zoho::SETTING_ACCOUNT_ID, $this->namespace )
);
}
public function handle_response() {
if ( ! $this->is_response() ) {
return;
}
$url = 'https://accounts.zoho.com/oauth/v2/token';
$state = $this->get_state();
// Require code and state, and valid mode; otherwise redirect back.
if ( ! isset( $_GET['code'] ) || empty( $state ) ) { //phpcs:ignore
return;
}
$code = FILTER_INPUT( INPUT_GET, 'code', FILTER_DEFAULT );
$args = array(
'grant_type' => 'authorization_code',
'redirect_uri' => $this->get_return_url( 'settings', true ),
);
$body = array(
'client_id' => $this->data->get( Connector_Zoho::SETTING_CLIENT_ID, $this->namespace ),
'client_secret' => $this->data->get( Connector_Zoho::SETTING_CLIENT_SECRET, $this->namespace ),
'code' => $code,
);
$url = add_query_arg( $args, $url );
$request = wp_remote_post( $url, array( 'body' => $body ) );
if ( (int) wp_remote_retrieve_response_code( $request ) !== 200 ) { //phpcs:ignore
return;
}
$response = wp_remote_retrieve_body( $request );
$response = json_decode( $response, true );
if ( isset( $response[ $this->payload_access_token_name ] ) ) {
$this->store_access_token( $response[ $this->payload_access_token_name ] );
}
if ( isset( $response[ $this->payload_refresh_token_name ] ) ) {
$this->store_refresh_token( $response[ $this->payload_refresh_token_name ] );
}
// Add Account ID
$accounts_url = $this->get_api_url( 'api/accounts' );
$headers = array(
'Authorization' => 'Zoho-oauthtoken ' . $response[ $this->payload_access_token_name ],
);
$request = wp_remote_get( $accounts_url, array( 'headers' => $headers ) );
$response = wp_remote_retrieve_body( $request );
$data = json_decode( $response, true );
if ( ! isset( $data['data'][0]['accountId'] ) ) {
return;
}
$this->data->save( Connector_Zoho::SETTING_ACCOUNT_ID, $data['data'][0]['accountId'], $this->namespace );
}
public function get_scope() {
return 'ZohoMail.messages.CREATE,ZohoMail.accounts.READ';
}
protected function refresh_expired_token() {
$refresh_token = $this->get_refresh_token();
if ( empty( $refresh_token ) ) {
return new \WP_Error( __( 'Token is invalid or expired.', 'gravitysmtp' ) );
}
$refresh_url = $this->get_refresh_url();
$args = array(
'refresh_token' => $refresh_token,
'client_id' => $this->data->get( Connector_Zoho::SETTING_CLIENT_ID, $this->namespace ),
'client_secret' => $this->data->get( Connector_Zoho::SETTING_CLIENT_SECRET, $this->namespace ),
'grant_type' => 'refresh_token',
'redirect_uri' => $this->get_return_url( 'settings', true ),
);
$url = add_query_arg( $args, $refresh_url );
$request = wp_remote_post( $url, array( 'body' => array() ) );
$code = wp_remote_retrieve_response_code( $request );
if ( (int) $code !== 200 ) {
return new \WP_Error( __( 'Token is invalid or expired.', 'gravitysmtp' ) );
}
$response_body = json_decode( wp_remote_retrieve_body( $request ), true );
if ( empty( $response_body['access_token'] ) ) {
return new \WP_Error( __( 'Token is invalid or expired.', 'gravitysmtp' ) );
}
$new_token = $response_body['access_token'];
$this->store_access_token( $new_token );
return $new_token;
}
protected function is_response() {
$page = filter_input( INPUT_GET, 'page' );
$tab = filter_input( INPUT_GET, 'tab' );
$integration = filter_input( INPUT_GET, 'integration' );
$wizard_screen = filter_input( INPUT_GET, 'setup-wizard-page', FILTER_SANITIZE_NUMBER_INT );
$payload = filter_input( INPUT_GET, $this->response_payload_name );
// Valid screens are a specific integration tab, or the setup wizard page.
$is_valid_screen = $page === 'gravitysmtp-settings' &&
(
( $tab === 'integrations' && $integration === $this->namespace ) ||
( ! empty( $wizard_screen ) )
);
return ! empty( $payload ) && $is_valid_screen;
}
public function get_return_url( $context = 'settings', $encode = true ) {
$base = admin_url( 'admin.php' );
if ( $context === 'copy' ) {
return $base;
}
$args = array(
'page' => 'gravitysmtp-settings',
);
if ( $context === 'settings' ) {
$args['integration'] = $this->namespace;
$args['tab'] = 'integrations';
}
if ( $context === 'wizard' ) {
$args['tab'] = 'integrations';
$args['setup-wizard-page'] = 4;
}
$value = add_query_arg( $args, $base );
if ( ! $encode ) {
return $value;
}
return urlencode( $value );
}
public function get_refresh_url() {
return esc_url( 'https://accounts.zoho.com/oauth/v2/token' );
}
private function get_state( $context = 'settings' ) {
$state = array(
'url' => admin_url( 'admin.php' ),
'page' => 'gravitysmtp-settings',
'nonce' => wp_create_nonce( 'gravitysmtp' ),
);
if ( $context === 'settings' ) {
$state['tab'] = 'integrations';
$state['integration'] = $this->namespace;
}
return $state;
}
public function get_oauth_url( $context = 'settings' ) {
return '';
}
protected function is_valid_token( $token ) {
static $is_valid;
if ( ! is_null( $is_valid ) ) {
return $is_valid;
}
if ( empty( $token ) ) {
return false;
}
$check_url = $this->get_api_url( 'api/accounts' );
$headers = array(
'Authorization' => 'Zoho-oauthtoken ' . $token,
'Content-type' => 'application/json',
'Accept' => 'application/json',
);
$response = wp_remote_get( $check_url, array( 'headers' => $headers ) );
$code = wp_remote_retrieve_response_code( $response );
$is_valid = (int) $code === 200;
return $is_valid;
}
private function get_api_url( $endpoint ) {
$data_center_location = $this->data->get( Connector_Zoho::SETTING_DATA_CENTER_REGION, $this->namespace );
if ( empty( $data_center_location ) ) {
$data_center_location = 'us';
}
$base = Zoho_Datacenters_Enum::url_for_datacenter( $data_center_location );
return trailingslashit( $base ) . $endpoint;
}
}
@@ -0,0 +1,432 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Types;
use Exception;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Base;
use Gravity_Forms\Gravity_SMTP\Feature_Flags\Feature_Flag_Manager;
use Gravity_Forms\Gravity_SMTP\Gravity_SMTP;
use Gravity_Forms\Gravity_SMTP\Utils\AWS_Signature_Handler;
use Gravity_Forms\Gravity_Tools\Utils\Utils_Service_Provider;
/**
* Connector for Amazon SES
*
* @since 1.0
*/
class Connector_Amazon extends Connector_Base {
const SETTING_CLIENT_ID = 'access_key_id';
const SETTING_CLIENT_SECRET = 'secret_access_key';
const SETTING_REGION = 'region';
const REGION_US_EAST_N_VIRGINIA = 'us-east-1';
const REGION_US_EAST_OHIO = 'us-east-2';
const REGION_US_WEST_N_CALIFORNIA = 'us-west-1';
const REGION_US_WEST_OREGON = 'us-west-2';
const REGION_AFRICA_CAPE_TOWN = 'af-south-1';
const REGION_ASIA_PACIFIC_HONG_KONG = 'ap-east-1';
const REGION_ASIA_PACIFIC_JAKARTA = 'ap-southeast-3';
const REGION_ASIA_PACIFIC_MUMBAI = 'ap-south-1';
const REGION_ASIA_PACIFIC_OSAKA = 'ap-northeast-3';
const REGION_ASIA_PACIFIC_SEOUL = 'ap-northeast-2';
const REGION_ASIA_PACIFIC_SINGAPORE = 'ap-southeast-1';
const REGION_ASIA_PACIFIC_SYDNEY = 'ap-southeast-2';
const REGION_ASIA_PACIFIC_TOKYO = 'ap-northeast-1';
const REGION_CANADA_CENTRAL = 'ca-central-1';
const REGION_EUROPE_FRANKFURT = 'eu-central-1';
const REGION_EUROPE_IRELAND = 'eu-west-1';
const REGION_EUROPE_LONDON = 'eu-west-2';
const REGION_EUROPE_MILAN = 'eu-south-1';
const REGION_EUROPE_PARIS = 'eu-west-3';
const REGION_EUROPE_STOCKHOLM = 'eu-north-1';
const REGION_MIDDLE_EAST_BAHRAIN = 'me-south-1';
const REGION_SOUTH_AMERICA_SAO_PAULO = 'sa-east-1';
const API_ENDPOINT = '/v2/email/outbound-emails';
const ISO8601_BASIC = 'Ymd\THis\Z';
protected $name = 'amazon';
protected $title = 'Amazon SES';
protected $disabled = false;
protected $logo = 'AmazonAWS';
protected $full_logo = 'AmazonAWSFull';
public function get_description() {
return __( 'Amazon SES offers a reliable and cost-effective service for sending and receiving emails using your own domain. It leverages Amazons robust infrastructure, making it a powerful option for managing your email communication.', 'gravitysmtp' );
}
protected $sensitive_fields = array(
self::SETTING_CLIENT_ID,
self::SETTING_CLIENT_SECRET,
);
/**
* Sending logic.
*
* @since 1.0
*
* @return bool
*/
public function send() {
$to = $this->get_att( 'to', '' );
$subject = $this->get_att( 'subject', '' );
$message = $this->get_att( 'message', '' );
$headers = $this->get_parsed_headers( $this->get_att( 'headers', array() ) );
$attachments = $this->get_att( 'attachments', array() );
$from = $this->get_from( true );
$reply_to = $this->get_reply_to( true );
$source = $this->get_att( 'source' );
$params = $this->get_request_params();
$email = $this->email;
$this->reset_phpmailer();
if ( ! empty( $headers['content-type'] ) ) {
$headers['content-type'] = $this->get_att( 'content_type', $headers['content-type'] );
}
$this->set_email_log_data( $subject, $message, $to, empty( $from['name'] ) ? $from['email'] : sprintf( '%s <%s>', $from['name'], $from['email'] ), $headers, $attachments, $source, $params );
$this->logger->log( $email, 'started', __( 'Starting email send for Amazon SES connector.', 'gravitysmtp' ) );
$this->php_mailer->CharSet = 'UTF-8';
$this->php_mailer->setFrom( $from['email'], empty( $from['name'] ) ? '' : $from['name'] );
foreach ( $to->recipients() as $recipient ) {
if ( ! empty( $recipient->name() ) ) {
$this->php_mailer->addAddress( $recipient->email(), $recipient->name() );
} else {
$this->php_mailer->addAddress( $recipient->email() );
}
}
$this->php_mailer->Subject = $subject;
$this->php_mailer->Body = $message;
if ( ! empty( $headers['cc'] ) ) {
foreach ( $headers['cc']->recipients() as $recipient ) {
if ( ! empty( $recipient->name() ) ) {
$this->php_mailer->addCC( $recipient->email(), $recipient->name() );
} else {
$this->php_mailer->addCC( $recipient->email() );
}
}
}
if ( ! empty( $headers['bcc'] ) ) {
foreach ( $headers['bcc']->recipients() as $recipient ) {
if ( ! empty( $recipient->name() ) ) {
$this->php_mailer->addBCC( $recipient->email(), $recipient->name() );
} else {
$this->php_mailer->addBCC( $recipient->email() );
}
}
}
if ( ! empty( $attachments ) ) {
foreach ( $attachments as $attachment ) {
$this->php_mailer->addAttachment( $attachment );
}
}
if ( ! empty( $reply_to ) ) {
foreach ( $reply_to as $address ) {
if ( isset( $address['name'] ) ) {
$this->php_mailer->addReplyTo( $address['email'], $address['name'] );
} else {
$this->php_mailer->addReplyTo( $address['email'] );
}
}
}
if ( ! empty( $headers['content-type'] ) && strpos( $headers['content-type'], 'text/html' ) !== false ) {
$this->php_mailer->isHTML( true );
} else {
$this->php_mailer->isHTML( false );
$this->php_mailer->ContentType = 'text/plain';
}
$additional_headers = $this->get_filtered_message_headers();
if ( ! empty( $additional_headers ) ) {
foreach ( $additional_headers as $key => $value ) {
$value = str_replace( sprintf( '%s:', $key ), '', $value );
$this->php_mailer->addCustomHeader( $key, trim( $value ) );
}
}
if ( $this->is_test_mode() ) {
$this->events->update( array( 'status' => 'sandboxed' ), $email );
$this->logger->log( $email, 'sandboxed', __( 'Email sandboxed.', 'gravitysmtp' ) );
return true;
}
try {
$debug_atts = compact( 'to', 'from', 'subject', 'headers', 'source', 'attachments', 'reply_to' );
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Attempting send with the following attributes: ' . json_encode( $debug_atts ) ) );
$raw = $this->get_raw_message();
/**
* @var AWS_Signature_Handler $signature_handler
*/
$signature_handler = Gravity_SMTP::$container->get( Utils_Service_Provider::AWS_SIGNATURE_HANDLER );
$body = array(
'Action' => 'SendRawEmail',
'Version' => '2010-12-01',
'RawMessage' => array(
'Data' => $raw,
),
);
$request_data = $signature_handler->get_request_data( $body, $this->get_setting( self::SETTING_CLIENT_ID, '' ), $this->get_setting( self::SETTING_CLIENT_SECRET, '' ), $this->get_setting( self::SETTING_REGION, self::REGION_US_EAST_N_VIRGINIA ) );
$response = wp_remote_post( $request_data['url'], array( 'headers' => $request_data['headers'], 'body' => $request_data['body'] ) );
$code = wp_remote_retrieve_response_code( $response );
$is_success = (int) $code === 200;
if ( ! $is_success ) {
$this->log_failure( $email, wp_remote_retrieve_body( $response ) );
return $email;
}
$this->events->update( array( 'status' => 'sent' ), $email );
$this->logger->log( $email, 'sent', __( 'Email successfully sent.', 'gravitysmtp' ) );
return true;
} catch ( Exception $e ) {
$this->log_failure( $email, $e->getMessage() );
$this->debug_logger->log_fatal( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Failed to send: ' . $e->getMessage() ) );
return $email;
}
}
/**
* Logs an email send failure.
*
* @since 1.4.0
*
* @param string $email the email that failed
* @param string $error_message the error message
*/
private function log_failure( $email, $error_message ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $error_message );
}
private function get_raw_message() {
$this->php_mailer->preSend();
$raw = $this->php_mailer->getSentMIMEMessage();
return base64_encode( $raw );
}
/**
* Reset the PHPMailer instance to prevent carryover from previous send.
*
* @since 1.0
*
* @return void
*/
private function reset_phpmailer() {
$this->php_mailer->clearCustomHeaders();
$this->php_mailer->clearAddresses();
$this->php_mailer->clearBCCs();
$this->php_mailer->clearCCs();
$this->php_mailer->clearAllRecipients();
$this->php_mailer->clearReplyTos();
$this->php_mailer->clearAttachments();
}
/**
* Connector data.
*
* @since 1.0
*
* @return array
*/
public function connector_data() {
return array(
self::SETTING_CLIENT_ID => $this->get_setting( self::SETTING_CLIENT_ID, '' ),
self::SETTING_CLIENT_SECRET => $this->get_setting( self::SETTING_CLIENT_SECRET, '' ),
self::SETTING_REGION => $this->get_setting( self::SETTING_REGION, self::REGION_US_EAST_N_VIRGINIA ),
self::SETTING_FROM_EMAIL => $this->get_setting( self::SETTING_FROM_EMAIL, '' ),
self::SETTING_FORCE_FROM_EMAIL => $this->get_setting( self::SETTING_FORCE_FROM_EMAIL, false ),
self::SETTING_FROM_NAME => $this->get_setting( self::SETTING_FROM_NAME, '' ),
self::SETTING_FORCE_FROM_NAME => $this->get_setting( self::SETTING_FORCE_FROM_NAME, false ),
self::SETTING_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_REPLY_TO_EMAIL, '' ),
self::SETTING_FORCE_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_FORCE_REPLY_TO_EMAIL, false ),
);
}
/**
* Settings fields.
*
* @since 1.0
*
* @return array
*/
public function settings_fields() {
return array(
'title' => esc_html__( 'Amazon SES Settings', 'gravitysmtp' ),
'description' => '',
'fields' => array_merge(
array(
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Configuration', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => array( 4, 0, 4, 0 ),
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
array(
'component' => 'LinkedHelpTextInput',
'external' => true,
'handle_change' => true,
'links' => array(
array(
'key' => 'link',
'props' => array(
'href' => 'https://aws.amazon.com/console/',
'size' => 'text-xs',
'target' => '_blank',
),
),
),
'props' => array(
'helpTextAttributes' => array(
'content' => esc_html__( 'Log in to your {{link}}AWS Console{{link}}, go to the IAM dashboard, and create a new access key for an IAM user with ses:SendEmail and ses:SendRawEmail permissions.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'labelAttributes' => array(
'label' => esc_html__( 'Access Key ID', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'name' => self::SETTING_CLIENT_ID,
'spacing' => 4,
'size' => 'size-l',
'value' => $this->get_setting( self::SETTING_CLIENT_ID, '' ),
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'Secret Access Key', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'name' => self::SETTING_CLIENT_SECRET,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_CLIENT_SECRET, '' ),
),
),
array(
'component' => 'Select',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'Region', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'name' => self::SETTING_REGION,
'size' => 'size-l',
'spacing' => 6,
'initialValue' => $this->get_setting( self::SETTING_REGION, self::REGION_US_EAST_N_VIRGINIA ),
'options' => $this->get_region_setting_options(),
),
),
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'General Settings', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => 4,
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
),
$this->get_from_settings_fields(),
$this->get_reply_to_settings_fields(),
),
);
}
protected function get_region_setting_options() {
$region_options = array(
__( 'US East (N. Virginia)', 'gravitysmtp' ) => self::REGION_US_EAST_N_VIRGINIA,
__( 'US East (Ohio)', 'gravitysmtp' ) => self::REGION_US_EAST_OHIO,
__( 'US West (N. California)', 'gravitysmtp' ) => self::REGION_US_WEST_N_CALIFORNIA,
__( 'US West (Oregon)', 'gravitysmtp' ) => self::REGION_US_WEST_OREGON,
__( 'Africa (Cape Town)', 'gravitysmtp' ) => self::REGION_AFRICA_CAPE_TOWN,
__( 'Asia Pacific (Hong Kong)', 'gravitysmtp' ) => self::REGION_ASIA_PACIFIC_HONG_KONG,
__( 'Asia Pacific (Jakarta)', 'gravitysmtp' ) => self::REGION_ASIA_PACIFIC_JAKARTA,
__( 'Asia Pacific (Mumbai)', 'gravitysmtp' ) => self::REGION_ASIA_PACIFIC_MUMBAI,
__( 'Asia Pacific (Osaka)', 'gravitysmtp' ) => self::REGION_ASIA_PACIFIC_OSAKA,
__( 'Asia Pacific (Seoul)', 'gravitysmtp' ) => self::REGION_ASIA_PACIFIC_SEOUL,
__( 'Asia Pacific (Singapore)', 'gravitysmtp' ) => self::REGION_ASIA_PACIFIC_SINGAPORE,
__( 'Asia Pacific (Sydney)', 'gravitysmtp' ) => self::REGION_ASIA_PACIFIC_SYDNEY,
__( 'Asia Pacific (Tokyo)', 'gravitysmtp' ) => self::REGION_ASIA_PACIFIC_TOKYO,
__( 'Canada (Central)', 'gravitysmtp' ) => self::REGION_CANADA_CENTRAL,
__( 'Europe (Frankfurt)', 'gravitysmtp' ) => self::REGION_EUROPE_FRANKFURT,
__( 'Europe (Ireland)', 'gravitysmtp' ) => self::REGION_EUROPE_IRELAND,
__( 'Europe (London)', 'gravitysmtp' ) => self::REGION_EUROPE_LONDON,
__( 'Europe (Milan)', 'gravitysmtp' ) => self::REGION_EUROPE_MILAN,
__( 'Europe (Paris)', 'gravitysmtp' ) => self::REGION_EUROPE_PARIS,
__( 'Europe (Stockholm)', 'gravitysmtp' ) => self::REGION_EUROPE_STOCKHOLM,
__( 'Middle East (Bahrain)', 'gravitysmtp' ) => self::REGION_MIDDLE_EAST_BAHRAIN,
__( 'South America (São Paulo)', 'gravitysmtp' ) => self::REGION_SOUTH_AMERICA_SAO_PAULO,
);
$settings = array();
foreach ( $region_options as $name => $slug ) {
$settings[] = array(
'label' => $name,
'value' => $slug,
);
}
return $settings;
}
/**
* Get the unique data for this connector, merged with the default/common data for all
* connectors in the system.
*
* @since 1.0
*
* @return array
*/
protected function get_merged_data() {
$data = parent::get_merged_data();
$data['disabled'] = ! Feature_Flag_Manager::is_enabled( 'amazon_ses_integration' );
return $data;
}
public function is_configured() {
if ( ! $this->get_setting( self::SETTING_CLIENT_ID, '' ) || ! $this->get_setting( self::SETTING_CLIENT_SECRET, '' ) ) {
return false;
}
return true;
}
}
@@ -0,0 +1,363 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Types;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Base;
/**
* Connector for Brevo
*
* @since 1.0
*/
class Connector_Brevo extends Connector_Base {
const SETTING_API_KEY = 'api_key';
protected $name = 'brevo';
protected $title = 'Brevo';
protected $description = '';
protected $logo = 'Brevo';
protected $full_logo = 'BrevoFull';
protected $url = 'https://api.brevo.com/v3/smtp/email';
protected $sensitive_fields = array(
self::SETTING_API_KEY,
);
public function get_description() {
return esc_html__( 'Confidently send transactional emails with Brevo, formerly Sendinblue. With an impressive free plan, Brevo allows you to send up to 300 transactional emails a day! And for those who need to send more, simply pay for what you send. For more information on how to get started with Brevo, read our documentation.', 'gravitysmtp' );
}
/**
* Sends email via Brevo.
*
* @since 1.0
*
* @return int Returns the email ID.
*/
public function send() {
try {
$atts = $this->get_send_atts();
$source = $this->get_att( 'source' );
$params = $this->get_request_params();
$email = $this->email;
$this->set_email_log_data( $atts['subject'], $atts['message'], $atts['to'], $atts['from']['from'], $atts['headers'], $atts['attachments'], $source, $params );
$this->logger->log( $email, 'started', __( 'Starting email send for Brevo connector.', 'gravitysmtp' ) );
if ( $this->is_test_mode() ) {
$this->events->update( array( 'status' => 'sandboxed' ), $email );
$this->logger->log( $email, 'sandboxed', __( 'Email sandboxed.', 'gravitysmtp' ) );
return true;
}
$response = wp_safe_remote_post( $this->url, $params );
$is_success = in_array( (int) wp_remote_retrieve_response_code( $response ), array( 201, 202 ) );
if ( ! $is_success ) {
$this->log_failure( $email, wp_remote_retrieve_body( $response ) );
return $email;
}
$this->events->update( array( 'status' => 'sent' ), $email );
$this->logger->log( $email, 'sent', __( 'Email successfully sent.', 'gravitysmtp' ) );
return true;
} catch ( \Exception $e ) {
$this->log_failure( $email, $e->getMessage() );
return $email;
}
}
/**
* Get the request parameters for sending email through connector.
*
* @since 1.0
*
* @return array
*/
public function get_request_params() {
$atts = $this->get_send_atts();
$api_key = $this->get_setting( self::SETTING_API_KEY );
$body = array(
'sender' => array(
'name' => isset( $atts['from']['name'] ) ? $atts['from']['name'] : '',
'email' => $atts['from']['email'],
),
'to' => $atts['to']->as_array(),
'subject' => $atts['subject'],
);
$body['sender'] = array_filter( $body['sender'] );
// Setting content
$is_html = ! empty( $atts['headers']['content-type'] ) && strpos( $atts['headers']['content-type'], 'text/html' ) !== false;
if ( $is_html ) {
$body['htmlContent'] = $atts['message'];
} else {
$body['textContent'] = $atts['message'];
}
// Setting cc
if ( ! empty( $atts['headers']['cc'] ) ) {
$body['cc'] = $atts['headers']['cc']->as_array();
}
// Setting bcc
if ( ! empty( $atts['headers']['bcc'] ) ) {
$body['bcc'] = $atts['headers']['bcc']->as_array();
}
// Setting reply to
if ( ! empty( $atts['reply_to'] ) ) {
if ( isset( $atts['reply_to']['email'] ) ) {
$reply_to = $atts['reply_to'];
} else {
$reply_to = $atts['reply_to'][0];
}
$body['replyTo'] = array_filter( array(
'name' => isset( $reply_to['name'] ) ? $reply_to['name'] : '',
'email' => $reply_to['email'],
) );
}
// Setting attachments
if ( ! empty( $atts['attachments'] ) ) {
$body['attachment'] = $this->get_attachments( $atts['attachments'] );
}
$additional_headers = $this->get_filtered_message_headers();
if ( ! empty( $additional_headers ) ) {
$body['headers'] = $additional_headers;
}
return array(
'body' => json_encode( $body ),
'headers' => $this->get_request_headers( $api_key ),
);
}
/**
* Get the attributes for sending email.
*
* @since 1.0
*
* @return array
*/
protected function get_send_atts() {
$headers = $this->get_parsed_headers( $this->get_att( 'headers', array() ) );
if ( ! empty( $headers['content-type'] ) ) {
$headers['content-type'] = $this->get_att( 'content_type', $headers['content-type'] );
}
return array(
'to' => $this->get_att( 'to', '' ),
'subject' => $this->get_att( 'subject', '' ),
'message' => $this->get_att( 'message', '' ),
'headers' => $headers,
'attachments' => $this->get_att( 'attachments', array() ),
'from' => $this->get_from( true ),
'reply_to' => $this->get_reply_to( true ),
);
}
/**
* Gets a list of attachments, and returns them in a format that can be used by the API.
*
* @param array $attachments The list of attachments.
*
* @since 1.0
*
* @return array Returns an array of attachments. Each item with a 'content' and 'name' property.
*/
protected function get_attachments( $attachments ) {
$data = array();
foreach ( $attachments as $custom_name => $attachment ) {
try {
if ( is_file( $attachment ) && is_readable( $attachment ) ) {
$fileName = is_numeric( $custom_name ) ? basename( $attachment ) : $custom_name;
$content = base64_encode( file_get_contents( $attachment ) );
$data[] = array(
'name' => $fileName,
'content' => $content,
);
}
} catch ( \Exception $e ) {
continue;
}
}
return $data;
}
/**
* Gets the headers to be used in the API request.
*
* @since 1.0
*
* @return array Returns the header array to be passed to Brevo's API.
*/
protected function get_request_headers( $api_key ) {
return array(
'content-type' => 'application/json',
'accept' => 'application/json',
'api-key' => $api_key,
);
}
/**
* Logs an email send failure.
*
* @since 1.0
*
* @param string $email The email that failed.
* @param string $error_message The error message.
*/
private function log_failure( $email, $error_message ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $error_message );
}
/**
* Connector data.
*
* @since 1.0
*
* @return array
*/
public function connector_data() {
return array(
self::SETTING_API_KEY => $this->get_setting( self::SETTING_API_KEY, '' ),
self::SETTING_FROM_EMAIL => $this->get_setting( self::SETTING_FROM_EMAIL, '' ),
self::SETTING_FORCE_FROM_EMAIL => $this->get_setting( self::SETTING_FORCE_FROM_EMAIL, false ),
self::SETTING_FROM_NAME => $this->get_setting( self::SETTING_FROM_NAME, '' ),
self::SETTING_FORCE_FROM_NAME => $this->get_setting( self::SETTING_FORCE_FROM_NAME, false ),
self::SETTING_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_REPLY_TO_EMAIL, '' ),
self::SETTING_FORCE_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_FORCE_REPLY_TO_EMAIL, false ),
);
}
/**
* Settings fields.
*
* @since 1.0
*
* @return array
*/
public function settings_fields() {
return array(
'title' => esc_html__( 'Brevo Settings', 'gravitysmtp' ),
'description' => '',
'fields' => array_merge(
array(
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Configuration', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => array( 4, 0, 4, 0 ),
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'API Key', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'helpTextAttributes' => array(
'asHtml' => true,
/* translators: 1: opening anchor tag, 2: closing anchor tag */
'content' => sprintf( __( 'To generate an API key from Brevo, log in to your Brevo dashboard and navigate to the API section. %1$sCreate a new API key%2$s and ensure your %3$sAuthorized IPs settings%2$s are configured correctly.', 'gravitysmtp' ), '<a class="gform-link gform-typography--size-text-xs" href="https://app.brevo.com/settings/keys/api" target="_blank" rel="noopener noreferrer">', '</a>', '<a class="gform-link gform-typography--size-text-xs" href="https://help.brevo.com/hc/en-us/articles/5740111683858-Authorize-IP-addresses-for-API-calls-to-improve-security" target="_blank" rel="noopener noreferrer">' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'name' => self::SETTING_API_KEY,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_API_KEY, '' ),
),
),
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'General Settings', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => 4,
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
),
$this->get_from_settings_fields(),
$this->get_reply_to_settings_fields(),
),
);
}
/**
* Determine if the API credentials are configured correctly.
*
* @since 1.0
*
* @return bool|\WP_Error Returns true if configured, or a WP_Error object if not.
*/
public function is_configured() {
$valid_api = $this->verify_api_key();
if ( is_wp_error( $valid_api ) ) {
self::$configured = $valid_api;
return $valid_api;
}
self::$configured = true;
return true;
}
/**
* Verify the API key with the API.
*
* @since 1.0
*
* @return true|\WP_Error
*/
private function verify_api_key() {
$api_key = $this->get_setting( self::SETTING_API_KEY );
$url = 'https://api.brevo.com/v3/smtp/templates?limit=1';
if ( empty( $api_key ) ) {
return new \WP_Error( 'missing_api_key', __( 'No API Key provided.', 'gravitysmtp' ) );
}
$response = wp_remote_get(
$url,
array(
'headers' => $this->get_request_headers( $api_key ),
)
);
if ( wp_remote_retrieve_response_code( $response ) != '200' ) {
return new \WP_Error( 'invalid_api_key', __( 'Invalid API Key provided.', 'gravitysmtp' ) );
}
return true;
}
}
@@ -0,0 +1,863 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Types;
use Exception;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Base;
use Gravity_Forms\Gravity_SMTP\Feature_Flags\Feature_Flag_Manager;
use Gravity_Forms\Gravity_SMTP\Models\Event_Model;
use WP_Error;
/**
* Connector for Cloudflare Email Service.
*
* @since 2.2.0
*/
class Connector_Cloudflare extends Connector_Base {
const SETTING_ACCOUNT_ID = 'account_id';
const SETTING_API_TOKEN = 'api_token';
protected $name = 'cloudflare';
protected $title = 'Cloudflare';
protected $description = '';
protected $logo = 'Cloudflare';
protected $full_logo = 'CloudflareFull';
protected $url = 'https://api.cloudflare.com/client/v4/accounts/%s/email/sending/send';
protected $sensitive_fields = array(
self::SETTING_API_TOKEN,
);
/**
* Get the connector description.
*
* @since 2.2.0
*
* @return string
*/
public function get_description() {
return esc_html__( 'Send transactional email through Cloudflare Email Service using a domain managed on Cloudflare DNS. Requires a paid Cloudflare plan.', 'gravitysmtp' );
}
/**
* Send the email through Cloudflare.
*
* @since 2.2.0
*
* @return bool|int
*/
public function send() {
$email = $this->email;
$atts = $this->get_send_atts();
$source = $this->get_att( 'source' );
/** @var Event_Model $events */
$events = $this->events;
try {
$request_body = $this->get_request_body( $atts );
if ( is_wp_error( $request_body ) ) {
return $this->log_failure( $email, $request_body->get_error_message() );
}
$params = $this->get_request_params_for_body( $request_body );
$this->set_email_log_data( $atts['subject'], $atts['message'], $atts['to'], $atts['from']['from'], $atts['headers'], $atts['attachments'], $source, $params );
$this->logger->log( $email, 'started', __( 'Starting email send for Cloudflare connector.', 'gravitysmtp' ) );
$this->debug_logger->log_debug(
$this->wrap_debug_with_details(
__FUNCTION__,
$email,
sprintf(
'Starting Cloudflare send with %1$d recipient(s) and payload size %2$d bytes.',
$this->get_recipient_count( $atts ),
strlen( $params['body'] )
)
)
);
if ( $this->is_test_mode() ) {
$events->update( array( 'status' => 'sandboxed' ), $email );
$this->logger->log( $email, 'sandboxed', __( 'Email sandboxed.', 'gravitysmtp' ) );
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Test mode is enabled, sandboxing email.' ) );
return true;
}
$response = wp_safe_remote_post( $this->get_send_url(), $params );
if ( is_wp_error( $response ) ) {
return $this->log_failure( $email, $response->get_error_message() );
}
$response_code = (int) wp_remote_retrieve_response_code( $response );
$response_body = wp_remote_retrieve_body( $response );
$decoded_body = json_decode( $response_body, true );
$this->debug_logger->log_debug(
$this->wrap_debug_with_details(
__FUNCTION__,
$email,
sprintf( 'Cloudflare response (%1$d): %2$s', $response_code, $response_body )
)
);
if ( ! $this->is_successful_response( $response_code, $decoded_body ) ) {
return $this->log_failure( $email, $this->get_api_error_message( $response_code, $decoded_body, $response_body ) );
}
$events->update( array( 'status' => 'sent' ), $email );
$this->logger->log( $email, 'sent', __( 'Email successfully sent.', 'gravitysmtp' ) );
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Email successfully sent.' ) );
return true;
} catch ( Exception $e ) {
return $this->log_failure( $email, $e->getMessage() );
}
}
/**
* Get the request parameters for sending email through Cloudflare.
*
* @since 2.2.0
*
* @return array
*/
public function get_request_params() {
$request_body = $this->get_request_body( $this->get_send_atts() );
if ( is_wp_error( $request_body ) ) {
return array();
}
return $this->get_request_params_for_body( $request_body );
}
/**
* Get the request parameters for a prepared Cloudflare body.
*
* @since 2.2.0
*
* @param array $request_body The request body.
*
* @return array
*/
protected function get_request_params_for_body( $request_body ) {
return array(
'body' => wp_json_encode( $request_body ),
'headers' => $this->get_request_headers( trim( (string) $this->get_setting( self::SETTING_API_TOKEN, '' ) ) ),
);
}
/**
* Get the attributes for sending email.
*
* @since 2.2.0
*
* @return array
*/
protected function get_send_atts() {
$headers = $this->get_parsed_headers( $this->get_att( 'headers', array() ) );
if ( ! empty( $headers['content-type'] ) ) {
$headers['content-type'] = $this->get_att( 'content_type', $headers['content-type'] );
}
return array(
'to' => $this->get_att( 'to', '' ),
'subject' => $this->get_att( 'subject', '' ),
'message' => $this->get_att( 'message', '' ),
'headers' => $headers,
'attachments' => $this->get_att( 'attachments', array() ),
'from' => $this->get_from( true ),
'reply_to' => $this->get_reply_to( true ),
);
}
/**
* Build the Cloudflare request body.
*
* @since 2.2.0
*
* @param array $atts The send attributes.
*
* @return array|WP_Error
*/
protected function get_request_body( $atts ) {
$account_id = trim( (string) $this->get_setting( self::SETTING_ACCOUNT_ID, '' ) );
$api_token = trim( (string) $this->get_setting( self::SETTING_API_TOKEN, '' ) );
if ( empty( $account_id ) ) {
return new WP_Error( 'missing_account_id', __( 'No Account ID provided.', 'gravitysmtp' ) );
}
if ( empty( $api_token ) ) {
return new WP_Error( 'missing_api_token', __( 'No API Token provided.', 'gravitysmtp' ) );
}
$request_body = array(
'from' => $this->format_address( $atts['from'] ),
'to' => $this->format_recipients( $atts['to'] ),
'subject' => $atts['subject'],
);
$is_html = ! empty( $atts['headers']['content-type'] ) && strpos( $atts['headers']['content-type'], 'text/html' ) !== false;
if ( $is_html ) {
$request_body['html'] = $atts['message'];
$request_body['text'] = $this->get_text_body( $atts['message'] );
} else {
$request_body['text'] = $atts['message'];
}
if ( empty( $request_body['html'] ) && empty( $request_body['text'] ) ) {
return new WP_Error( 'missing_email_body', __( 'Cloudflare requires either an HTML or plain text email body.', 'gravitysmtp' ) );
}
if ( ! empty( $atts['headers']['cc'] ) ) {
$request_body['cc'] = $this->format_recipients( $atts['headers']['cc'] );
}
if ( ! empty( $atts['headers']['bcc'] ) ) {
$request_body['bcc'] = $this->format_recipients( $atts['headers']['bcc'] );
}
if ( ! empty( $atts['reply_to'] ) ) {
$reply_to = isset( $atts['reply_to'][0] ) ? $atts['reply_to'][0] : $atts['reply_to'];
if ( ! empty( $reply_to['email'] ) ) {
$request_body['reply_to'] = $this->format_address( $reply_to );
}
}
$additional_headers = $this->get_filtered_message_headers();
if ( ! empty( $additional_headers ) ) {
$request_body['headers'] = array_map( 'strval', $additional_headers );
}
if ( ! empty( $atts['attachments'] ) ) {
$attachments = $this->get_attachments( $atts['attachments'] );
if ( ! empty( $attachments ) ) {
$request_body['attachments'] = $attachments;
}
}
return $request_body;
}
/**
* Format a recipient collection for Cloudflare.
*
* @since 2.2.0
*
* @param object $recipients The parsed recipient collection.
*
* @return array
*/
protected function format_recipients( $recipients ) {
$formatted = array();
foreach ( $recipients->as_array() as $recipient ) {
$formatted[] = $this->format_address( $recipient );
}
return $formatted;
}
/**
* Format an address array for Cloudflare.
*
* @since 2.2.0
*
* @param array $address The address data.
*
* @return array|string
*/
protected function format_address( $address ) {
if ( ! empty( $address['name'] ) ) {
$name = $address['name'];
// RFC 5322: quote display names containing specials so they aren't
// mis-parsed (e.g. parentheses treated as comments by Cloudflare).
if ( preg_match( '/[()<>\[\]:;@\\\\",.]/', $name ) ) {
$name = '"' . str_replace( array( '\\', '"' ), array( '\\\\', '\\"' ), $name ) . '"';
}
return sprintf( '%s <%s>', $name, $address['email'] );
}
return $address['email'];
}
/**
* Convert HTML content into a text fallback.
*
* @since 2.2.0
*
* @param string $message The message body.
*
* @return string
*/
protected function get_text_body( $message ) {
$text_body = wp_strip_all_tags( $message );
return preg_replace( "/([\r\n]{2,}|[\n]{2,}|[\r]{2,}|[\r\t]{2,}|[\n\t]{2,})/", "\n", $text_body );
}
/**
* Get attachments formatted for Cloudflare.
*
* @since 2.2.0
*
* @param array $attachments The attachments array.
*
* @return array
*/
protected function get_attachments( $attachments ) {
$data = array();
foreach ( $attachments as $custom_name => $attachment ) {
$file = false;
try {
if ( is_file( $attachment ) && is_readable( $attachment ) ) {
$file_name = is_numeric( $custom_name ) ? basename( $attachment ) : $custom_name;
$content_id = wp_hash( $attachment );
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Local attachments must be base64 encoded for API connectors.
$file = file_get_contents( $attachment );
$mime_type = mime_content_type( $attachment );
$file_type = str_replace( ';', '', trim( $mime_type ) );
}
} catch ( Exception $e ) {
$file = false;
}
if ( $file === false ) {
continue;
}
$data[] = array(
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- Local attachments must be base64 encoded for Cloudflare's API.
'content' => base64_encode( $file ),
'disposition' => 'attachment',
'filename' => $file_name,
'type' => $file_type,
'content_id' => $content_id,
);
}
return $data;
}
/**
* Determine if the Cloudflare response is successful.
*
* @since 2.2.0
*
* @param int $response_code The HTTP response code.
* @param array|null $decoded_body The decoded response body.
*
* @return bool
*/
protected function is_successful_response( $response_code, $decoded_body ) {
if ( $response_code >= 300 ) {
return false;
}
if ( ! is_array( $decoded_body ) ) {
return false;
}
return ! empty( $decoded_body['success'] );
}
/**
* Build an actionable API error message.
*
* @since 2.2.0
*
* @param int $response_code The HTTP response code.
* @param array|null $decoded_body The decoded response body.
* @param string $response_body The raw response body.
*
* @return string
*/
protected function get_api_error_message( $response_code, $decoded_body, $response_body ) {
$parts = array();
if ( 429 === $response_code ) {
$parts[] = __( 'Cloudflare rate limit exceeded.', 'gravitysmtp' );
} elseif ( $response_code >= 300 ) {
$parts[] = sprintf(
/* translators: %d: HTTP response code. */
__( 'Cloudflare API request failed with status code %d.', 'gravitysmtp' ),
$response_code
);
} else {
$parts[] = __( 'Cloudflare API reported an unsuccessful response.', 'gravitysmtp' );
}
if ( is_array( $decoded_body ) ) {
$error_parts = array();
if ( ! empty( $decoded_body['errors'] ) && is_array( $decoded_body['errors'] ) ) {
foreach ( $decoded_body['errors'] as $error ) {
$code = isset( $error['code'] ) ? $error['code'] : '';
$message = isset( $error['message'] ) ? $error['message'] : '';
if ( empty( $message ) ) {
continue;
}
$error_parts[] = empty( $code ) ? $message : sprintf( '[%1$s] %2$s', $code, $message );
}
}
if ( ! empty( $decoded_body['messages'] ) && is_array( $decoded_body['messages'] ) ) {
foreach ( $decoded_body['messages'] as $message ) {
$message_text = isset( $message['message'] ) ? $message['message'] : '';
if ( empty( $message_text ) ) {
continue;
}
$error_parts[] = $message_text;
}
}
if ( ! empty( $error_parts ) ) {
$parts[] = implode( ' ', $error_parts );
}
}
if ( empty( $decoded_body ) && ! empty( $response_body ) ) {
$parts[] = $response_body;
}
return implode( ' ', array_filter( $parts ) );
}
/**
* Get the send URL.
*
* @since 2.2.0
*
* @return string
*/
protected function get_send_url() {
return sprintf( $this->url, trim( (string) $this->get_setting( self::SETTING_ACCOUNT_ID, '' ) ) );
}
/**
* Get the recipient count for the message.
*
* @since 2.2.0
*
* @param array $atts The send attributes.
*
* @return int
*/
protected function get_recipient_count( $atts ) {
$count = count( $atts['to']->as_array() );
if ( ! empty( $atts['headers']['cc'] ) ) {
$count += count( $atts['headers']['cc']->as_array() );
}
if ( ! empty( $atts['headers']['bcc'] ) ) {
$count += count( $atts['headers']['bcc']->as_array() );
}
return $count;
}
/**
* Get the headers to be used in the API request.
*
* @since 2.2.0
*
* @param string $api_token The Cloudflare API token.
*
* @return array
*/
protected function get_request_headers( $api_token ) {
return array(
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $api_token,
);
}
/**
* Log an email send failure.
*
* @since 2.2.0
*
* @param int $email The failed email event ID.
* @param string $error_message The error message.
*
* @return int
*/
protected function log_failure( $email, $error_message ) {
/** @var Event_Model $events */
$events = $this->events;
$events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $error_message );
$this->debug_logger->log_error( $this->wrap_debug_with_details( __FUNCTION__, $email, $error_message ) );
return $email;
}
/**
* Connector data.
*
* @since 2.2.0
*
* @return array
*/
public function connector_data() {
return array(
self::SETTING_ACCOUNT_ID => $this->get_setting( self::SETTING_ACCOUNT_ID, '' ),
self::SETTING_API_TOKEN => $this->get_setting( self::SETTING_API_TOKEN, '' ),
self::SETTING_FROM_EMAIL => $this->get_setting( self::SETTING_FROM_EMAIL, '' ),
self::SETTING_FORCE_FROM_EMAIL => $this->get_setting( self::SETTING_FORCE_FROM_EMAIL, false ),
self::SETTING_FROM_NAME => $this->get_setting( self::SETTING_FROM_NAME, '' ),
self::SETTING_FORCE_FROM_NAME => $this->get_setting( self::SETTING_FORCE_FROM_NAME, false ),
self::SETTING_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_REPLY_TO_EMAIL, '' ),
self::SETTING_FORCE_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_FORCE_REPLY_TO_EMAIL, false ),
);
}
/**
* Get the unique data for this connector, merged with the default/common data for all
* connectors in the system.
*
* @since 2.2.0
*
* @return array
*/
protected function get_merged_data() {
$data = parent::get_merged_data();
$data['disabled'] = ! Feature_Flag_Manager::is_enabled( 'cloudflare_integration' );
return $data;
}
/**
* Settings fields.
*
* @since 2.2.0
*
* @return array
*/
public function settings_fields() {
return array(
'title' => esc_html__( 'Cloudflare Settings', 'gravitysmtp' ),
'description' => '',
'fields' => array_merge(
array(
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Configuration', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => array( 4, 0, 4, 0 ),
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'Account ID', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'helpTextAttributes' => array(
'asHtml' => true,
/* translators: 1: opening anchor tag, 2: closing anchor tag */
'content' => sprintf( __( 'Copy the Account ID from your Cloudflare dashboard. Your Default From Email must use a domain managed on Cloudflare DNS and onboarded in Cloudflare Email Service for Email Sending. Cloudflare adds the required sending records on the cf-bounce subdomain plus your domain DMARC record. See Cloudflare\'s %1$sdomain configuration docs%2$s for setup details.', 'gravitysmtp' ), '<a class="gform-link gform-typography--size-text-xs" href="https://developers.cloudflare.com/email-service/configuration/domains/" target="_blank" rel="noopener noreferrer">', '</a>' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'name' => self::SETTING_ACCOUNT_ID,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_ACCOUNT_ID, '' ),
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'API Token', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'helpTextAttributes' => array(
'asHtml' => true,
/* translators: 1: opening anchor tag, 2: closing anchor tag */
'content' => sprintf( __( 'Create a Cloudflare API token with access to Cloudflare Email Service for the target account. For full setup verification, also grant Zone Read and Email Sending Read permissions. Cloudflare Email Service currently requires a paid Cloudflare plan. See Cloudflare\'s %1$semail sending docs%2$s for setup guidance.', 'gravitysmtp' ), '<a class="gform-link gform-typography--size-text-xs" href="https://developers.cloudflare.com/email-service/api/send-emails/rest-api/" target="_blank" rel="noopener noreferrer">', '</a>' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'name' => self::SETTING_API_TOKEN,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_API_TOKEN, '' ),
),
),
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'General Settings', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => 4,
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
array(
'component' => 'Text',
'props' => array(
'content' => esc_html__( 'Set your Default From Email to a mailbox on a domain managed on Cloudflare DNS and onboarded in Cloudflare Email Service for Email Sending.', 'gravitysmtp' ),
'size' => 'text-xs',
'spacing' => 6,
'weight' => 'regular',
),
),
),
$this->get_from_settings_fields(),
$this->get_reply_to_settings_fields(),
),
);
}
/**
* Determine if the Cloudflare connector is configured.
*
* Validates credentials are present, then checks the Cloudflare API to
* confirm the From Email domain is an active zone on this account with
* Email Sending enabled.
*
* @since 2.2.0
*
* @return bool|WP_Error
*/
public function is_configured() {
$account_id = trim( (string) $this->get_setting( self::SETTING_ACCOUNT_ID, '' ) );
$api_token = trim( (string) $this->get_setting( self::SETTING_API_TOKEN, '' ) );
$from_email = trim( (string) $this->get_setting( self::SETTING_FROM_EMAIL, '' ) );
if ( empty( $account_id ) ) {
return new WP_Error( 'missing_account_id', __( 'No Account ID provided.', 'gravitysmtp' ) );
}
if ( empty( $api_token ) ) {
return new WP_Error( 'missing_api_token', __( 'No API Token provided.', 'gravitysmtp' ) );
}
if ( empty( $from_email ) ) {
return new WP_Error( 'missing_from_email', __( 'No Default From Email provided. Cloudflare requires a From Email on a domain managed in your Cloudflare account.', 'gravitysmtp' ) );
}
if ( ! is_email( $from_email ) ) {
return new WP_Error( 'invalid_from_email', __( 'The Default From Email is not a valid email address.', 'gravitysmtp' ) );
}
$from_domain = $this->get_email_domain( $from_email );
if ( empty( $from_domain ) ) {
return new WP_Error( 'invalid_from_domain', __( 'Could not determine a domain from the Default From Email.', 'gravitysmtp' ) );
}
$zone_id = $this->get_zone_id_for_domain( $from_domain, $account_id, $api_token );
if ( is_wp_error( $zone_id ) ) {
return $zone_id;
}
$subdomains = $this->get_sending_subdomains( $zone_id, $api_token );
if ( is_wp_error( $subdomains ) ) {
return new WP_Error(
'sending_status_check_failed',
sprintf(
/* translators: %s: sending domain. */
__( 'Could not verify Email Sending status for %s. Make sure your API token has Email Sending read permissions.', 'gravitysmtp' ),
$from_domain
)
);
}
if ( empty( $subdomains ) ) {
return new WP_Error(
'no_sending_subdomains',
sprintf(
/* translators: %s: sending domain. */
__( 'No sending subdomains are configured for %s. Onboard your domain in Cloudflare Email Service for Email Sending.', 'gravitysmtp' ),
$from_domain
)
);
}
$has_enabled = false;
foreach ( $subdomains as $subdomain ) {
if ( ! empty( $subdomain['enabled'] ) ) {
$has_enabled = true;
break;
}
}
if ( ! $has_enabled ) {
return new WP_Error(
'sending_not_enabled',
sprintf(
/* translators: %s: sending domain. */
__( 'Email Sending is not yet enabled for %s. Complete the domain onboarding in Cloudflare Email Service so that the required DNS records are verified.', 'gravitysmtp' ),
$from_domain
)
);
}
return true;
}
/**
* Get the domain portion of an email address.
*
* @since 2.2.0
*
* @param string $email The email address.
*
* @return string
*/
protected function get_email_domain( $email ) {
$at_position = strrpos( $email, '@' );
if ( $at_position === false ) {
return '';
}
return strtolower( substr( $email, $at_position + 1 ) );
}
/**
* Resolve the Cloudflare zone ID for a domain on this account.
*
* @since 2.2.0
*
* @param string $domain The sending domain.
* @param string $account_id The Cloudflare account ID.
* @param string $api_token The Cloudflare API token.
*
* @return string|WP_Error The zone ID, or WP_Error on failure.
*/
protected function get_zone_id_for_domain( $domain, $account_id, $api_token ) {
$url = add_query_arg(
array(
'name' => $domain,
'account.id' => $account_id,
),
'https://api.cloudflare.com/client/v4/zones'
);
$response = $this->cloudflare_api_get( $url, $api_token );
if ( is_wp_error( $response ) ) {
return $response;
}
if ( empty( $response['result'] ) || ! is_array( $response['result'] ) ) {
return new WP_Error( 'zone_not_found', __( 'No matching zone found on this Cloudflare account.', 'gravitysmtp' ) );
}
$zone = $response['result'][0];
if ( empty( $zone['id'] ) ) {
return new WP_Error( 'zone_not_found', __( 'No matching zone found on this Cloudflare account.', 'gravitysmtp' ) );
}
if ( isset( $zone['status'] ) && 'active' !== $zone['status'] ) {
return new WP_Error(
'zone_not_active',
sprintf(
/* translators: %s: zone status. */
__( 'Zone exists but is not active (status: %s).', 'gravitysmtp' ),
$zone['status']
)
);
}
return $zone['id'];
}
/**
* Get the sending subdomains for a zone.
*
* @since 2.2.0
*
* @param string $zone_id The Cloudflare zone ID.
* @param string $api_token The Cloudflare API token.
*
* @return array|WP_Error The subdomains array, or WP_Error on failure.
*/
protected function get_sending_subdomains( $zone_id, $api_token ) {
$url = sprintf( 'https://api.cloudflare.com/client/v4/zones/%s/email/sending/subdomains', $zone_id );
$response = $this->cloudflare_api_get( $url, $api_token );
if ( is_wp_error( $response ) ) {
return $response;
}
if ( ! isset( $response['result'] ) || ! is_array( $response['result'] ) ) {
return array();
}
return $response['result'];
}
/**
* Make a GET request to the Cloudflare API v4.
*
* @since 2.2.0
*
* @param string $url The full API URL.
* @param string $api_token The Cloudflare API token.
*
* @return array|WP_Error The decoded response body, or WP_Error on failure.
*/
protected function cloudflare_api_get( $url, $api_token ) {
$response = wp_safe_remote_get(
$url,
array(
'headers' => $this->get_request_headers( $api_token ),
'timeout' => 15,
)
);
if ( is_wp_error( $response ) ) {
return $response;
}
$response_code = (int) wp_remote_retrieve_response_code( $response );
$decoded_body = json_decode( wp_remote_retrieve_body( $response ), true );
if ( ! $this->is_successful_response( $response_code, $decoded_body ) ) {
return new WP_Error(
'cloudflare_api_error',
$this->get_api_error_message( $response_code, $decoded_body, wp_remote_retrieve_body( $response ) )
);
}
return $decoded_body;
}
}
@@ -0,0 +1,387 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Types;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Base;
use Gravity_Forms\Gravity_SMTP\Feature_Flags\Feature_Flag_Manager;
/**
* Connector for Elastic Email
*
* @since 1.0
*/
class Connector_Elastic_Email extends Connector_Base {
const SETTING_API_KEY = 'api_key';
protected $name = 'elastic_email';
protected $title = 'Elastic Email';
protected $logo = 'ElasticEmail';
protected $full_logo = 'ElasticEmailFull';
protected $url = 'https://api.elasticemail.com/v4';
protected $sensitive_fields = array(
self::SETTING_API_KEY,
);
public function get_description() {
return esc_html__( 'Elastic Email is a high-performance email platform offering both marketing and transactional email solutions. With a free plan for up to 100 daily emails and affordable paid options, Elastic Email provides detailed analytics and automation tools.', 'gravitysmtp' );
}
/**
* Sends email via Elastic Email.
*
* @since 1.0
*
* @return int Returns the email ID.
*/
public function send() {
try {
$atts = $this->get_send_atts();
$source = $this->get_att( 'source' );
$params = $this->get_request_params();
$email = $this->email;
$this->set_email_log_data( $atts['subject'], $atts['message'], $atts['to'], $atts['from']['from'], $atts['headers'], $atts['attachments'], $source, $params );
$this->logger->log( $email, 'started', __( 'Starting email send for Elastic Email connector.', 'gravitysmtp' ) );
if ( $this->is_test_mode() ) {
$this->events->update( array( 'status' => 'sandboxed' ), $email );
$this->logger->log( $email, 'sandboxed', __( 'Email sandboxed.', 'gravitysmtp' ) );
return true;
}
$response = wp_safe_remote_post( $this->url . '/emails/transactional', $params );
$is_success = in_array( (int) wp_remote_retrieve_response_code( $response ), array( 200, 201, 202 ) );
if ( ! $is_success ) {
$this->log_failure( $email, wp_remote_retrieve_body( $response ) );
return $email;
}
$this->events->update( array( 'status' => 'sent' ), $email );
$this->logger->log( $email, 'sent', __( 'Email successfully sent.', 'gravitysmtp' ) );
return true;
} catch ( \Exception $e ) {
$this->log_failure( $email, $e->getMessage() );
return $email;
}
}
/**
* Get the request parameters for sending email through connector.
*
* @since 1.0
*
* @return array
*/
public function get_request_params() {
$atts = $this->get_send_atts();
$api_key = $this->get_setting( self::SETTING_API_KEY );
$is_html = ! empty( $atts['headers']['content-type'] ) && strpos( $atts['headers']['content-type'], 'text/html' ) !== false;
$from_email = $atts['from']['email'];
if ( ! empty( $atts['from']['name'] ) ) {
$from_email = sprintf( '%s <%s>', $atts['from']['name'], $atts['from']['email'] );
}
$body = array(
'Recipients' => array(
'To' => array(),
),
'Content' => array(
'From' => $from_email,
'Subject' => $atts['subject'],
'Body' => array(
array(
'Charset' => 'utf-8',
'Content' => $atts['message'],
'ContentType' => $is_html ? 'HTML' : 'PlainText',
),
),
),
);
foreach ( $atts['to']->as_array() as $to_value ) {
$body['Recipients']['To'][] = $to_value['email'];
}
// Setting cc
if ( ! empty( $atts['headers']['cc'] ) ) {
$body['Recipients']['CC'] = array();
foreach ( $atts['headers']['cc']->as_array() as $cc_value ) {
$body['Recipients']['CC'][] = $cc_value['email'];
}
}
// Setting bcc
if ( ! empty( $atts['headers']['bcc'] ) ) {
$body['Recipients']['BCC'] = array();
foreach ( $atts['headers']['bcc']->as_array() as $bcc_value ) {
$body['Recipients']['BCC'][] = $bcc_value['email'];
}
}
// Setting reply to
if ( ! empty( $atts['reply_to'] ) ) {
if ( isset( $atts['reply_to']['email'] ) ) {
$reply_to = $atts['reply_to'];
} else {
$reply_to = $atts['reply_to'][0];
}
$body['Content']['ReplyTo'] = $reply_to['email'];
}
// Setting attachments
if ( ! empty( $atts['attachments'] ) ) {
$body['Content']['Attachments'] = $this->get_attachments( $atts['attachments'] );
}
return array(
'body' => json_encode( $body ),
'headers' => $this->get_request_headers( $api_key ),
);
}
/**
* Get the attributes for sending email.
*
* @since 1.0
*
* @return array
*/
protected function get_send_atts() {
$headers = $this->get_parsed_headers( $this->get_att( 'headers', array() ) );
if ( ! empty( $headers['content-type'] ) ) {
$headers['content-type'] = $this->get_att( 'content_type', $headers['content-type'] );
}
return array(
'to' => $this->get_att( 'to', '' ),
'subject' => $this->get_att( 'subject', '' ),
'message' => $this->get_att( 'message', '' ),
'headers' => $headers,
'attachments' => $this->get_att( 'attachments', array() ),
'from' => $this->get_from( true ),
'reply_to' => $this->get_reply_to( true ),
);
}
/**
* Gets a list of attachments, and returns them in a format that can be used by the API.
*
* @param array $attachments The list of attachments.
*
* @since 1.0
*
* @return array Returns an array of attachments. Each item with a 'content' and 'name' property.
*/
protected function get_attachments( $attachments ) {
$data = array();
foreach ( $attachments as $custom_name => $attachment ) {
try {
if ( is_file( $attachment ) && is_readable( $attachment ) ) {
$fileName = is_numeric( $custom_name ) ? basename( $attachment ) : $custom_name;
$content = base64_encode( file_get_contents( $attachment ) );
$data[] = array(
'Name' => $fileName,
'BinaryContent' => $content,
'ContentType' => mime_content_type( $attachment ),
'Size' => filesize( $attachment ),
);
}
} catch ( \Exception $e ) {
continue;
}
}
return $data;
}
/**
* Gets the headers to be used in the API request.
*
* @since 1.0
*
* @return array Returns the header array to be passed to Elastic Email's API.
*/
protected function get_request_headers( $api_key ) {
return array(
'content-type' => 'application/json',
'accept' => 'application/json',
'X-ElasticEmail-ApiKey' => $api_key,
);
}
/**
* Logs an email send failure.
*
* @since 1.0
*
* @param string $email The email that failed.
* @param string $error_message The error message.
*/
private function log_failure( $email, $error_message ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $error_message );
}
/**
* Connector data.
*
* @since 1.0
*
* @return array
*/
public function connector_data() {
return array(
self::SETTING_API_KEY => $this->get_setting( self::SETTING_API_KEY, '' ),
self::SETTING_FROM_EMAIL => $this->get_setting( self::SETTING_FROM_EMAIL, '' ),
self::SETTING_FORCE_FROM_EMAIL => $this->get_setting( self::SETTING_FORCE_FROM_EMAIL, false ),
self::SETTING_FROM_NAME => $this->get_setting( self::SETTING_FROM_NAME, '' ),
self::SETTING_FORCE_FROM_NAME => $this->get_setting( self::SETTING_FORCE_FROM_NAME, false ),
self::SETTING_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_REPLY_TO_EMAIL, '' ),
self::SETTING_FORCE_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_FORCE_REPLY_TO_EMAIL, false ),
);
}
/**
* Settings fields.
*
* @since 1.0
*
* @return array
*/
public function settings_fields() {
return array(
'title' => esc_html__( 'Elastic Email Settings', 'gravitysmtp' ),
'description' => '',
'fields' => array_merge(
array(
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Configuration', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => array( 4, 0, 4, 0 ),
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'API Key', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'helpTextAttributes' => array(
'asHtml' => true,
/* translators: 1: opening anchor tag, 2: closing anchor tag */
'content' => sprintf( __( 'To generate an API key from Elastic Email, log in to your Elastic Email dashboard and navigate to the API section. %1$sCreate a new API key%2$s and ensure your %3$sdomain settings%2$s are configured correctly.', 'gravitysmtp' ), '<a class="gform-link gform-typography--size-text-xs" href="https://app.elasticemail.com/api/settings/create-api" target="_blank" rel="noopener noreferrer">', '</a>', '<a class="gform-link gform-typography--size-text-xs" href="https://app.elasticemail.com/api/settings/domains" target="_blank" rel="noopener noreferrer">' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'name' => self::SETTING_API_KEY,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_API_KEY, '' ),
),
),
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'General Settings', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => 4,
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
),
$this->get_from_settings_fields(),
$this->get_reply_to_settings_fields(),
),
);
}
/**
* Determine if the API credentials are configured correctly.
*
* @since 1.0
*
* @return bool|\WP_Error Returns true if configured, or a WP_Error object if not.
*/
public function is_configured() {
$valid_api = $this->verify_api_key();
if ( is_wp_error( $valid_api ) ) {
self::$configured = $valid_api;
return $valid_api;
}
self::$configured = true;
return true;
}
/**
* Verify the API key with the API.
*
* @since 1.0
*
* @return true|\WP_Error
*/
private function verify_api_key() {
$api_key = $this->get_setting( self::SETTING_API_KEY );
$url = $this->url . '/statistics?from=' . date( 'Y-m-d h:i:s', time() );
if ( empty( $api_key ) ) {
return new \WP_Error( 'missing_api_key', __( 'No API Key provided.', 'gravitysmtp' ) );
}
$headers = $this->get_request_headers( $api_key );
$response = wp_remote_get(
$url,
array(
'headers' => $headers,
)
);
if ( wp_remote_retrieve_response_code( $response ) != '200' ) {
return new \WP_Error( 'invalid_api_key', __( 'Invalid API Key provided.', 'gravitysmtp' ) );
}
return true;
}
/**
* Get the unique data for this connector, merged with the default/common data for all
* connectors in the system.
*
* @since 1.0
*
* @return array
*/
protected function get_merged_data() {
$data = parent::get_merged_data();
$data['disabled'] = ! Feature_Flag_Manager::is_enabled( 'elasticemail_integration' );
return $data;
}
}
@@ -0,0 +1,409 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Types;
use Exception;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Base;
use Gravity_Forms\Gravity_SMTP\Feature_Flags\Feature_Flag_Manager;
use WP_Error;
/**
* Connector for Emailit
*
* @since 1.0
*/
class Connector_Emailit extends Connector_Base {
const SETTING_API_KEY = 'api_key';
protected $name = 'emailit';
protected $title = 'Emailit';
protected $logo = 'Emailit';
protected $full_logo = 'EmailitFull';
protected $url = 'https://api.emailit.com/v2';
protected $sensitive_fields = array(
self::SETTING_API_KEY,
);
/**
* Get the connector description.
*
* @since 1.0
*
* @return string The connector description.
*/
public function get_description() {
return esc_html__( 'Simple and no-subscription based API for sending transactional and marketing emails.', 'gravitysmtp' );
}
/**
* Sends email via Emailit.
*
* @since 1.0
*
* @return true|int True on success, int (email ID) on failure to trigger retry.
*/
public function send() {
try {
$atts = $this->get_send_atts();
$source = $this->get_att( 'source' );
$params = $this->get_request_params();
$email = $this->email;
$this->set_email_log_data( $atts['subject'], $atts['message'], $atts['to'], $atts['from']['from'], $atts['headers'], $atts['attachments'], $source, $params );
$this->logger->log( $email, 'started', __( 'Starting email send for Emailit connector.', 'gravitysmtp' ) );
if ( $this->is_test_mode() ) {
$this->events->update( array( 'status' => 'sandboxed' ), $email );
$this->logger->log( $email, 'sandboxed', __( 'Email sandboxed.', 'gravitysmtp' ) );
return true;
}
$response = wp_safe_remote_post( $this->url . '/emails', $params );
$is_success = in_array( (int) wp_remote_retrieve_response_code( $response ), array( 200, 201, 202 ) );
if ( ! $is_success ) {
$this->log_failure( $email, wp_remote_retrieve_body( $response ) );
return $email;
}
$this->events->update( array( 'status' => 'sent' ), $email );
$this->logger->log( $email, 'sent', __( 'Email successfully sent.', 'gravitysmtp' ) );
return true;
} catch ( Exception $e ) {
$this->log_failure( $email, $e->getMessage() );
return $email;
}
}
/**
* Get the request parameters for sending email through connector.
*
* @since 1.0
*
* @return array
*/
public function get_request_params() {
$atts = $this->get_send_atts();
$api_key = $this->get_setting( self::SETTING_API_KEY );
$message = array(
'to' => array(),
'from' => ! empty( $atts['from']['name'] ) ? sprintf( '%s <%s>', $atts['from']['name'], $atts['from']['email'] ) : $atts['from']['email'],
'subject' => $atts['subject'],
);
$to_value = array();
foreach ( $atts['to']->as_array() as $recipient ) {
if ( ! empty( $recipient['name'] ) ) {
$to_value[] = sprintf( '%s <%s>', $recipient['name'], $recipient['email'] );
} else {
$to_value[] = $recipient['email'];
}
}
$message['to'] = $to_value;
// Setting content
$is_html = ! empty( $atts['headers']['content-type'] ) && strpos( $atts['headers']['content-type'], 'text/html' ) !== false;
if ( $is_html ) {
$message['html'] = $atts['message'];
// Strip tags from plaintext
$text_body = wp_strip_all_tags( $atts['message'] );
// Remove leftover double-linebreaks from plaintext.
$text_body = preg_replace( "/([\r\n]{2,}|[\n]{2,}|[\r]{2,}|[\r\t]{2,}|[\n\t]{2,})/", "\n", $text_body );
$message['text'] = $text_body;
} else {
$message['text'] = $atts['message'];
}
// Setting cc
if ( ! empty( $atts['headers']['cc'] ) ) {
$cc_headers = array();
foreach ( $atts['headers']['cc']->as_array() as $cc_value ) {
$cc_headers[] = ! empty( $cc_value['name'] ) ? sprintf( '%s <%s>', $cc_value['name'], $cc_value['email'] ) : $cc_value['email'];
}
$message['cc'] = $cc_headers;
}
// Setting Bcc
if ( ! empty( $atts['headers']['bcc'] ) ) {
$bcc_headers = array();
foreach ( $atts['headers']['bcc']->as_array() as $bcc_value ) {
$bcc_headers[] = ! empty( $bcc_value['name'] ) ? sprintf( '%s <%s>', $bcc_value['name'], $bcc_value['email'] ) : $bcc_value['email'];
}
$message['bcc'] = $bcc_headers;
}
// Setting reply to
if ( ! empty( $atts['reply_to'] ) ) {
if ( isset( $atts['reply_to']['email'] ) ) {
$reply_to = $atts['reply_to'];
} else {
$reply_to = $atts['reply_to'][0];
}
$message['reply_to'] = $reply_to['email'];
}
// Setting attachments
if ( ! empty( $atts['attachments'] ) ) {
$message['attachments'] = $this->get_attachments( $atts['attachments'] );
}
return array(
'body' => json_encode( $message ),
'headers' => $this->get_request_headers( $api_key ),
);
}
/**
* Get the attributes for sending email.
*
* @since 1.0
*
* @return array
*/
protected function get_send_atts() {
$headers = $this->get_parsed_headers( $this->get_att( 'headers', array() ) );
if ( ! empty( $headers['content-type'] ) ) {
$headers['content-type'] = $this->get_att( 'content_type', $headers['content-type'] );
}
return array(
'to' => $this->get_att( 'to', '' ),
'subject' => $this->get_att( 'subject', '' ),
'message' => $this->get_att( 'message', '' ),
'headers' => $headers,
'attachments' => $this->get_att( 'attachments', array() ),
'from' => $this->get_from( true ),
'reply_to' => $this->get_reply_to( true ),
);
}
/**
* Gets a list of attachments, and returns them in a format that can be used by the API.
*
* @param array $attachments the list of attachments
*
* @since 1.0
*
* @return array Returns an array of attachments. Each item with a 'content' and 'name' property.
*/
protected function get_attachments( $attachments ) {
$data = array();
foreach ( $attachments as $custom_name => $attachment ) {
try {
if ( is_file( $attachment ) && is_readable( $attachment ) ) {
$fileName = is_numeric( $custom_name ) ? basename( $attachment ) : $custom_name;
$content = base64_encode( file_get_contents( $attachment ) );
$data[] = array(
'filename' => $fileName,
'content' => $content,
'content_type' => mime_content_type( $attachment ),
);
}
} catch ( Exception $e ) {
continue;
}
}
return $data;
}
/**
* Gets the headers to be used in the API request.
*
* @since 1.0
*
* @param string $api_key The API key for authorization.
*
* @return array returns the header array to be passed to Emailit's API
*/
protected function get_request_headers( $api_key ) {
return array(
'content-type' => 'application/json',
'Authorization' => 'Bearer ' . $api_key,
);
}
/**
* Logs an email send failure.
*
* @since 1.0
*
* @param string $email the email that failed
* @param string $error_message the error message
*
* @return void
*/
private function log_failure( $email, $error_message ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $error_message );
}
/**
* Connector data.
*
* @since 1.0
*
* @return array
*/
public function connector_data() {
return array(
self::SETTING_API_KEY => $this->get_setting( self::SETTING_API_KEY, '' ),
self::SETTING_FROM_EMAIL => $this->get_setting( self::SETTING_FROM_EMAIL, '' ),
self::SETTING_FORCE_FROM_EMAIL => $this->get_setting( self::SETTING_FORCE_FROM_EMAIL, false ),
self::SETTING_FROM_NAME => $this->get_setting( self::SETTING_FROM_NAME, '' ),
self::SETTING_FORCE_FROM_NAME => $this->get_setting( self::SETTING_FORCE_FROM_NAME, false ),
self::SETTING_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_REPLY_TO_EMAIL, '' ),
self::SETTING_FORCE_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_FORCE_REPLY_TO_EMAIL, false ),
);
}
/**
* Settings fields.
*
* @since 1.0
*
* @return array
*/
public function settings_fields() {
return array(
'title' => esc_html__( 'Emailit Settings', 'gravitysmtp' ),
'description' => '',
'fields' => array_merge(
array(
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Configuration', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => array( 4, 0, 4, 0 ),
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'API Key', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'helpTextAttributes' => array(
'asHtml' => true,
/* translators: 1: opening anchor tag, 2: closing anchor tag */
'content' => __( 'To generate an API key from Emailit, log in to your Emailit dashboard and navigate to the Credentials section and then generate your API key.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'name' => self::SETTING_API_KEY,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_API_KEY, '' ),
),
),
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'General Settings', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => 4,
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
),
$this->get_from_settings_fields(),
$this->get_reply_to_settings_fields(),
),
);
}
/**
* Determine if the API credentials are configured correctly.
*
* @since 1.0
*
* @return bool|WP_Error returns true if configured, or a WP_Error object if not
*/
public function is_configured() {
$valid_api = $this->verify_api_key();
if ( is_wp_error( $valid_api ) ) {
self::$configured = $valid_api;
return $valid_api;
}
self::$configured = true;
return true;
}
/**
* Verify the API key with the API.
*
* @since 1.0
*
* @return true|WP_Error
*/
private function verify_api_key() {
$api_key = $this->get_setting( self::SETTING_API_KEY, '' );
$url = $this->url . '/domains';
if ( empty( $api_key ) ) {
return new WP_Error( 'missing_api_key', __( 'No API Key provided.', 'gravitysmtp' ) );
}
$response = wp_remote_get(
$url,
array(
'headers' => $this->get_request_headers( $api_key ),
)
);
if ( wp_remote_retrieve_response_code( $response ) != '200' ) {
return new WP_Error( 'invalid_api_key', __( 'Invalid API Key provided.', 'gravitysmtp' ) );
}
return true;
}
/**
* Get the unique data for this connector, merged with the default/common data for all
* connectors in the system.
*
* @since 1.0
*
* @return array
*/
protected function get_merged_data() {
$data = parent::get_merged_data();
$data['disabled'] = ! Feature_Flag_Manager::is_enabled( 'emailit_integration' );
return $data;
}
}
@@ -0,0 +1,596 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Types;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Base;
use Gravity_Forms\Gravity_SMTP\Utils\Recipient_Collection;
/**
* Connector for Generic/Custom SMTP integration.
*
* @since 1.0
*/
class Connector_Generic extends Connector_Base {
const SETTING_HOST = 'host';
const SETTING_PORT = 'port';
const SETTING_AUTH = 'auth';
const SETTING_USERNAME = 'username';
const SETTING_PASSWORD = 'password';
const SETTING_ENCRYPTION_TYPE = 'encryption_type';
const SETTING_AUTO_TLS = 'auto_tls';
const SETTING_USE_RETURN_PATH = 'use_return_path';
protected $name = 'generic';
protected $title = 'Custom SMTP';
protected $disabled = false;
protected $description = '';
protected $logo = 'CustomSMTP';
protected $full_logo = 'CustomSMTPFull';
public function get_description() {
return __( "Use our Custom SMTP feature to easily connect to any SMTP server. If you don't want to use one of Gravity SMTP's built-in integrations, with Custom SMTP you can sync with a huge array of services that can reliably send your site's emails. For more information on how to get started with Custom SMTP, read our documentation.", 'gravitysmtp' );
}
protected $sensitive_fields = array(
self::SETTING_PASSWORD,
);
/**
* Sending logic.
*
* @since 1.0
*
* @return bool
*/
public function send() {
try {
/**
* @var Recipient_Collection $to
*/
$to = $this->get_att( 'to', '' );
$subject = $this->get_att( 'subject', '' );
$message = $this->get_att( 'message', '' );
$headers = $this->get_parsed_headers( $this->get_att( 'headers', array() ) );
$attachments = $this->get_att( 'attachments', array() );
$from = $this->get_from( true );
$reply_to = $this->get_reply_to( true );
$source = $this->get_att( 'source' );
$params = array( 'body' => array( __( 'Body is not stored for Custom SMTP events.', 'gravitysmtp' ) ), 'headers' => $headers );
$email = $this->email;
if ( ! empty( $headers['content-type'] ) ) {
$headers['content-type'] = $this->get_att( 'content_type', $headers['content-type'] );
}
$this->set_email_log_data( $subject, $message, $to, empty( $from['name'] ) ? $from['email'] : sprintf( '%s <%s>', $from['name'], $from['email'] ), $headers, $attachments, $source, $params );
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Starting email send with Custom SMTP connector.' ) );
$this->reset_phpmailer();
$this->configure_phpmailer();
$this->php_mailer->setFrom( $from['email'], empty( $from['name'] ) ? '' : $from['name'] );
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, sprintf( 'Using From Name: %s, From Email: %s', empty( $from['name'] ) ? '' : $from['name'], $from['email'] ) ) );
foreach( $to->recipients() as $recipient ) {
if ( ! empty( $recipient->name() ) ) {
$this->php_mailer->addAddress( $recipient->email(), $recipient->name() );
} else {
$this->php_mailer->addAddress( $recipient->email() );
}
}
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Email recipients: ' . json_encode( $to->as_array() ) ) );
$this->php_mailer->Subject = $subject;
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Email subject: ' . $subject ) );
$this->php_mailer->Body = $message;
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Email message: ' . esc_html( $message ) ) );
if ( ! empty( $headers['cc'] ) ) {
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Email CC: ' . json_encode( $headers['cc']->as_array() ) ) );
foreach ( $headers['cc']->recipients() as $recipient ) {
if ( ! empty( $recipient->name() ) ) {
$this->php_mailer->addCC( $recipient->email(), $recipient->name() );
} else {
$this->php_mailer->addCC( $recipient->email() );
}
}
}
if ( ! empty( $headers['bcc'] ) ) {
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Email BCC: ' . json_encode( $headers['bcc']->as_array() ) ) );
foreach ( $headers['bcc']->recipients() as $recipient ) {
if ( ! empty( $recipient->name() ) ) {
$this->php_mailer->addBCC( $recipient->email(), $recipient->name() );
} else {
$this->php_mailer->addBCC( $recipient->email() );
}
}
}
if ( ! empty( $attachments ) ) {
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Email attachments: ' . json_encode( $attachments ) ) );
foreach ( $attachments as $attachment ) {
$this->php_mailer->addAttachment( $attachment );
}
}
if ( ! empty( $reply_to ) ) {
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Email reply_to: ' . json_encode( $reply_to ) ) );
foreach( $reply_to as $address ) {
if ( isset( $address['name'] ) ) {
$this->php_mailer->addReplyTo( $address['email'], $address['name'] );
} else {
$this->php_mailer->addReplyTo( $address['email'] );
}
}
}
if ( ! empty( $headers['content-type'] ) && strpos( $headers['content-type'], 'text/html' ) !== false ) {
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Setting content type to text/html' ) );
$this->php_mailer->isHTML( true );
} else {
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Setting content type to text/plain' ) );
$this->php_mailer->isHTML( false );
$this->php_mailer->ContentType = 'text/plain';
}
$additional_headers = $this->get_filtered_message_headers();
if ( ! empty( $additional_headers ) ) {
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Additional email headers: ' . json_encode( $additional_headers ) ) );
foreach ( $additional_headers as $key => $value ) {
$this->php_mailer->addCustomHeader( $key, $value );
}
}
if ( (bool) $this->get_setting( self::SETTING_USE_RETURN_PATH, false ) ) {
$this->php_mailer->Sender = $this->php_mailer->From;
}
$this->logger->log( $email, 'pre_send', array(
self::SETTING_AUTH => $this->php_mailer->SMTPAuth,
'secure' => $this->php_mailer->SMTPSecure,
self::SETTING_HOST => $this->php_mailer->Host,
self::SETTING_PORT => $this->php_mailer->Port,
) );
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'SMTP Connection Details: ' . json_encode( array(
self::SETTING_AUTH => $this->php_mailer->SMTPAuth,
'secure' => $this->php_mailer->SMTPSecure,
self::SETTING_HOST => $this->php_mailer->Host,
self::SETTING_PORT => $this->php_mailer->Port,
) ) ) );
if ( $this->is_test_mode() ) {
$this->events->update( array( 'status' => 'sandboxed' ), $email );
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Test mode is enabled, sandboxing email.' ) );
return true;
}
/**
* Fires after PHPMailer is initialized.
*
* @since 2.2.0
*
* @param PHPMailer $phpmailer The PHPMailer instance (passed by reference).
*/
do_action_ref_array( 'phpmailer_init', array( &$this->php_mailer ) );
$this->php_mailer->send();
$this->events->update( array( 'status' => 'sent' ), $email );
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Email successfully sent.' ) );
return true;
} catch ( \Exception $e ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $this->php_mailer->ErrorInfo );
$this->debug_logger->log_error( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Email failed to send. Details: ' . $this->php_mailer->ErrorInfo ) );
return $email;
}
}
/**
* Get the request parameters for sending email through connector.
*
* @since 1.0
*
* @return array
*/
public function get_request_params() {
return array();
}
/**
* Connector data.
*
* @since 1.0
*
* @return array
*/
public function connector_data() {
return array(
self::SETTING_HOST => $this->get_setting( self::SETTING_HOST, '' ),
self::SETTING_PORT => $this->get_setting( self::SETTING_PORT, '' ),
self::SETTING_AUTH => $this->get_setting( self::SETTING_AUTH, false ),
self::SETTING_USERNAME => $this->get_setting( self::SETTING_USERNAME, '' ),
self::SETTING_PASSWORD => $this->get_setting( self::SETTING_PASSWORD, '' ),
self::SETTING_FROM_EMAIL => $this->get_setting( self::SETTING_FROM_EMAIL, '' ),
self::SETTING_FORCE_FROM_EMAIL => $this->get_setting( self::SETTING_FORCE_FROM_EMAIL, false ),
self::SETTING_FROM_NAME => $this->get_setting( self::SETTING_FROM_NAME, '' ),
self::SETTING_FORCE_FROM_NAME => $this->get_setting( self::SETTING_FORCE_FROM_NAME, false ),
self::SETTING_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_REPLY_TO_EMAIL, '' ),
self::SETTING_FORCE_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_FORCE_REPLY_TO_EMAIL, false ),
self::SETTING_ENCRYPTION_TYPE => $this->get_setting( self::SETTING_ENCRYPTION_TYPE, 'tls' ),
self::SETTING_AUTO_TLS => (bool) $this->get_setting( self::SETTING_AUTO_TLS, false ),
self::SETTING_USE_RETURN_PATH => (bool) $this->get_setting( self::SETTING_USE_RETURN_PATH, false ),
);
}
/**
* Settings fields.
*
* @since 1.0
*
* @return array
*/
public function settings_fields() {
$encryption_type = $this->get_setting( self::SETTING_ENCRYPTION_TYPE, 'tls' );
return array(
'title' => esc_html__( 'Custom SMTP Settings', 'gravitysmtp' ),
'description' => '',
'fields' => array_merge(
array(
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Configuration', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => [ 4, 0, 4, 0 ],
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
// array(
// 'component' => 'Toggle',
// 'props' => array(
// 'initialChecked' => (bool) $this->get_plugin_setting( 'primary' ) === $this->name,
// 'labelAttributes' => array(
// 'label' => esc_html__( 'If enabled, Custom SMTP will be the default SMTP mailer.', 'gravitysmtp' ),
// ),
// 'labelPosition' => 'left',
// 'name' => 'default-mailer',
// 'size' => 'size-m',
// 'spacing' => 5,
// 'width' => 'full',
// ),
// ),
array(
'component' => 'Input',
'props' => array(
'helpTextAttributes' => array(
'content' => esc_html__( 'The URL (such as smtp.mailprovider.com) or IP address of your SMTP host.', 'gravitysmtp' ),
'spacing' => [ 2, 0, 0, 0 ],
),
'labelAttributes' => array(
'label' => esc_html__( 'SMTP Hostname', 'gravitysmtp' ),
),
'name' => self::SETTING_HOST,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_HOST, '' ),
),
),
array(
'component' => 'Input',
'props' => array(
'helpTextAttributes' => array(
'content' => esc_html__( 'Port 465 is usually used with SSL. Ports 25 and 587 are usually used with TLS.', 'gravitysmtp' ),
'spacing' => [ 2, 0, 0, 0 ],
),
'labelAttributes' => array(
'label' => esc_html__( 'SMTP Port', 'gravitysmtp' ),
),
'name' => self::SETTING_PORT,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_PORT, '' ),
),
),
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'General Settings', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => 4,
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
array(
'component' => 'Toggle',
'props' => array(
'helpTextAttributes' => array(
'content' => esc_html__( 'If Return Path is enabled this adds the return path to the email header which indicates where non-deliverable notifications should be sent. Bounce messages may be lost if not enabled.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
'spacing' => [ 2, 0, 0, 0 ],
),
'helpTextWidth' => 'full',
'initialChecked' => (bool) $this->get_setting( self::SETTING_USE_RETURN_PATH, false ),
'labelAttributes' => array(
'label' => esc_html__( 'Return Path', 'gravitysmtp' ),
),
'labelPosition' => 'left',
'name' => self::SETTING_USE_RETURN_PATH,
'size' => 'size-m',
'spacing' => 5,
'width' => 'full',
),
),
array(
'component' => 'Toggle',
'props' => array(
'helpTextAttributes' => array(
'content' => esc_html__( 'SMTP servers usually use TLS if available. However, on some servers, you may need to disable it to prevent issues.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
'spacing' => [ 2, 0, 0, 0 ],
),
'helpTextWidth' => 'full',
'initialChecked' => (bool) $this->get_setting( self::SETTING_AUTO_TLS, false ),
'labelAttributes' => array(
'label' => esc_html__( 'Auto TLS', 'gravitysmtp' ),
),
'labelPosition' => 'left',
'name' => self::SETTING_AUTO_TLS,
'size' => 'size-m',
'spacing' => 5,
'width' => 'full',
),
),
array(
'component' => 'Box',
'props' => array(
'display' => 'block',
'spacing' => 6,
),
'fields' => array(
array(
'component' => 'Label',
'props' => array(
'label' => __( 'Encryption', 'gravitysmtp' ),
//'htmlFor' => self::SETTING_ENCRYPTION_TYPE,
'weight' => 'medium',
'size' => 'text-sm',
'spacing' => 2,
),
),
array(
'component' => 'InputGroup',
'props' => array(
'customAttributes' => array(
'style' => array(
'display' => 'flex',
),
),
'id' => self::SETTING_ENCRYPTION_TYPE . '_group',
'initialValue' => $encryption_type,
'inputType' => 'radio',
'spacing' => 2,
'data' => array(
array(
'id' => self::SETTING_ENCRYPTION_TYPE . '_tls',
'name' => self::SETTING_ENCRYPTION_TYPE,
'value' => 'tls',
'size' => 'size-md',
'spacing' => array( 0, 4, 0, 0 ),
'labelAttributes' => array(
'label' => __( 'TLS', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'regular',
),
),
array(
'id' => self::SETTING_ENCRYPTION_TYPE . '_ssl',
'name' => self::SETTING_ENCRYPTION_TYPE,
'value' => 'ssl',
'size' => 'size-md',
'spacing' => array( 0, 4, 0, 0 ),
'labelAttributes' => array(
'label' => __( 'SSL', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'regular',
),
),
array(
'id' => self::SETTING_ENCRYPTION_TYPE . '_none',
'name' => self::SETTING_ENCRYPTION_TYPE,
'value' => 'none',
'size' => 'size-md',
'spacing' => array( 0, 4, 0, 0 ),
'labelAttributes' => array(
'label' => __( 'None', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'regular',
),
),
),
),
),
array(
'component' => 'Text',
'props' => array(
'size' => 'text-xs',
'weight' => 'regular',
'content' => esc_html__( 'In most cases, TLS is the preferred encryption method.', 'gravitysmtp' ),
),
)
),
),
array(
'component' => 'Toggle',
'props' => array(
'helpTextAttributes' => array(
'content' => esc_html__( 'Enable authentication if your SMTP server requires a username and password. This option should be enabled in most cases.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
'spacing' => [ 2, 0, 0, 0 ],
),
'helpTextWidth' => 'full',
'initialChecked' => (bool) $this->get_setting( self::SETTING_AUTH, false ),
'labelAttributes' => array(
'label' => esc_html__( 'Authentication', 'gravitysmtp' ),
),
'labelPosition' => 'left',
'name' => self::SETTING_AUTH,
'size' => 'size-m',
'spacing' => 5,
'width' => 'full',
),
),
array(
'component' => 'Input',
'props' => array(
'helpTextAttributes' => array(
'content' => esc_html__( 'The username for logging into your mail server.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'labelAttributes' => array(
'label' => esc_html__( 'Authentication Username', 'gravitysmtp' ),
),
'name' => self::SETTING_USERNAME,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_USERNAME, '' ),
),
),
array(
'component' => 'Input',
'props' => array(
'helpTextAttributes' => array(
'content' => esc_html__( 'The password for accessing your mail server. It will be stored securely in the database.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'customAttributes' => array(
'style' => array(
'display' => 'block',
'width' => '100%',
),
),
'labelAttributes' => array(
'label' => esc_html__( 'Authentication Password', 'gravitysmtp' ),
),
'name' => self::SETTING_PASSWORD,
'size' => 'size-l',
'spacing' => 6,
'type' => 'password',
'value' => $this->get_setting( self::SETTING_PASSWORD, '' ),
),
),
),
$this->get_from_settings_fields(),
$this->get_reply_to_settings_fields(),
),
);
}
/**
* Determine if the SMTP credentials are configured correctly.
*
* @since 1.0
*
* @return bool|\WP_Error
*/
public function is_configured() {
// Protect against other plugins modifying PHPMailer.
if ( ! class_exists( 'PHPMailer\PHPMailer\SMTP' ) ) {
$error = new \WP_Error( 'invalid_configuration', __( 'PHPMailer is not configured on this system.', 'gravitysmtp' ) );
return $error;
}
$this->configure_phpmailer();
try {
// @todo - this can be adjusted if we find it's causing correct-but-slow configurations to fail.
$this->php_mailer->Timeout = 10;
$this->php_mailer->smtpConnect();
} catch ( \Exception $e ) {
$error = new \WP_Error( 'invalid_configuration', $e->getMessage() );
self::$configured = $error;
return $error;
}
self::$configured = true;
return true;
}
/**
* Reset the PHPMailer instance to prevent carryover from previous send.
*
* @since 1.0
*
* @return void
*/
private function reset_phpmailer() {
$this->php_mailer->clearCustomHeaders();
$this->php_mailer->clearAddresses();
$this->php_mailer->clearBCCs();
$this->php_mailer->clearCCs();
$this->php_mailer->clearAllRecipients();
$this->php_mailer->clearReplyTos();
$this->php_mailer->clearAttachments();
}
/**
* Configure the PHPMailer instance.
*
* @since 1.0
*
* @return void
*/
private function configure_phpmailer() {
$this->php_mailer->isSMTP();
$this->php_mailer->CharSet = \PHPMailer\PHPMailer\PHPMailer::CHARSET_UTF8;
$this->php_mailer->Host = $this->get_setting( self::SETTING_HOST, '' );
$this->php_mailer->Port = $this->get_setting( self::SETTING_PORT, '' );
if ( (bool) $this->get_setting( self::SETTING_AUTH ) ) {
$this->php_mailer->SMTPAuth = true;
$this->php_mailer->Username = $this->get_setting( self::SETTING_USERNAME, '' );
$this->php_mailer->Password = $this->get_setting( self::SETTING_PASSWORD, '' );
}
$this->php_mailer->SMTPSecure = $this->get_setting( self::SETTING_ENCRYPTION_TYPE, 'tls' );
$this->php_mailer->SMTPAutoTLS = (bool) $this->get_setting( self::SETTING_AUTO_TLS, false );
}
}
@@ -0,0 +1,642 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Types;
use Google\Client;
use Google\Service\Gmail;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Base;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Connectors\Oauth\Google_Oauth_Handler;
use Gravity_Forms\Gravity_SMTP\Connectors\Oauth_Handler;
use Gravity_Forms\Gravity_SMTP\Gravity_SMTP;
use Gravity_Forms\Gravity_SMTP\Utils\Booliesh;
/**
* Connector for Google / Gmail
*
* @since 1.0
*/
class Connector_Google extends Connector_Base {
const SETTING_ACCESS_TOKEN = 'access_token';
const SETTING_CLIENT_ID = 'client_id';
const SETTING_CLIENT_SECRET = 'client_secret';
const SETTING_USE_RETURN_PATH = 'use_return_path';
const VALUE_REDIRECT_URI = 'redirect_uri';
protected $name = 'google';
protected $title = 'Google';
protected $disabled = true;
protected $description = '';
protected $logo = 'Google';
protected $full_logo = 'GoogleFull';
protected $oauth_handler;
public function init( $to, $subject, $message, $headers = '', $attachments = array(), $source = '' ) {
parent::init( $to, $subject, $message, $headers, $attachments, $source );
$this->oauth_handler = \Gravity_Forms\Gravity_SMTP\Gravity_SMTP::container()->get( Connector_Service_Provider::GOOGLE_OAUTH_HANDLER );
}
public function get_description() {
return esc_html__( 'Integrate your website with Gmail or a Google Workspace account, helping to improve email deliverability and prevent your carefully crafted content from ending up in spam folders. Be sure to check the email sending limits for Gmail and Google Workspace. For more information on how to get started with Gmail / Google Workspace, read our documentation.', 'gravitysmtp' );
}
protected $sensitive_fields = array(
self::SETTING_ACCESS_TOKEN,
self::SETTING_CLIENT_ID,
self::SETTING_CLIENT_SECRET,
);
/**
* Sending logic.
*
* @since 1.0
*
* @return bool
*/
public function send() {
$to = $this->get_att( 'to', '' );
$subject = $this->get_att( 'subject', '' );
$message = $this->get_att( 'message', '' );
$headers = $this->get_parsed_headers( $this->get_att( 'headers', array() ) );
$attachments = $this->get_att( 'attachments', array() );
$from = $this->get_from( true );
$reply_to = $this->get_reply_to( true );
$source = $this->get_att( 'source' );
$params = $this->get_request_params();
$email = $this->email;
$this->reset_phpmailer();
if ( ! empty( $headers['content-type'] ) ) {
$headers['content-type'] = $this->get_att( 'content_type', $headers['content-type'] );
}
$this->set_email_log_data( $subject, $message, $to, empty( $from['name'] ) ? $from['email'] : sprintf( '%s <%s>', $from['name'], $from['email'] ), $headers, $attachments, $source, $params );
$this->logger->log( $email, 'started', __( 'Starting email send for Google connector.', 'gravitysmtp' ) );
$this->php_mailer->setFrom( $from['email'], empty( $from['name'] ) ? '' : $from['name'] );
foreach( $to->recipients() as $recipient ) {
if ( ! empty( $recipient->name() ) ) {
$this->php_mailer->addAddress( $recipient->email(), $recipient->name() );
} else {
$this->php_mailer->addAddress( $recipient->email() );
}
}
$this->php_mailer->Subject = $subject;
$this->php_mailer->Body = $message;
if ( ! empty( $headers['cc'] ) ) {
foreach ( $headers['cc']->recipients() as $recipient ) {
if ( ! empty( $recipient->name() ) ) {
$this->php_mailer->addCC( $recipient->email(), $recipient->name() );
} else {
$this->php_mailer->addCC( $recipient->email() );
}
}
}
if ( ! empty( $headers['bcc'] ) ) {
foreach ( $headers['bcc']->recipients() as $recipient ) {
if ( ! empty( $recipient->name() ) ) {
$this->php_mailer->addBCC( $recipient->email(), $recipient->name() );
} else {
$this->php_mailer->addBCC( $recipient->email() );
}
}
}
if ( ! empty( $attachments ) ) {
foreach ( $attachments as $attachment ) {
$this->php_mailer->addAttachment( $attachment );
}
}
if ( ! empty( $reply_to ) ) {
foreach( $reply_to as $address ) {
if ( isset( $address['name'] ) ) {
$this->php_mailer->addReplyTo( $address['email'], $address['name'] );
} else {
$this->php_mailer->addReplyTo( $address['email'] );
}
}
}
if ( ! empty( $headers['content-type'] ) && strpos( $headers['content-type'], 'text/html' ) !== false ) {
$this->php_mailer->isHTML( true );
} else {
$this->php_mailer->isHTML( false );
$this->php_mailer->ContentType = 'text/plain';
}
$this->php_mailer->CharSet = 'UTF-8';
$additional_headers = $this->get_filtered_message_headers();
if ( ! empty( $additional_headers ) ) {
foreach ( $additional_headers as $key => $value ) {
$this->php_mailer->addCustomHeader( $key, $value );
}
}
if ( (bool) $this->get_setting( self::SETTING_USE_RETURN_PATH, false ) ) {
$this->php_mailer->Sender = $this->php_mailer->From;
}
if ( $this->is_test_mode() ) {
$this->events->update( array( 'status' => 'sandboxed' ), $email );
$this->logger->log( $email, 'sandboxed', __( 'Email sandboxed.', 'gravitysmtp' ) );
return true;
}
try {
$debug_atts = compact( 'to', 'from', 'subject', 'headers', 'source', 'attachments', 'reply_to' );
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Attempting send with the following attributes: ' . json_encode( $debug_atts ) ) );
$raw = $this->get_raw_message();
$body = array(
'raw' => $raw,
);
$url = 'https://gmail.googleapis.com/gmail/v1/users/me/messages/send';
/**
* @var Google_Oauth_Handler $oauth_handler
*/
$oauth_handler = Gravity_SMTP::container()->get( Connector_Service_Provider::GOOGLE_OAUTH_HANDLER );
$token = $oauth_handler->get_access_token();
if ( is_wp_error( $token ) ) {
throw new \Exception( $token->get_error_message() );
}
$headers = array(
'Authorization' => 'Bearer ' . $token,
'Content-Type' => 'application/json',
);
$args = array(
'body' => json_encode( $body ),
'headers' => $headers,
);
$response = wp_remote_post( $url, $args );
$response_body = wp_remote_retrieve_body( $response );
$response_code = wp_remote_retrieve_response_code( $response );
if ( (int) $response_code !== 200 ) {
$this->log_failure( $email, $response_body );
return $email;
}
$this->events->update( array( 'status' => 'sent' ), $email );
$this->logger->log( $email, 'sent', __( 'Email successfully sent.', 'gravitysmtp' ) );
return true;
} catch ( \Exception $e ) {
$this->log_failure( $email, $e->getMessage() );
$this->debug_logger->log_fatal( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Failed to send: ' . $e->getMessage() ) );
return $email;
}
}
private function log_failure( $email, $message ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $message );
}
private function get_raw_message() {
$this->php_mailer->preSend();
$raw = $this->php_mailer->getSentMIMEMessage();
return str_replace(
[ '+', '/', '=' ],
[ '-', '_', '' ],
base64_encode( $raw )
);
}
/**
* Connector data.
*
* @since 1.0
*
* @return array
*/
public function connector_data() {
return array(
self::SETTING_CLIENT_ID => $this->get_setting( self::SETTING_CLIENT_ID, '' ),
self::SETTING_CLIENT_SECRET => $this->get_setting( self::SETTING_CLIENT_SECRET, '' ),
self::SETTING_ACCESS_TOKEN => $this->get_setting( self::SETTING_ACCESS_TOKEN, '' ),
self::SETTING_FROM_EMAIL => $this->get_setting( self::SETTING_FROM_EMAIL, '' ),
self::SETTING_FORCE_FROM_EMAIL => $this->get_setting( self::SETTING_FORCE_FROM_EMAIL, false ),
self::SETTING_FROM_NAME => $this->get_setting( self::SETTING_FROM_NAME, '' ),
self::SETTING_FORCE_FROM_NAME => $this->get_setting( self::SETTING_FORCE_FROM_NAME, false ),
self::SETTING_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_REPLY_TO_EMAIL, '' ),
self::SETTING_FORCE_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_FORCE_REPLY_TO_EMAIL, false ),
self::SETTING_USE_RETURN_PATH => (bool) $this->get_setting( self::SETTING_USE_RETURN_PATH, false ),
'oauth_url' => 'https://accounts.google.com/o/oauth2/v2/auth',
'oauth_params' => '&' . $this->get_oauth_params(),
);
}
protected function get_oauth_params() {
/**
* @var Google_Oauth_Handler $oauth_handler
*/
$oauth_handler = Gravity_SMTP::container()->get( Connector_Service_Provider::GOOGLE_OAUTH_HANDLER );
$params = array(
'response_type' => 'code',
'redirect_uri' => urldecode( $oauth_handler->get_return_url() ),
'scope' => 'https://www.googleapis.com/auth/gmail.send https://www.googleapis.com/auth/gmail.readonly',
'include_granted_scopes' => 'true',
'state' => 1,
'access_type' => 'offline',
'prompt' => 'consent',
);
return http_build_query( $params );
}
/**
* Settings fields.
*
* @since 1.0
*
* @return array
*/
public function settings_fields() {
/**
* @var Oauth_Handler $oauth_handler
*/
$oauth_handler = Gravity_SMTP::container()->get( Connector_Service_Provider::GOOGLE_OAUTH_HANDLER );
$oauth_handler->handle_response( $this->name );
$token = $oauth_handler->get_access_token( $this->name );
$has_token = $token && ! is_wp_error( $token );
$settings = array(
'title' => esc_html__( 'Google / Gmail Settings', 'gravitysmtp' ),
'hide_save' => ! $has_token,
'fields' => array(),
);
if ( ! $has_token ) {
$settings['fields'][] = array(
'component' => 'Alert',
'props' => array(
'id' => 'google-connection-notice',
'customIconPrefix' => 'gravity-admin-icon',
'theme' => 'cosmos',
'type' => 'notice',
'spacing' => 3,
),
'fields' => array(
array(
'component' => 'Text',
'props' => array(
'content' => esc_html__( 'Before proceeding, make sure to save your settings with the Client ID and Client Secret.', 'gravitysmtp' ),
'customClasses' => array( 'gform--display-block', 'gravitysmtp-integration__notice-message' ),
'size' => 'text-sm',
'spacing' => 4,
'tagName' => 'span',
),
),
array(
'component' => 'Link',
'props' => array(
'content' => esc_html__( 'Read our Google / Gmail documentation', 'gravitysmtp' ),
'customClasses' => array(
'gform-link--theme-cosmos',
'gravitysmtp-integration__notice-link',
'gform-button',
'gform-button--size-height-m',
'gform-button--white',
'gform-button--width-auto'
),
'href' => 'https://docs.gravitysmtp.com/category/integrations/google/',
'target' => '_blank',
),
),
),
);
} else {
$settings['fields'][] = array(
'component' => 'Alert',
'props' => array(
'id' => 'google-alias-notice',
'customIconPrefix' => 'gravity-admin-icon',
'theme' => 'cosmos',
'type' => 'info',
'spacing' => 3,
),
'fields' => array(
array(
'component' => 'LinkedText',
'external' => true,
'links' => array(
array(
'key' => 'link',
'props' => array(
'href' => 'https://docs.gravitysmtp.com/how-to-send-emails-from-an-alias-google-gmail/',
'size' => 'text-sm',
'target' => '_blank',
),
),
),
'props' => array(
'customClasses' => array( 'gform--display-block' ),
'content' => esc_html__( 'Important: To use alias email addresses with Gravity SMTP, ensure your primary Google account is authenticated, then add and verify your alias in your Google account settings. For detailed instructions, please refer to our {{link}}documentation article{{link}}.', 'gravitysmtp' ),
'weight' => 'medium',
'size' => 'text-sm',
'tagName' => 'span',
),
),
),
);
}
if ( isset( $_GET['code'] ) && ! $has_token ) {
$settings['fields'][] = array(
'component' => 'Alert',
'props' => array(
'id' => 'google-connection-error',
'customIconPrefix' => 'gravity-admin-icon',
'theme' => 'cosmos',
'type' => 'error',
'spacing' => 3,
),
'fields' => array(
array(
'component' => 'Text',
'props' => array(
'content' => esc_html__( 'Error Connecting to Google. Check your credentials and try again.', 'gravitysmtp' ),
'weight' => 'medium',
'size' => 'text-sm',
'spacing' => 2,
'tagName' => 'span',
),
),
),
);
}
$settings['fields'][] = array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Configuration', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => [ 4, 0, 3, 0 ],
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
);
if ( ! $has_token ) {
$settings['fields'][] = array(
'component' => 'LinkedHelpTextInput',
'external' => true,
'handle_change' => true,
'links' => array(
array(
'key' => 'link',
'props' => array(
'href' => 'https://console.cloud.google.com/',
'size' => 'text-xs',
'target' => '_blank',
),
),
),
'props' => array(
'helpTextAttributes' => array(
'content' => esc_html__( 'To obtain a Client ID from Google / Gmail, log in to your {{link}}Google Cloud Console{{link}} and generate the Client ID.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'labelAttributes' => array(
'label' => esc_html__( 'Client ID', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'name' => self::SETTING_CLIENT_ID,
'spacing' => 6,
'size' => 'size-l',
'value' => $this->get_setting( self::SETTING_CLIENT_ID, '' ),
),
);
$settings['fields'][] = array(
'component' => 'LinkedHelpTextInput',
'external' => true,
'handle_change' => true,
'links' => array(
array(
'key' => 'link',
'props' => array(
'href' => 'https://console.cloud.google.com/',
'size' => 'text-xs',
'target' => '_blank',
),
),
),
'props' => array(
'helpTextAttributes' => array(
'content' => esc_html__( 'To obtain a Client Secret from Google / Gmail, log in to your {{link}}Google Cloud Console{{link}} and generate the Client ID.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'labelAttributes' => array(
'label' => esc_html__( 'Client Secret', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'name' => self::SETTING_CLIENT_SECRET,
'spacing' => 6,
'size' => 'size-l',
'value' => $this->get_setting( self::SETTING_CLIENT_SECRET, '' ),
),
);
$settings['fields'][] = array(
'component' => 'CopyInput',
'external' => true,
'props' => array(
'actionButtonAttributes' => array(
'customAttributes' => array(
'type' => 'button',
),
'icon' => 'copy',
'iconPrefix' => 'gravity-admin-icon',
'label' => esc_html__( 'Copy', 'gravitysmtp' ),
),
'labelAttributes' => array(
'label' => esc_html__( 'Authorized redirect URI', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'name' => self::VALUE_REDIRECT_URI,
'spacing' => 6,
'size' => 'size-l',
'customAttributes' => array(
'readOnly' => true,
),
'value' => urldecode( $oauth_handler->get_return_url( 'settings' ) ),
'helpTextAttributes' => array(
'content' => __( 'Copy this URL into the "Authorized redirect URIs" field of your Google web application.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
),
),
);
$settings['fields'][] = array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Authorization', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => [ 4, 0, 3, 0 ],
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
);
$settings['fields'][] = array(
'component' => 'BrandedButton',
'external' => true,
'props' => array(
'label' => esc_html__( 'Sign in with Google', 'gravitysmtp' ),
'spacing' => 4,
'Svg' => 'GoogleAltLogo',
'type' => 'color',
),
);
} else {
$settings['fields'][] = array(
'component' => 'Box',
'props' => array(
'customClasses' => array( 'gravitysmtp-google-integration__connected-message' ),
'display' => 'flex',
'spacing' => 3,
),
'fields' => array(
array(
'component' => 'Icon',
'props' => array(
'customClasses' => array( 'gravitysmtp-google-integration__checkmark', 'gform-icon--preset-active', 'gform-icon-preset--status-correct', 'gform-alert__icon' ),
'icon' => 'checkmark-simple',
'iconPrefix' => 'gravity-admin-icon',
),
),
array(
'component' => 'Text',
'props' => array(
'asHtml' => true,
'content' => sprintf(
'%s <span class="gform-text gform-text--color-port gform-typography--size-text-sm gform-typography--weight-medium">%s</span>',
esc_html__( 'Connected with email account:', 'gravitysmtp' ),
esc_html( $oauth_handler->get_connection_details()['email'] )
),
'size' => 'text-sm',
'tagName' => 'span',
),
),
),
);
$disconnect_url = add_query_arg( '_wpnonce', wp_create_nonce( 'gsmtp_disconnect_google' ), admin_url( 'admin-post.php?action=smtp_disconnect_google' ) );
$settings['fields'][] = array(
'component' => 'Text',
'props' => array(
'content' => sprintf( '<a href="%s" class="%s"><span class="gravity-admin-icon gravity-admin-icon--x-circle gform-button__icon"></span>%s</a>', $disconnect_url, 'gform-link gform-link--theme-cosmos gform-button gform-button--size-height-m gform-button--white gform-button--width-auto gform-button--active-type-loader gform-button--loader-after gform-button--icon-leading', __( 'Disconnect from Google', 'gravitysmtp' ) ),
'asHtml' => true,
'spacing' => 6,
),
);
$settings['fields'][] = array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Configuration', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => [ 4, 0, 4, 0 ],
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
);
$settings['fields'][] = array(
'component' => 'Toggle',
'props' => array(
'helpTextAttributes' => array(
'content' => esc_html__( 'If Return Path is enabled this adds the return path to the email header which indicates where non-deliverable notifications should be sent. Bounce messages may be lost if not enabled.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
'spacing' => [ 2, 0, 0, 0 ],
),
'helpTextWidth' => 'full',
'initialChecked' => (bool) $this->get_setting( self::SETTING_USE_RETURN_PATH, false ),
'labelAttributes' => array(
'label' => esc_html__( 'Return Path', 'gravitysmtp' ),
),
'labelPosition' => 'left',
'name' => self::SETTING_USE_RETURN_PATH,
'size' => 'size-m',
'spacing' => 5,
'width' => 'full',
),
);
$settings['fields'] = array_merge( $settings['fields'], $this->get_from_settings_fields(), $this->get_reply_to_settings_fields() );
}
return $settings;
}
public function is_configured() {
if ( Booliesh::get( $this->get_setting( 'access_token', false ) ) ) {
/**
* @var Google_Oauth_Handler $oauth_handler
*/
$oauth_handler = Gravity_SMTP::container()->get( Connector_Service_Provider::GOOGLE_OAUTH_HANDLER );
$token = $oauth_handler->get_access_token();
return $token;
}
return false;
}
/**
* Reset the PHPMailer instance to prevent carryover from previous send.
*
* @since 1.0
*
* @return void
*/
private function reset_phpmailer() {
$this->php_mailer->clearCustomHeaders();
$this->php_mailer->clearAddresses();
$this->php_mailer->clearBCCs();
$this->php_mailer->clearCCs();
$this->php_mailer->clearAllRecipients();
$this->php_mailer->clearReplyTos();
$this->php_mailer->clearAttachments();
}
}
@@ -0,0 +1,440 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Types;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Base;
use Gravity_Forms\Gravity_SMTP\Feature_Flags\Feature_Flag_Manager;
/**
* Connector for Mailchimp
*
* @since 1.4.2
*/
class Connector_Mailchimp extends Connector_Base {
const SETTING_API_KEY = 'api_key';
const SETTING_USE_RETURN_PATH = 'use_return_path';
protected $name = 'mailchimp';
protected $title = 'Mailchimp';
protected $logo = 'Mailchimp';
protected $full_logo = 'MailchimpFull';
protected $url = 'https://mandrillapp.com/api/1.0/';
public function get_description() {
return esc_html__( 'Reach inboxes when it matters most. Send email notifications to your contacts with MailChimp Transactional Email.', 'gravitysmtp' );
}
protected $sensitive_fields = array(
self::SETTING_API_KEY,
);
protected function get_merged_data() {
$data = parent::get_merged_data();
$data['disabled'] = ! Feature_Flag_Manager::is_enabled( 'mailchimp_integration' );
return $data;
}
/**
* Sending logic.
*
* @since 1.4.2
*
* @return bool
*/
public function send() {
try {
$atts = $this->get_send_atts();
$source = $this->get_att( 'source' );
$from = $this->get_from( true );
$params = $this->get_request_params();
$email = $this->email;
$this->set_email_log_data( $atts['subject'], $atts['message'], $atts['to'], $atts['from']['from'], $atts['headers'], $atts['attachments'], $source, $params );
$this->logger->log( $email, 'started', __( 'Starting email send for Mailchimp connector.', 'gravitysmtp' ) );
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Starting email send with Mailchimp connector and the following params: ' . json_encode( $params) ) );
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, sprintf( 'Using From Name: %s, From Email: %s', $from['name'], $from['email'] ) ) );
if ( $this->is_test_mode() ) {
$this->events->update( array( 'status' => 'sandboxed' ), $email );
$this->logger->log( $email, 'sandboxed', __( 'Email sandboxed.', 'gravitysmtp' ) );
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Test mode is enabled, sandboxing email.' ) );
return true;
}
$url = $this->url . 'messages/send';
$response = wp_safe_remote_post( $url, $params );
$body = wp_remote_retrieve_body( $response );
$decoded = json_decode( $body, true );
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Received response of: ' . $body ) );
$is_success = (int) wp_remote_retrieve_response_code( $response ) === 200 && $decoded[0]['status'] !== 'rejected';
if ( ! $is_success ) {
$this->log_failure( $email, $body );
$this->debug_logger->log_error( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Email failed to send. Details: ' . $body ) );
return $email;
}
$this->events->update( array( 'status' => 'sent' ), $email );
$this->logger->log( $email, 'sent', __( 'Email successfully sent.', 'gravitysmtp' ) );
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Email successfully sent.' ) );
return true;
} catch ( \Exception $e ) {
$this->log_failure( $email, $e->getMessage() );
$this->debug_logger->log_error( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Email failed to send. Details: ' . $e->getMessage() ) );
return $email;
}
}
/**
* Logs an email send failure.
*
* @since 1.4.2
*
* @param string $email The email that failed.
* @param string $error_message The error message.
*/
private function log_failure( $email, $error_message ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $error_message );
}
/**
* Get the request parameters for sending email through connector.
*
* @since 1.4.2
*
* @return array
*/
public function get_request_params() {
$atts = $this->get_send_atts();
$api_key = $this->get_setting( self::SETTING_API_KEY );
$body = array(
'key' => $api_key,
'message' => array(
'subject' => $atts['subject'],
'from_email' => $atts['from']['email'],
'headers' => array(),
),
);
if ( ! empty( $atts['from']['name'] ) ) {
$body['message']['from_name'] = $atts['from']['name'];
}
if ( ! empty( $atts['to'] ) ) {
$body['message']['to'] = $atts['to']->as_array();
}
// Setting content
$is_html = ! empty( $atts['headers']['content-type'] ) && strpos( $atts['headers']['content-type'], 'text/html' ) !== false;
if ( $is_html ) {
$body['message']['html'] = $atts['message'];
$body['message']['text'] = wp_strip_all_tags( $atts['message'] );
} else {
$body['message']['text'] = $atts['message'];
}
// Setting reply-to
if ( ! empty( $atts['headers']['reply-to'] ) ) {
$address = str_replace( 'Reply-To: ', '', $atts['headers']['reply-to'] );
$body['message']['headers']['reply-to'] = $address;
}
// Setting cc
if ( ! empty( $atts['headers']['cc'] ) ) {
foreach ( $atts['headers']['cc']->as_array() as $recipient ) {
if ( isset( $recipient['email'] ) ) {
$body['message']['to'][] = array(
'type' => 'cc',
'email' => $recipient['email'],
);
}
}
}
// Setting bcc
if ( ! empty( $atts['headers']['bcc'] ) ) {
foreach ( $atts['headers']['bcc']->as_array() as $recipient ) {
if ( isset( $recipient['email'] ) ) {
$body['message']['to'][] = array(
'type' => 'bcc',
'email' => $recipient['email'],
);
}
}
}
if ( (bool) $this->get_setting( self::SETTING_USE_RETURN_PATH, false ) ) {
$body['message']['return_path_domain'] = $atts['from']['email'];
}
// Setting attachments
if ( ! empty( $atts['attachments'] ) ) {
$body['message']['attachments'] = $this->get_attachments( $atts['attachments'] );
}
return array(
'body' => json_encode( $body ),
'headers' => array(
'Content-Type' => 'application/json',
),
);
}
/**
* Gets a list of attachments, and returns them in a format that can be used by the API.
*
* @param array $attachments The list of attachments.
*
* @since 1.4.2
*
* @return array Returns an array of attachments. Each item with a 'content' and 'name' property.
*/
protected function get_attachments( $attachments ) {
$data = array();
foreach ( $attachments as $custom_name => $attachment ) {
try {
if ( is_file( $attachment ) && is_readable( $attachment ) ) {
$file_name = is_numeric( $custom_name ) ? basename( $attachment ) : $custom_name;
$content = base64_encode( file_get_contents( $attachment ) );
$data[] = array(
'name' => $file_name,
'content' => $content,
'type' => mime_content_type( $attachment ),
);
}
} catch ( \Exception $e ) {
continue;
}
}
return $data;
}
/**
* Get the attributes for sending email.
*
* @since 1.4.2
*
* @return array
*/
protected function get_send_atts() {
$headers = $this->get_parsed_headers( $this->get_att( 'headers', array() ) );
if ( ! empty( $headers['content-type'] ) ) {
$headers['content-type'] = $this->get_att( 'content_type', $headers['content-type'] );
}
return array(
'to' => $this->get_att( 'to', '' ),
'subject' => $this->get_att( 'subject', '' ),
'message' => $this->get_att( 'message', '' ),
'headers' => $headers,
'attachments' => $this->get_att( 'attachments', array() ),
'from' => $this->get_from( true ),
'reply_to' => $this->get_reply_to( true ),
);
}
/**
* Connector data.
*
* @since 1.4.2
*
* @return array
*/
public function connector_data() {
return array(
self::SETTING_API_KEY => $this->get_setting( self::SETTING_API_KEY, '' ),
self::SETTING_FROM_EMAIL => $this->get_setting( self::SETTING_FROM_EMAIL, '' ),
self::SETTING_FORCE_FROM_EMAIL => $this->get_setting( self::SETTING_FORCE_FROM_EMAIL, false ),
self::SETTING_FROM_NAME => $this->get_setting( self::SETTING_FROM_NAME, '' ),
self::SETTING_FORCE_FROM_NAME => $this->get_setting( self::SETTING_FORCE_FROM_NAME, false ),
self::SETTING_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_REPLY_TO_EMAIL, '' ),
self::SETTING_FORCE_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_FORCE_REPLY_TO_EMAIL, false ),
self::SETTING_USE_RETURN_PATH => (bool) $this->get_setting( self::SETTING_USE_RETURN_PATH, false ),
);
}
/**
* Settings fields.
*
* @since 1.4.2
*
* @return array
*/
public function settings_fields() {
return array(
'title' => esc_html__( 'Mailchimp Settings', 'gravitysmtp' ),
'description' => '',
'fields' => array_merge(
array(
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Configuration', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => array( 4, 0, 4, 0 ),
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'API Key', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'helpTextAttributes' => array(
'asHtml' => true,
/* translators: 1: opening anchor tag, 2: closing anchor tag */
'content' => sprintf( __( 'To generate an API key from Mailchimp, navigate to the %ssettings of your Mailchimp Transactional account%s and look for the API Keys section.', 'gravitysmtp' ), '<a class="gform-link gform-typography--size-text-xs" href="https://mandrillapp.com/settings" target="_blank" rel="noopener noreferrer">', '</a>' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'name' => self::SETTING_API_KEY,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_API_KEY, '' ),
),
),
),
array(
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'General Settings', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => 4,
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
array(
'component' => 'Toggle',
'props' => array(
'helpTextAttributes' => array(
'content' => esc_html__( 'If Return Path is enabled this adds the return path to the email header which indicates where non-deliverable notifications should be sent. Bounce messages may be lost if not enabled.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
'spacing' => [ 2, 0, 0, 0 ],
),
'helpTextWidth' => 'full',
'initialChecked' => (bool) $this->get_setting( self::SETTING_USE_RETURN_PATH, false ),
'labelAttributes' => array(
'label' => esc_html__( 'Return Path', 'gravitysmtp' ),
),
'labelPosition' => 'left',
'name' => self::SETTING_USE_RETURN_PATH,
'size' => 'size-m',
'spacing' => 5,
'width' => 'full',
),
)
),
$this->get_from_settings_fields(),
$this->get_reply_to_settings_fields(),
),
);
}
public function is_configured() {
static $configured;
if ( ! is_null( $configured ) ) {
return $configured;
}
if ( empty( $this->get_setting( self::SETTING_API_KEY, '' ) ) ) {
return false;
}
$base_url = $this->url . 'users/ping';
$body = json_encode( array(
'key' => $this->get_setting( self::SETTING_API_KEY, '' ),
) );
$params = array(
'body' => $body,
'headers' => array( 'Content-Type' => 'application/json' ),
);
$request = wp_remote_post( $base_url, $params );
$code = wp_remote_retrieve_response_code( $request );
if ( $code === 200 ) {
$configured = true;
return true;
}
$error = new \WP_Error( 'authentication_error', __( 'Could not authenticate with Mailchimp.', 'gravitysmtp' ) );
$configured = $error;
return $error;
}
protected function get_authenticated_domains() {
$base_url = $this->url . 'senders/domains';
$body = json_encode( array(
'key' => $this->get_setting( self::SETTING_API_KEY, '' ),
) );
$params = array(
'body' => $body,
'headers' => array( 'Content-Type' => 'application/json' ),
);
$request = wp_remote_post( $base_url, $params );
$code = wp_remote_retrieve_response_code( $request );
$no_results = array(
__( 'No authenticated Domains found in your account. Sending will not be possible until you add a verified domain to your Mailchimp Account.', 'gravitysmtp' ),
);
if ( $code !== 200 ) {
return $no_results;
}
$body = wp_remote_retrieve_body( $request );
$domains = json_decode( $body, true );
$results = array();
if ( empty( $domains ) ) {
return $no_results;
}
foreach ( $domains as $domain ) {
if ( empty( $domain['verified_at'] ) ) {
continue;
}
$results[] = $domain['domain'];
}
if ( empty( $results ) ) {
return $no_results;
}
return $results;
}
}
@@ -0,0 +1,396 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Types;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Base;
use Gravity_Forms\Gravity_SMTP\Feature_Flags\Feature_Flag_Manager;
/**
* Connector for MailerSend
*
* @since 1.0
*/
class Connector_MailerSend extends Connector_Base {
const SETTING_API_KEY = 'api_key';
protected $name = 'mailersend';
protected $title = 'MailerSend';
protected $disabled = true;
protected $logo = 'MailerSend';
protected $full_logo = 'MailerSendFull';
protected $url = 'https://api.mailersend.com/v1';
protected $sensitive_fields = array(
self::SETTING_API_KEY,
);
public function get_description() {
return esc_html__( 'Deliver transactional emails fast with MailerSend, a developer-friendly platform built for performance and scalability. Easily send notifications, receipts, and more with advanced analytics, templates, and robust API support.', 'gravitysmtp' );
}
/**
* Sends email via MailerSend.
*
* @since 1.0
*
* @return int Returns the email ID.
*/
public function send() {
try {
$atts = $this->get_send_atts();
$source = $this->get_att( 'source' );
$params = $this->get_request_params();
$email = $this->email;
$this->set_email_log_data( $atts['subject'], $atts['message'], $atts['to'], $atts['from']['from'], $atts['headers'], $atts['attachments'], $source, $params );
$this->logger->log( $email, 'started', __( 'Starting email send for MailerSend connector.', 'gravitysmtp' ) );
if ( $this->is_test_mode() ) {
$this->events->update( array( 'status' => 'sandboxed' ), $email );
$this->logger->log( $email, 'sandboxed', __( 'Email sandboxed.', 'gravitysmtp' ) );
return true;
}
$response = wp_safe_remote_post( $this->url . '/email', $params );
$is_success = in_array( (int) wp_remote_retrieve_response_code( $response ), array( 200, 201, 202 ) );
if ( ! $is_success ) {
$this->log_failure( $email, wp_remote_retrieve_body( $response ) );
return $email;
}
$this->events->update( array( 'status' => 'sent' ), $email );
$this->logger->log( $email, 'sent', __( 'Email successfully sent.', 'gravitysmtp' ) );
return true;
} catch ( \Exception $e ) {
$this->log_failure( $email, $e->getMessage() );
return $email;
}
}
/**
* Get the request parameters for sending email through connector.
*
* @since 1.0
*
* @return array
*/
public function get_request_params() {
$atts = $this->get_send_atts();
$api_key = $this->get_setting( self::SETTING_API_KEY );
$body = array(
'subject' => $atts['subject'],
'from' => array(
'email' => $atts['from']['email'],
'name' => $atts['from']['name'],
),
'to' => array(),
);
// Setting to
foreach ( $atts['to']->as_array() as $to ) {
$to_value = array(
'email' => $to['email'],
'name' => ! empty( $to['name'] ) ? $to['name'] : null,
);
$body['to'][] = array_filter( $to_value );
}
// Setting content
$is_html = ! empty( $atts['headers']['content-type'] ) && strpos( $atts['headers']['content-type'], 'text/html' ) !== false;
if ( $is_html ) {
$body['html'] = $atts['message'];
} else {
$body['text'] = $atts['message'];
}
// Setting cc
if ( ! empty( $atts['headers']['cc'] ) ) {
$body['cc'] = array();
foreach ( $atts['headers']['cc']->as_array() as $cc_value ) {
$values = array(
'email' => $cc_value['email'],
'name' => ! empty( $cc_value['name'] ) ? $cc_value['name'] : null,
);
$body['cc'][] = array_filter( $values );
}
}
// Setting bcc
if ( ! empty( $atts['headers']['bcc'] ) ) {
$body['bcc'] = array();
foreach ( $atts['headers']['bcc']->as_array() as $bcc_value ) {
$values = array(
'email' => $bcc_value['email'],
'name' => ! empty( $bcc_value['name'] ) ? $bcc_value['name'] : null,
);
$body['bcc'][] = array_filter( $values );
}
}
// Setting reply to
if ( ! empty( $atts['reply_to'] ) ) {
if ( isset( $atts['reply_to']['email'] ) ) {
$reply_to = $atts['reply_to'];
} else {
$reply_to = $atts['reply_to'][0];
}
$body['reply_to'] = array(
'email' => $reply_to['email'],
);
}
// Setting attachments
if ( ! empty( $atts['attachments'] ) ) {
$body['attachments'] = $this->get_attachments( $atts['attachments'] );
}
return array(
'body' => json_encode( $body ),
'headers' => $this->get_request_headers( $api_key ),
);
}
/**
* Get the attributes for sending email.
*
* @since 1.0
*
* @return array
*/
protected function get_send_atts() {
$headers = $this->get_parsed_headers( $this->get_att( 'headers', array() ) );
if ( ! empty( $headers['content-type'] ) ) {
$headers['content-type'] = $this->get_att( 'content_type', $headers['content-type'] );
}
return array(
'to' => $this->get_att( 'to', '' ),
'subject' => $this->get_att( 'subject', '' ),
'message' => $this->get_att( 'message', '' ),
'headers' => $headers,
'attachments' => $this->get_att( 'attachments', array() ),
'from' => $this->get_from( true ),
'reply_to' => $this->get_reply_to( true ),
);
}
/**
* Gets a list of attachments, and returns them in a format that can be used by the API.
*
* @param array $attachments The list of attachments.
*
* @since 1.0
*
* @return array Returns an array of attachments. Each item with a 'content' and 'name' property.
*/
protected function get_attachments( $attachments ) {
$data = array();
foreach ( $attachments as $custom_name => $attachment ) {
try {
if ( is_file( $attachment ) && is_readable( $attachment ) ) {
$fileName = is_numeric( $custom_name ) ? basename( $attachment ) : $custom_name;
$content = base64_encode( file_get_contents( $attachment ) );
$data[] = array(
'filename' => $fileName,
'content' => $content,
'disposition' => 'attachment',
);
}
} catch ( \Exception $e ) {
continue;
}
}
return $data;
}
/**
* Gets the headers to be used in the API request.
*
* @since 1.0
*
* @return array Returns the header array to be passed to MailerSend's API.
*/
protected function get_request_headers( $api_key ) {
return array(
'content-type' => 'application/json',
'accept' => 'application/json',
'Authorization' => 'Bearer ' . $api_key,
);
}
/**
* Logs an email send failure.
*
* @since 1.0
*
* @param string $email The email that failed.
* @param string $error_message The error message.
*/
private function log_failure( $email, $error_message ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $error_message );
}
/**
* Connector data.
*
* @since 1.0
*
* @return array
*/
public function connector_data() {
return array(
self::SETTING_API_KEY => $this->get_setting( self::SETTING_API_KEY, '' ),
self::SETTING_FROM_EMAIL => $this->get_setting( self::SETTING_FROM_EMAIL, '' ),
self::SETTING_FORCE_FROM_EMAIL => $this->get_setting( self::SETTING_FORCE_FROM_EMAIL, false ),
self::SETTING_FROM_NAME => $this->get_setting( self::SETTING_FROM_NAME, '' ),
self::SETTING_FORCE_FROM_NAME => $this->get_setting( self::SETTING_FORCE_FROM_NAME, false ),
self::SETTING_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_REPLY_TO_EMAIL, '' ),
self::SETTING_FORCE_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_FORCE_REPLY_TO_EMAIL, false ),
);
}
/**
* Settings fields.
*
* @since 1.0
*
* @return array
*/
public function settings_fields() {
return array(
'title' => esc_html__( 'MailerSend Settings', 'gravitysmtp' ),
'description' => '',
'fields' => array_merge(
array(
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Configuration', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => array( 4, 0, 4, 0 ),
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'API Key', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'helpTextAttributes' => array(
'asHtml' => true,
/* translators: 1: opening anchor tag, 2: closing anchor tag */
'content' => sprintf( __( 'To generate an API key from MailerSend, log in to your MailerSend dashboard and navigate to the Domain section. %1$sCreate a new domain%2$s and then %3$sgenerate your API token%2$s.', 'gravitysmtp' ), '<a class="gform-link gform-typography--size-text-xs" href="https://app.mailersend.com/domains" target="_blank" rel="noopener noreferrer">', '</a>', '<a class="gform-link gform-typography--size-text-xs" href="https://www.mailersend.com/help/managing-api-tokens" target="_blank" rel="noopener noreferrer">' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'name' => self::SETTING_API_KEY,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_API_KEY, '' ),
),
),
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'General Settings', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => 4,
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
),
$this->get_from_settings_fields(),
$this->get_reply_to_settings_fields(),
),
);
}
/**
* Determine if the API credentials are configured correctly.
*
* @since 1.0
*
* @return bool|\WP_Error Returns true if configured, or a WP_Error object if not.
*/
public function is_configured() {
$valid_api = $this->verify_api_key();
if ( is_wp_error( $valid_api ) ) {
self::$configured = $valid_api;
return $valid_api;
}
self::$configured = true;
return true;
}
/**
* Verify the API key with the API.
*
* @since 1.0
*
* @return true|\WP_Error
*/
private function verify_api_key() {
$api_key = $this->get_setting( self::SETTING_API_KEY );
$url = $this->url . '/api-quota';
if ( empty( $api_key ) ) {
return new \WP_Error( 'missing_api_key', __( 'No API Key provided.', 'gravitysmtp' ) );
}
$response = wp_remote_get(
$url,
array(
'headers' => $this->get_request_headers( $api_key ),
)
);
if ( wp_remote_retrieve_response_code( $response ) != '200' ) {
return new \WP_Error( 'invalid_api_key', __( 'Invalid API Key provided.', 'gravitysmtp' ) );
}
return true;
}
/**
* Get the unique data for this connector, merged with the default/common data for all
* connectors in the system.
*
* @since 1.0
*
* @return array
*/
protected function get_merged_data() {
$data = parent::get_merged_data();
$data['disabled'] = ! Feature_Flag_Manager::is_enabled( 'mailersend_integration' );
return $data;
}
}
@@ -0,0 +1,603 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Types;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Base;
/**
* Connector for Mailgun
*
* @since 1.0
*/
class Connector_Mailgun extends Connector_Base {
const SETTING_API_KEY = 'api_key';
const SETTING_REGION = 'region';
const SETTING_DOMAIN = 'domain';
const SETTING_USE_RETURN_PATH = 'use_return_path';
const OPTION_REGION_US = 'us';
const OPTION_REGION_EU = 'eu';
const API_URL_US = 'https://api.mailgun.net/v3/';
const API_URL_EU = 'https://api.eu.mailgun.net/v3/';
protected $name = 'mailgun';
protected $title = 'Mailgun';
protected $disabled = true;
protected $description = '';
protected $logo = 'Mailgun';
protected $full_logo = 'MailgunFull';
public function get_description() {
return esc_html__( 'Mailgun is a transactional email service that provides industry-leading reliability, compliance, and speed. Offering a 30-day trial, Mailguns premium service starts at $35 a month, which allows you to send up to 50,000 emails. For more information on how to get started with Mailgun, read our documentation.', 'gravitysmtp' );
}
protected $sensitive_fields = array(
self::SETTING_API_KEY,
);
/**
* Sending logic.
*
* @since 1.0
*
* @return bool
*/
public function send() {
try {
$atts = $this->get_send_atts();
$source = $this->get_att( 'source' );
$params = $this->get_request_params();
$email = $this->email;
$this->set_email_log_data( $atts['subject'], $atts['message'], $atts['to'], $atts['from'], $atts['headers'], $atts['attachments'], $source, $params );
$this->logger->log( $email, 'started', __( 'Starting email send for Mailgun connector.', 'gravitysmtp' ) );
if ( $this->is_test_mode() ) {
$this->events->update( array( 'status' => 'sandboxed' ), $email );
$this->logger->log( $email, 'sandboxed', __( 'Email sandboxed.', 'gravitysmtp' ) );
return true;
}
$response = wp_safe_remote_post( $this->get_api_url(), $params );
if ( is_wp_error( $response ) ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $response->get_error_message() );
return $email;
}
$response_body = wp_remote_retrieve_body( $response );
$response_code = wp_remote_retrieve_response_code( $response );
if ( (int) $response_code !== 200 ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $response_body );
return $email;
}
$this->events->update( array( 'status' => 'sent' ), $email );
$this->logger->log( $email, 'sent', __( 'Email successfully sent.', 'gravitysmtp' ) );
return true;
} catch ( \Exception $e ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $e->getMessage() );
return false;
}
}
/**
* Get the request parameters for sending email through connector.
*
* @since 1.0
*
* @return array
*/
public function get_request_params() {
$atts = $this->get_send_atts();
$api_key = $this->get_setting( self::SETTING_API_KEY );
if ( ! empty( $atts['headers']['content-type'] ) && strpos( $atts['headers']['content-type'], 'text/html' ) !== false ) {
$content_type = 'text/html';
} else {
$content_type = 'text/plain';
}
$content_type = $this->get_att( 'content_type', $content_type );
$body = [
'from' => $atts['from'],
'subject' => $atts['subject'],
'h:Content-Type' => $content_type
];
if ( ! empty( $atts['reply_to'] ) ) {
$body['h:Reply-To'] = $atts['reply_to'];
}
unset( $atts['headers']['reply-to'] );
if ( $content_type === 'text/html' ) {
$body['html'] = $atts['message'];
} else {
$body['text'] = $atts['message'];
}
$cc = isset( $atts['headers']['cc'] ) ? $atts['headers']['cc']->as_string( true ) : '';
$bcc = isset( $atts['headers']['bcc'] ) ? $atts['headers']['bcc']->as_string( true ) : '';
$recipients = array(
'to' => $atts['to']->as_string( true ),
'cc' => $cc,
'bcc' => $bcc,
);
$body = array_merge( $body, array_filter( $recipients ) );
foreach ( $this->get_filtered_message_headers() as $key => $value ) {
$header_key = sprintf( 'h:%s', $key );
if ( isset( $body[ $header_key ] ) ) {
continue;
}
$body[ $header_key ] = $value;
}
if ( (bool) $this->get_setting( self::SETTING_USE_RETURN_PATH, false ) ) {
$body['sender'] = $atts['from'];
}
$params = [
'body' => $body,
'headers' => $this->get_request_headers( $api_key )
];
if ( ! empty( $atts['attachments'] ) ) {
$params = $this->get_attachments( $params, $atts['attachments'] );
}
return $params;
}
/**
* Get the attributes for sending email.
*
* @since 1.0
*
* @return array
*/
protected function get_send_atts() {
return array(
'to' => $this->get_att( 'to', array() ),
'subject' => $this->get_att( 'subject', '' ),
'message' => $this->get_att( 'message', '' ),
'headers' => $this->get_parsed_headers( $this->get_att( 'headers', array() ) ),
'attachments' => $this->get_att( 'attachments', array() ),
'from' => $this->get_from(),
'reply_to' => $this->get_reply_to(),
);
}
/**
* Get the correct API URL based on region, and include the domain for requests.
*
* @since 1.0
*
* @return string
*/
protected function get_api_url( $endpoint = 'messages', $include_domain = true ) {
$region = $this->get_setting( self::SETTING_REGION, self::OPTION_REGION_US );
$url = $region === self::OPTION_REGION_US ? self::API_URL_US : self::API_URL_EU;
if ( $include_domain ) {
$url .= $this->get_setting( self::SETTING_DOMAIN, '' ) . '/';
}
$url .= $endpoint;
return sanitize_text_field( $url );
}
/**
* Get attachments for this email.
*
* @since 1.0
*
* @param $params
* @param $attachments
*
* @return array
*/
protected function get_attachments( $params, $attachments ) {
$data = array();
$payload = '';
foreach ( $attachments as $custom_name => $attachment ) {
$file = false;
try {
if ( is_file( $attachment ) && is_readable( $attachment ) ) {
$fileName = is_numeric( $custom_name ) ? basename( $attachment ) : $custom_name;
$file = file_get_contents( $attachment );
}
} 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;
}
/**
* Get the common headers for making the API request (with API keys).
*
* @since 1.0
*
* @return string[]
*/
protected function get_request_headers( $api_key ) {
return array(
'Authorization' => 'Basic ' . base64_encode( 'api:' . $api_key )
);
}
/**
* Connector data.
*
* @since 1.0
*
* @return array
*/
public function connector_data() {
return array(
self::SETTING_API_KEY => $this->get_setting( self::SETTING_API_KEY, '' ),
self::SETTING_FROM_EMAIL => $this->get_setting( self::SETTING_FROM_EMAIL, '' ),
self::SETTING_FORCE_FROM_EMAIL => $this->get_setting( self::SETTING_FORCE_FROM_EMAIL, false ),
self::SETTING_FROM_NAME => $this->get_setting( self::SETTING_FROM_NAME, '' ),
self::SETTING_FORCE_FROM_NAME => $this->get_setting( self::SETTING_FORCE_FROM_NAME, false ),
self::SETTING_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_REPLY_TO_EMAIL, '' ),
self::SETTING_FORCE_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_FORCE_REPLY_TO_EMAIL, false ),
self::SETTING_REGION => $this->get_setting( self::SETTING_REGION, self::OPTION_REGION_US ),
self::SETTING_DOMAIN => $this->get_setting( self::SETTING_DOMAIN, '' ),
self::SETTING_USE_RETURN_PATH => (bool) $this->get_setting( self::SETTING_USE_RETURN_PATH, false ),
);
}
/**
* Settings fields.
*
* @since 1.0
*
* @return array
*/
public function settings_fields() {
return array(
'title' => esc_html__( 'Mailgun Settings', 'gravitysmtp' ),
'description' => '',
'fields' => array_merge(
array(
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Configuration', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => [ 4, 0, 4, 0 ],
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'Mailgun API Key', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'helpTextAttributes' => array(
'asHtml' => true,
/* translators: 1: opening anchor tag, 2: closing anchor tag */
'content' => sprintf( __( 'To obtain a %1$sMailgun API Key%2$s, please navigate to the \'Mailgun API Keys\' and generate a key.', 'gravitysmtp' ), '<a class="gform-link gform-typography--size-text-xs" href="https://app.mailgun.com/settings/api_security" target="_blank" rel="noopener noreferrer">', '</a>' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'name' => self::SETTING_API_KEY,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_API_KEY, '' ),
),
),
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'General Settings', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => 4,
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
array(
'component' => 'Toggle',
'props' => array(
'helpTextAttributes' => array(
'content' => esc_html__( 'If Return Path is enabled this adds the return path to the email header which indicates where non-deliverable notifications should be sent. Bounce messages may be lost if not enabled.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
'spacing' => [ 2, 0, 0, 0 ],
),
'helpTextWidth' => 'full',
'initialChecked' => (bool) $this->get_setting( self::SETTING_USE_RETURN_PATH, false ),
'labelAttributes' => array(
'label' => esc_html__( 'Return Path', 'gravitysmtp' ),
),
'labelPosition' => 'left',
'name' => self::SETTING_USE_RETURN_PATH,
'size' => 'size-m',
'spacing' => 5,
'width' => 'full',
),
),
array(
'component' => 'Box',
'props' => array(
'display' => 'block',
'spacing' => 6,
),
'fields' => array(
array(
'component' => 'Label',
'props' => array(
'label' => __( 'Region', 'gravitysmtp' ),
'weight' => 'medium',
'size' => 'text-sm',
'spacing' => 2,
),
),
array(
'component' => 'InputGroup',
'props' => array(
'customAttributes' => array(
'style' => array(
'display' => 'flex',
),
),
'id' => self::SETTING_REGION . '_group',
'initialValue' => $this->get_setting( self::SETTING_REGION, self::OPTION_REGION_US ),
'inputType' => 'radio',
'spacing' => 2,
'data' => array(
array(
'id' => self::SETTING_REGION . '_' . self::OPTION_REGION_US,
'name' => self::SETTING_REGION,
'value' => self::OPTION_REGION_US,
'size' => 'size-md',
'spacing' => array( 0, 4, 0, 0 ),
'labelAttributes' => array(
'label' => __( 'US', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'regular',
),
),
array(
'id' => self::SETTING_REGION . '_' . self::OPTION_REGION_EU,
'name' => self::SETTING_REGION,
'value' => self::OPTION_REGION_EU,
'size' => 'size-md',
'spacing' => array( 0, 4, 0, 0 ),
'labelAttributes' => array(
'label' => __( 'EU', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'regular',
),
),
),
),
),
array(
'component' => 'Text',
'props' => array(
'asHtml' => true,
/* translators: 1: opening anchor tag, 2: closing anchor tag */
'content' => sprintf( __( 'Choose your message sending endpoint. If subject to EU regulations, consider the EU region. For more information, visit %1$sMailgun.com%2$s.', 'gravitysmtp' ), '<a class="gform-link gform-typography--size-text-xs" href="https://www.mailgun.com/regions" target="_blank" rel="noopener noreferrer">', '</a>' ),
'size' => 'text-xs',
'weight' => 'regular',
),
),
),
),
),
$this->get_from_settings_fields(),
$this->get_reply_to_settings_fields(),
array(
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'Sending Domain', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'helpTextAttributes' => array(
'asHtml' => true,
/* translators: 1: opening anchor tag, 2: closing anchor tag */
'content' => sprintf( __( 'Verify your Mailgun domain name. %1$sView domains%2$s.', 'gravitysmtp' ), '<a class="gform-link gform-typography--size-text-xs" href="https://login.mailgun.com/login" target="_blank" rel="noopener noreferrer">', '</a>' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'name' => self::SETTING_DOMAIN,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_DOMAIN, '' ),
),
),
),
),
);
}
public function migration_map() {
return array(
array(
'original_key' => 'gravityformsaddon_gravityformsmailgun_settings',
'sub_key' => 'apiKey',
'new_key' => self::SETTING_API_KEY,
),
array(
'original_key' => 'gravityformsaddon_gravityformsmailgun_settings',
'sub_key' => 'region',
'new_key' => self::SETTING_REGION,
)
);
}
/**
* Verify the API key with the API.
*
* @since 1.0
*
* @return true|\WP_Error
*/
private function verify_api_key() {
$api_key = $this->get_setting( self::SETTING_API_KEY );
$url = $this->get_api_url( 'messages', true );
if ( empty( $api_key ) ) {
return new \WP_Error( 'missing_api_key', __( 'No API Key provided.', 'gravitysmtp' ) );
}
$data = array(
'headers' => $this->get_request_headers( $api_key ),
'body' => array(
"from" => "string",
"to" => "string",
"subject" => "string",
"html" => "string",
),
);
$request = wp_remote_post( $url, $data );
$code = wp_remote_retrieve_response_code( $request );
if ( (int) $code === 401 ) {
return new \WP_Error( 'invalid_api_key', __( 'Invalid API Key provided.', 'gravitysmtp' ) );
}
return true;
}
/**
* Verify the sending domain with the API.
*
* @since 1.0
*
* @return true|\WP_Error
*/
private function verify_domain() {
$api_key = $this->get_setting( self::SETTING_API_KEY );
$url = $this->get_api_url( 'domains/' . $this->get_setting( self::SETTING_DOMAIN ), false );
$data = array(
'headers' => $this->get_request_headers( $api_key ),
);
$result = wp_remote_get( $url, $data );
if ( wp_remote_retrieve_response_code( $result ) == '404' ) {
return new \WP_Error( 'invalid_domain', __( 'Invalid sending domain provided.', 'gravitysmtp' ) );
}
return true;
}
/**
* Determine if the API credentials are configured correctly.
*
* @since 1.0
*
* @return bool|\WP_Error
*/
public function is_configured() {
$valid_api = $this->verify_api_key();
if ( is_wp_error( $valid_api ) ) {
self::$configured = $valid_api;
return $valid_api;
}
$valid_domain = $this->verify_domain();
if ( is_wp_error( $valid_domain ) ) {
self::$configured = $valid_domain;
return $valid_domain;
}
self::$configured = true;
return true;
}
}
@@ -0,0 +1,435 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Types;
use Exception;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Base;
use Gravity_Forms\Gravity_SMTP\Feature_Flags\Feature_Flag_Manager;
use WP_Error;
/**
* Connector for Mailjet
*
* @since 1.0
*/
class Connector_Mailjet extends Connector_Base {
const SETTING_API_KEY = 'api_key';
const SETTING_API_SECRET = 'api_secret';
protected $name = 'mailjet';
protected $title = 'Mailjet';
protected $disabled = true;
protected $logo = 'Mailjet';
protected $full_logo = 'MailjetFull';
protected $url = 'https://api.mailjet.com/v3.1';
protected $sensitive_fields = array(
self::SETTING_API_KEY,
self::SETTING_API_SECRET,
);
public function get_description() {
return esc_html__( 'Mailjet is a powerful transactional email system built for developers but designed so non-tech teams can contribute without coding.', 'gravitysmtp' );
}
/**
* Sends email via Mailjet.
*
* @since 1.0
*
* @return int returns the email ID
*/
public function send() {
try {
$atts = $this->get_send_atts();
$source = $this->get_att( 'source' );
$params = $this->get_request_params();
$email = $this->email;
$this->set_email_log_data( $atts['subject'], $atts['message'], $atts['to'], $atts['from']['from'], $atts['headers'], $atts['attachments'], $source, $params );
$this->logger->log( $email, 'started', __( 'Starting email send for Mailjet connector.', 'gravitysmtp' ) );
if ( $this->is_test_mode() ) {
$this->events->update( array( 'status' => 'sandboxed' ), $email );
$this->logger->log( $email, 'sandboxed', __( 'Email sandboxed.', 'gravitysmtp' ) );
return true;
}
$response = wp_safe_remote_post( $this->url . '/send', $params );
$is_success = in_array( (int) wp_remote_retrieve_response_code( $response ), array( 200, 201, 202 ) );
if ( ! $is_success ) {
$this->log_failure( $email, wp_remote_retrieve_body( $response ) );
return $email;
}
$this->events->update( array( 'status' => 'sent' ), $email );
$this->logger->log( $email, 'sent', __( 'Email successfully sent.', 'gravitysmtp' ) );
return true;
} catch ( Exception $e ) {
$this->log_failure( $email, $e->getMessage() );
return $email;
}
}
/**
* Get the request parameters for sending email through connector.
*
* @since 1.0
*
* @return array
*/
public function get_request_params() {
$atts = $this->get_send_atts();
$api_key = $this->get_setting( self::SETTING_API_KEY );
$api_secret = $this->get_setting( self::SETTING_API_SECRET );
$message = array(
'To' => array(),
'From' => array(
'Email' => $atts['from']['email'],
'Name' => $atts['from']['name'],
),
'Subject' => $atts['subject'],
);
foreach ( $atts['to']->as_array() as $recipient ) {
$to_value = array(
'Email' => $recipient['email'],
);
if ( ! empty( $recipient['name'] ) ) {
$to_value['Name'] = $recipient['name'];
}
$message['To'][] = $to_value;
}
// Setting content
$is_html = ! empty( $atts['headers']['content-type'] ) && strpos( $atts['headers']['content-type'], 'text/html' ) !== false;
if ( $is_html ) {
$message['HTMLPart'] = $atts['message'];
// Strip tags from plaintext
$text_body = wp_strip_all_tags( $atts['message'] );
// Remove leftover double-linebreaks from plaintext.
$text_body = preg_replace( "/([\r\n]{2,}|[\n]{2,}|[\r]{2,}|[\r\t]{2,}|[\n\t]{2,})/", "\n", $text_body );
$message['TextPart'] = $text_body;
} else {
$message['TextPart'] = $atts['message'];
}
// Setting cc
if ( ! empty( $atts['headers']['cc'] ) ) {
$message['Cc'] = array();
foreach ( $atts['headers']['cc']->as_array() as $cc_value ) {
$values = array(
'Email' => $cc_value['email'],
'Name' => ! empty( $cc_value['name'] ) ? $cc_value['name'] : null,
);
$message['Cc'][] = array_filter( $values );
}
}
// Setting Bcc
if ( ! empty( $atts['headers']['bcc'] ) ) {
$message['Bcc'] = array();
foreach ( $atts['headers']['bcc']->as_array() as $bcc_value ) {
$values = array(
'Email' => $bcc_value['email'],
'Name' => ! empty( $bcc_value['name'] ) ? $bcc_value['name'] : null,
);
$message['Bcc'][] = array_filter( $values );
}
}
// Setting reply to
if ( ! empty( $atts['reply_to'] ) ) {
if ( isset( $atts['reply_to']['email'] ) ) {
$reply_to = $atts['reply_to'];
} else {
$reply_to = $atts['reply_to'][0];
}
$message['Headers'] = array();
$message['Headers']['Reply-To'] = $reply_to['email'];
}
// Setting attachments
if ( ! empty( $atts['attachments'] ) ) {
$message['attachments'] = $this->get_attachments( $atts['attachments'] );
}
$body = array(
'Messages' => array(
$message,
),
);
return array(
'body' => json_encode( $body ),
'headers' => $this->get_request_headers( $api_key, $api_secret ),
);
}
/**
* Get the attributes for sending email.
*
* @since 1.0
*
* @return array
*/
protected function get_send_atts() {
$headers = $this->get_parsed_headers( $this->get_att( 'headers', array() ) );
if ( ! empty( $headers['content-type'] ) ) {
$headers['content-type'] = $this->get_att( 'content_type', $headers['content-type'] );
}
return array(
'to' => $this->get_att( 'to', '' ),
'subject' => $this->get_att( 'subject', '' ),
'message' => $this->get_att( 'message', '' ),
'headers' => $headers,
'attachments' => $this->get_att( 'attachments', array() ),
'from' => $this->get_from( true ),
'reply_to' => $this->get_reply_to( true ),
);
}
/**
* Gets a list of attachments, and returns them in a format that can be used by the API.
*
* @param array $attachments the list of attachments
*
* @since 1.0
*
* @return array Returns an array of attachments. Each item with a 'content' and 'name' property.
*/
protected function get_attachments( $attachments ) {
$data = array();
foreach ( $attachments as $custom_name => $attachment ) {
try {
if ( is_file( $attachment ) && is_readable( $attachment ) ) {
$fileName = is_numeric( $custom_name ) ? basename( $attachment ) : $custom_name;
$content = base64_encode( file_get_contents( $attachment ) );
$data[] = array(
'Filename' => $fileName,
'Base64Content' => $content,
'ContentType' => mime_content_type( $attachment ),
);
}
} catch ( Exception $e ) {
continue;
}
}
return $data;
}
/**
* Gets the headers to be used in the API request.
*
* @since 1.0
*
* @return array returns the header array to be passed to Mailjet's API
*/
protected function get_request_headers( $api_key, $api_secret ) {
return array(
'content-type' => 'application/json',
'accept' => 'application/json',
'Authorization' => 'Basic ' . base64_encode( $api_key . ':' . $api_secret ),
);
}
/**
* Logs an email send failure.
*
* @since 1.0
*
* @param string $email the email that failed
* @param string $error_message the error message
*/
private function log_failure( $email, $error_message ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $error_message );
}
/**
* Connector data.
*
* @since 1.0
*
* @return array
*/
public function connector_data() {
return array(
self::SETTING_API_KEY => $this->get_setting( self::SETTING_API_KEY, '' ),
self::SETTING_API_SECRET => $this->get_setting( self::SETTING_API_SECRET, '' ),
self::SETTING_FROM_EMAIL => $this->get_setting( self::SETTING_FROM_EMAIL, '' ),
self::SETTING_FORCE_FROM_EMAIL => $this->get_setting( self::SETTING_FORCE_FROM_EMAIL, false ),
self::SETTING_FROM_NAME => $this->get_setting( self::SETTING_FROM_NAME, '' ),
self::SETTING_FORCE_FROM_NAME => $this->get_setting( self::SETTING_FORCE_FROM_NAME, false ),
self::SETTING_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_REPLY_TO_EMAIL, '' ),
self::SETTING_FORCE_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_FORCE_REPLY_TO_EMAIL, false ),
);
}
/**
* Settings fields.
*
* @since 1.0
*
* @return array
*/
public function settings_fields() {
return array(
'title' => esc_html__( 'Mailjet Settings', 'gravitysmtp' ),
'description' => '',
'fields' => array_merge(
array(
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Configuration', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => array( 4, 0, 4, 0 ),
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'API Key', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'helpTextAttributes' => array(
'asHtml' => true,
/* translators: 1: opening anchor tag, 2: closing anchor tag */
'content' => sprintf( __( 'To generate an API key from Mailjet, log in to your Mailjet dashboard and navigate to the API section and then %1$sgenerate your API key%2$s.', 'gravitysmtp' ), '<a class="gform-link gform-typography--size-text-xs" href="https://app.mailjet.com/account/apikeys" target="_blank" rel="noopener noreferrer">', '</a>' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'name' => self::SETTING_API_KEY,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_API_KEY, '' ),
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'API Secret Key', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'name' => self::SETTING_API_SECRET,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_API_SECRET, '' ),
),
),
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'General Settings', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => 4,
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
),
$this->get_from_settings_fields(),
$this->get_reply_to_settings_fields(),
),
);
}
/**
* Determine if the API credentials are configured correctly.
*
* @since 1.0
*
* @return bool|WP_Error returns true if configured, or a WP_Error object if not
*/
public function is_configured() {
$valid_api = $this->verify_api_key();
if ( is_wp_error( $valid_api ) ) {
self::$configured = $valid_api;
return $valid_api;
}
self::$configured = true;
return true;
}
/**
* Verify the API key with the API.
*
* @since 1.0
*
* @return true|WP_Error
*/
private function verify_api_key() {
$api_key = $this->get_setting( self::SETTING_API_KEY, '' );
$api_secret = $this->get_setting( self::SETTING_API_SECRET, '' );
$url = 'https://api.mailjet.com/v3/REST/geostatistics';
if ( empty( $api_key ) || empty( $api_secret ) ) {
return new WP_Error( 'missing_api_key', __( 'No API Key or Secret provided.', 'gravitysmtp' ) );
}
$response = wp_remote_get(
$url,
array(
'headers' => $this->get_request_headers( $api_key, $api_secret ),
)
);
if ( wp_remote_retrieve_response_code( $response ) != '200' ) {
return new WP_Error( 'invalid_api_key', __( 'Invalid API Key provided.', 'gravitysmtp' ) );
}
return true;
}
/**
* Get the unique data for this connector, merged with the default/common data for all
* connectors in the system.
*
* @since 1.0
*
* @return array
*/
protected function get_merged_data() {
$data = parent::get_merged_data();
$data['disabled'] = ! Feature_Flag_Manager::is_enabled( 'mailjet_integration' );
return $data;
}
}
@@ -0,0 +1,545 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Types;
use Exception;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Base;
use Gravity_Forms\Gravity_SMTP\Feature_Flags\Feature_Flag_Manager;
use WP_Error;
/**
* Connector for Mailtrap
*
* @since 1.9.5
*/
class Connector_Mailtrap extends Connector_Base {
const SETTING_API_KEY = 'api_key';
const SETTING_SANDBOX_ENABLED = 'sandbox_enabled';
const SETTING_INBOX_ID = 'inbox_id';
protected $name = 'mailtrap';
protected $title = 'Mailtrap';
protected $disabled = true;
protected $logo = 'Mailtrap';
protected $full_logo = 'MailtrapFull';
protected $sensitive_fields = array(
self::SETTING_API_KEY,
);
/**
* Get the description for this connector.
*
* @since 1.9.5
*
* @return string
*/
public function get_description() {
return esc_html__( 'Mailtrap is an email delivery platform for businesses and individuals to test, send, and control email infrastructure in one place.', 'gravitysmtp' );
}
/**
* Sends email via Mailtrap.
*
* @since 1.9.5
*
* @return bool|int Returns true on success, or the email ID on failure.
*/
public function send() {
try {
$atts = $this->get_send_atts();
$source = $this->get_att( 'source' );
$params = $this->get_request_params();
$email = $this->email;
$this->set_email_log_data( $atts['subject'], $atts['message'], $atts['to'], $atts['from']['from'], $atts['headers'], $atts['attachments'], $source, $params );
$this->logger->log( $email, 'started', __( 'Starting email send for Mailtrap connector.', 'gravitysmtp' ) );
if ( $this->is_test_mode() ) {
$this->events->update( array( 'status' => 'sandboxed' ), $email );
$this->logger->log( $email, 'sandboxed', __( 'Email sandboxed.', 'gravitysmtp' ) );
return true;
}
$url = $this->get_send_url();
$response = wp_safe_remote_post( $url, $params );
$response_code = (int) wp_remote_retrieve_response_code( $response );
$is_success = in_array( $response_code, array( 200, 201, 202 ) );
if ( ! $is_success ) {
$body = wp_remote_retrieve_body( $response );
$error_message = $this->get_api_error_message( $response_code, $body );
$this->log_failure( $email, $error_message );
return $email;
}
$this->events->update( array( 'status' => 'sent' ), $email );
$this->logger->log( $email, 'sent', __( 'Email successfully sent.', 'gravitysmtp' ) );
return true;
} catch ( Exception $e ) {
$this->log_failure( $email, $e->getMessage() );
return $email;
}
}
/**
* Get the URL to send email to, switching between transactional and sandbox endpoints.
*
* @since 1.9.5
*
* @return string
*/
private function get_send_url() {
$sandbox_enabled = (bool) $this->get_setting( self::SETTING_SANDBOX_ENABLED, false );
if ( $sandbox_enabled ) {
$inbox_id = absint( $this->get_setting( self::SETTING_INBOX_ID, '' ) );
// Sandbox endpoint requires the inbox ID in the URL path.
return sprintf( 'https://sandbox.api.mailtrap.io/api/send/%d', $inbox_id );
}
return 'https://send.api.mailtrap.io/api/send';
}
/**
* Get the request parameters for sending email through connector.
*
* @since 1.9.5
*
* @return array
*/
public function get_request_params() {
$atts = $this->get_send_atts();
$api_key = $this->get_setting( self::SETTING_API_KEY );
$body = array(
'from' => array(
'email' => $atts['from']['email'],
'name' => isset( $atts['from']['name'] ) ? $atts['from']['name'] : '',
),
'subject' => $atts['subject'],
);
// Build to recipients as array of objects.
$to_value = array();
foreach ( $atts['to']->as_array() as $recipient ) {
$to_entry = array( 'email' => $recipient['email'] );
if ( ! empty( $recipient['name'] ) ) {
$to_entry['name'] = $recipient['name'];
}
$to_value[] = $to_entry;
}
$body['to'] = $to_value;
// Set content — Mailtrap accepts both html and text fields.
$is_html = ! empty( $atts['headers']['content-type'] ) && strpos( $atts['headers']['content-type'], 'text/html' ) !== false;
if ( $is_html ) {
$body['html'] = $atts['message'];
// Strip tags for plain text fallback.
$text_body = wp_strip_all_tags( $atts['message'] );
// Remove leftover double-linebreaks from plaintext.
$text_body = preg_replace( "/([\r\n]{2,}|[\n]{2,}|[\r]{2,}|[\r\t]{2,}|[\n\t]{2,})/", "\n", $text_body );
$body['text'] = $text_body;
} else {
$body['text'] = $atts['message'];
}
// CC recipients.
if ( ! empty( $atts['headers']['cc'] ) ) {
$cc_value = array();
foreach ( $atts['headers']['cc']->as_array() as $cc_recipient ) {
$cc_entry = array( 'email' => $cc_recipient['email'] );
if ( ! empty( $cc_recipient['name'] ) ) {
$cc_entry['name'] = $cc_recipient['name'];
}
$cc_value[] = $cc_entry;
}
$body['cc'] = $cc_value;
}
// BCC recipients.
if ( ! empty( $atts['headers']['bcc'] ) ) {
$bcc_value = array();
foreach ( $atts['headers']['bcc']->as_array() as $bcc_recipient ) {
$bcc_entry = array( 'email' => $bcc_recipient['email'] );
if ( ! empty( $bcc_recipient['name'] ) ) {
$bcc_entry['name'] = $bcc_recipient['name'];
}
$bcc_value[] = $bcc_entry;
}
$body['bcc'] = $bcc_value;
}
// Reply-to.
if ( ! empty( $atts['reply_to'] ) ) {
if ( isset( $atts['reply_to']['email'] ) ) {
$reply_to = $atts['reply_to'];
} else {
$reply_to = $atts['reply_to'][0];
}
$reply_to_entry = array( 'email' => $reply_to['email'] );
if ( ! empty( $reply_to['name'] ) ) {
$reply_to_entry['name'] = $reply_to['name'];
}
$body['reply_to'] = $reply_to_entry;
}
// Attachments.
if ( ! empty( $atts['attachments'] ) ) {
$body['attachments'] = $this->get_attachments( $atts['attachments'] );
}
return array(
'body' => json_encode( $body ),
'headers' => $this->get_request_headers( $api_key ),
);
}
/**
* Get the attributes for sending email.
*
* @since 1.9.5
*
* @return array
*/
protected function get_send_atts() {
$headers = $this->get_parsed_headers( $this->get_att( 'headers', array() ) );
if ( ! empty( $headers['content-type'] ) ) {
$headers['content-type'] = $this->get_att( 'content_type', $headers['content-type'] );
}
return array(
'to' => $this->get_att( 'to', '' ),
'subject' => $this->get_att( 'subject', '' ),
'message' => $this->get_att( 'message', '' ),
'headers' => $headers,
'attachments' => $this->get_att( 'attachments', array() ),
'from' => $this->get_from( true ),
'reply_to' => $this->get_reply_to( true ),
);
}
/**
* Gets a list of attachments formatted for the Mailtrap API.
*
* @since 1.9.5
*
* @param array $attachments The list of attachments.
*
* @return array Returns an array of attachments with filename, content, type, and disposition.
*/
protected function get_attachments( $attachments ) {
$data = array();
foreach ( $attachments as $custom_name => $attachment ) {
try {
if ( is_file( $attachment ) && is_readable( $attachment ) ) {
$file_name = is_numeric( $custom_name ) ? basename( $attachment ) : $custom_name;
$content = base64_encode( file_get_contents( $attachment ) );
$mime_type = mime_content_type( $attachment );
$data[] = array(
'filename' => $file_name,
'content' => $content,
'type' => $mime_type,
'disposition' => 'attachment',
);
}
} catch ( Exception $e ) {
continue;
}
}
return $data;
}
/**
* Gets the headers to be used in the API request.
*
* @since 1.9.5
*
* @param string $api_key The Mailtrap API token.
*
* @return array Returns the header array to be passed to Mailtrap's API.
*/
protected function get_request_headers( $api_key ) {
return array(
'Content-Type' => 'application/json',
'Api-Token' => $api_key,
);
}
/**
* Logs an email send failure.
*
* @since 1.9.5
*
* @param string $email The email log ID.
* @param string $error_message The error message.
*/
private function log_failure( $email, $error_message ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $error_message );
}
/**
* Parses an API error response into a human-readable message.
*
* @since 1.9.5
*
* @param int $response_code The HTTP response code.
* @param string $body The raw response body.
*
* @return string The error message.
*/
private function get_api_error_message( $response_code, $body ) {
// Rate limit exceeded — surface a clear message so admins know to wait.
if ( $response_code === 429 ) {
return __( 'Mailtrap rate limit exceeded. Please wait before sending again.', 'gravitysmtp' );
}
$decoded = json_decode( $body, true );
if ( ! empty( $decoded['errors'] ) && is_array( $decoded['errors'] ) ) {
return implode( ' ', $decoded['errors'] );
}
return $body;
}
/**
* Connector data.
*
* @since 1.9.5
*
* @return array
*/
public function connector_data() {
return array(
self::SETTING_API_KEY => $this->get_setting( self::SETTING_API_KEY, '' ),
self::SETTING_SANDBOX_ENABLED => $this->get_setting( self::SETTING_SANDBOX_ENABLED, false ),
self::SETTING_INBOX_ID => $this->get_setting( self::SETTING_INBOX_ID, '' ),
self::SETTING_FROM_EMAIL => $this->get_setting( self::SETTING_FROM_EMAIL, '' ),
self::SETTING_FORCE_FROM_EMAIL => $this->get_setting( self::SETTING_FORCE_FROM_EMAIL, false ),
self::SETTING_FROM_NAME => $this->get_setting( self::SETTING_FROM_NAME, '' ),
self::SETTING_FORCE_FROM_NAME => $this->get_setting( self::SETTING_FORCE_FROM_NAME, false ),
self::SETTING_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_REPLY_TO_EMAIL, '' ),
self::SETTING_FORCE_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_FORCE_REPLY_TO_EMAIL, false ),
);
}
/**
* Settings fields.
*
* @since 1.9.5
*
* @return array
*/
public function settings_fields() {
$sandbox_enabled = (bool) $this->get_setting( self::SETTING_SANDBOX_ENABLED, false );
$fields = array(
'title' => esc_html__( 'Mailtrap Settings', 'gravitysmtp' ),
'description' => '',
'fields' => array_merge(
array(
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Configuration', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => array( 4, 0, 4, 0 ),
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'API Token', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'helpTextAttributes' => array(
'asHtml' => true,
/* translators: 1: opening anchor tag, 2: closing anchor tag */
'content' => sprintf( __( 'To obtain an API token from Mailtrap, log in to your %1$sMailtrap dashboard%2$s and navigate to API Tokens under your account settings.', 'gravitysmtp' ), '<a class="gform-link gform-typography--size-text-xs" href="https://mailtrap.io/api-tokens" target="_blank" rel="noopener noreferrer">', '</a>' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'name' => self::SETTING_API_KEY,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_API_KEY, '' ),
),
),
array(
'component' => 'Toggle',
'props' => array(
'helpTextAttributes' => array(
'content' => esc_html__( 'When enabled, emails are sent to your Mailtrap sandbox inbox instead of real recipients. Requires a Sandbox Inbox ID.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'initialChecked' => $sandbox_enabled,
'labelAttributes' => array(
'label' => esc_html__( 'Enable Sandbox Mode', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'labelPosition' => 'left',
'name' => self::SETTING_SANDBOX_ENABLED,
'size' => 'size-m',
'spacing' => 6,
'width' => 'full',
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'Sandbox Inbox ID', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'helpTextAttributes' => array(
'asHtml' => true,
/* translators: 1: opening anchor tag, 2: closing anchor tag */
'content' => sprintf( __( 'Enter the numeric Inbox ID from your %1$sMailtrap sandbox%2$s. Required when Sandbox Mode is enabled.', 'gravitysmtp' ), '<a class="gform-link gform-typography--size-text-xs" href="https://mailtrap.io/sandboxes" target="_blank" rel="noopener noreferrer">', '</a>' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'name' => self::SETTING_INBOX_ID,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_INBOX_ID, '' ),
),
),
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'General Settings', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => 4,
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
),
$this->get_from_settings_fields(),
$this->get_reply_to_settings_fields(),
),
);
return $fields;
}
/**
* Determine if the API credentials are configured correctly.
*
* @since 1.9.5
*
* @return bool|WP_Error Returns true if configured, or a WP_Error object if not.
*/
public function is_configured() {
$sandbox_enabled = (bool) $this->get_setting( self::SETTING_SANDBOX_ENABLED, false );
// When sandbox mode is on, inbox_id is required for sending to work.
if ( $sandbox_enabled ) {
$inbox_id = $this->get_setting( self::SETTING_INBOX_ID, '' );
if ( empty( $inbox_id ) ) {
$error = new WP_Error( 'missing_inbox_id', __( 'Sandbox Inbox ID is required when Sandbox Mode is enabled.', 'gravitysmtp' ) );
self::$configured = $error;
return $error;
}
}
$valid_api = $this->verify_api_key();
if ( is_wp_error( $valid_api ) ) {
self::$configured = $valid_api;
return $valid_api;
}
self::$configured = true;
return true;
}
/**
* Verify the API token with the Mailtrap accounts endpoint.
*
* @since 1.9.5
*
* @return true|WP_Error
*/
private function verify_api_key() {
$api_key = $this->get_setting( self::SETTING_API_KEY, '' );
if ( empty( $api_key ) ) {
return new WP_Error( 'missing_api_key', __( 'No API Token provided.', 'gravitysmtp' ) );
}
$response = wp_remote_get(
'https://mailtrap.io/api/accounts',
array(
'headers' => $this->get_request_headers( $api_key ),
)
);
if ( wp_remote_retrieve_response_code( $response ) != '200' ) {
return new WP_Error( 'invalid_api_key', __( 'Invalid API Token provided.', 'gravitysmtp' ) );
}
return true;
}
/**
* Get the unique data for this connector, merged with the default/common data for all
* connectors in the system.
*
* @since 1.9.5
*
* @return array
*/
protected function get_merged_data() {
$data = parent::get_merged_data();
$data['disabled'] = ! Feature_Flag_Manager::is_enabled( 'mailtrap_integration' );
return $data;
}
}
@@ -0,0 +1,634 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Types;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Base;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Connectors\Oauth\Google_Oauth_Handler;
use Gravity_Forms\Gravity_SMTP\Connectors\Oauth\Microsoft_Oauth_Handler;
use Gravity_Forms\Gravity_SMTP\Gravity_SMTP;
use Gravity_Forms\Gravity_SMTP\Utils\Booliesh;
/**
* Connector for 365 / Outlook
*
* @since 1.0
*/
class Connector_Microsoft extends Connector_Base {
const SETTING_ACCESS_TOKEN = 'access_token';
const SETTING_CLIENT_ID = 'client_id';
const SETTING_CLIENT_SECRET = 'client_secret';
const SETTING_USE_RETURN_PATH = 'use_return_path';
const VALUE_REDIRECT_URI = 'redirect_uri';
const VALUE_REDIRECT_URI_FULL = 'redirect_uri_full';
protected $name = 'microsoft';
protected $title = 'Microsoft';
protected $disabled = true;
protected $logo = 'Microsoft';
protected $full_logo = 'MicrosoftFull';
public function get_description() {
return __( "Deliver emails with confidence using Microsoft 365 / Outlook. Connect to Microsofts API to securely authenticate and send any emails or form notifications from your website.", 'gravitysmtp' );
}
protected $sensitive_fields = array(
self::SETTING_ACCESS_TOKEN,
self::SETTING_CLIENT_SECRET,
);
/**
* Sending logic.
*
* @since 1.0
*
* @return bool
*/
public function send() {
$to = $this->get_att( 'to', '' );
$subject = $this->get_att( 'subject', '' );
$message = $this->get_att( 'message', '' );
$headers = $this->get_parsed_headers( $this->get_att( 'headers', array() ) );
$attachments = $this->get_att( 'attachments', array() );
$from = $this->get_from( true );
$reply_to = $this->get_reply_to( true );
$source = $this->get_att( 'source' );
$params = $this->get_request_params();
$email = $this->email;
$this->reset_phpmailer();
if ( ! empty( $headers['content-type'] ) ) {
$headers['content-type'] = $this->get_att( 'content_type', $headers['content-type'] );
}
$this->set_email_log_data( $subject, $message, $to, empty( $from['name'] ) ? $from['email'] : sprintf( '%s <%s>', $from['name'], $from['email'] ), $headers, $attachments, $source, $params );
$this->logger->log( $email, 'started', __( 'Starting email send for Microsoft connector.', 'gravitysmtp' ) );
$this->php_mailer->setFrom( $from['email'], isset( $from['name'] ) ? $from['name'] : '' );
foreach ( $to->recipients() as $recipient ) {
if ( ! empty( $recipient->name() ) ) {
$this->php_mailer->addAddress( $recipient->email(), $recipient->name() );
} else {
$this->php_mailer->addAddress( $recipient->email() );
}
}
$this->php_mailer->Subject = $subject;
$this->php_mailer->Body = $message;
if ( ! empty( $headers['cc'] ) ) {
foreach ( $headers['cc']->recipients() as $recipient ) {
if ( ! empty( $recipient->name() ) ) {
$this->php_mailer->addCC( $recipient->email(), $recipient->name() );
} else {
$this->php_mailer->addCC( $recipient->email() );
}
}
}
if ( ! empty( $headers['bcc'] ) ) {
foreach ( $headers['bcc']->recipients() as $recipient ) {
if ( ! empty( $recipient->name() ) ) {
$this->php_mailer->addBCC( $recipient->email(), $recipient->name() );
} else {
$this->php_mailer->addBCC( $recipient->email() );
}
}
}
if ( ! empty( $attachments ) ) {
foreach ( $attachments as $attachment ) {
$this->php_mailer->addAttachment( $attachment );
}
}
if ( ! empty( $reply_to ) ) {
foreach( $reply_to as $address ) {
if ( isset( $address['name'] ) ) {
$this->php_mailer->addReplyTo( $address['email'], $address['name'] );
} else {
$this->php_mailer->addReplyTo( $address['email'] );
}
}
}
if ( ! empty( $headers['content-type'] ) && strpos( $headers['content-type'], 'text/html' ) !== false ) {
$this->php_mailer->isHTML( true );
} else {
$this->php_mailer->isHTML( false );
$this->php_mailer->ContentType = 'text/plain';
}
$this->php_mailer->CharSet = 'UTF-8';
$additional_headers = $this->get_filtered_message_headers();
if ( ! empty( $additional_headers ) ) {
foreach ( $additional_headers as $key => $value ) {
$this->php_mailer->addCustomHeader( $key, $value );
}
}
if ( (bool) $this->get_setting( self::SETTING_USE_RETURN_PATH, false ) ) {
$this->php_mailer->Sender = $this->php_mailer->From;
}
if ( $this->is_test_mode() ) {
$this->events->update( array( 'status' => 'sandboxed' ), $email );
$this->logger->log( $email, 'sandboxed', __( 'Email sandboxed.', 'gravitysmtp' ) );
return true;
}
try {
$debug_atts = compact( 'to', 'from', 'subject', 'headers', 'source', 'attachments', 'reply_to' );
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Attempting send with the following attributes: ' . json_encode( $debug_atts ) ) );
$raw = $this->get_raw_message();
/**
* @var Microsoft_Oauth_Handler $oauth_handler
*/
$oauth_handler = Gravity_SMTP::container()->get( Connector_Service_Provider::MICROSOFT_OAUTH_HANDLER );
$token = $oauth_handler->get_access_token();
if ( is_wp_error( $token ) ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $token->get_error_message() );
return $email;
}
$args = array(
'body' => $raw,
'headers' => array(
'content-type' => 'text/plain',
'Authorization' => 'Bearer ' . $token,
),
);
$request = wp_remote_post( 'https://graph.microsoft.com/v1.0/me/sendMail', $args );
$code = wp_remote_retrieve_response_code( $request );
if ( (int) $code === 202 ) {
$this->events->update( array( 'status' => 'sent' ), $email );
$this->logger->log( $email, 'sent', __( 'Email successfully sent.', 'gravitysmtp' ) );
return true;
}
$this->log_failure( $email, wp_remote_retrieve_body( $request ) );
return $email;
} catch ( \Exception $e ) {
$this->log_failure( $email, $e->getMessage() );
$this->debug_logger->log_fatal( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Failed to send: ' . $e->getMessage() ) );
return $email;
}
}
private function log_failure( $email, $message ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $message );
}
private function get_raw_message() {
$this->php_mailer->preSend();
$raw = $this->php_mailer->getSentMIMEMessage();
return base64_encode( $raw );
}
/**
* Connector data.
*
* @since 1.0
*
* @return array
*/
public function connector_data() {
return array(
self::SETTING_CLIENT_ID => $this->get_setting( self::SETTING_CLIENT_ID, '' ),
self::SETTING_CLIENT_SECRET => $this->get_setting( self::SETTING_CLIENT_SECRET, '' ),
self::SETTING_ACCESS_TOKEN => $this->get_setting( self::SETTING_ACCESS_TOKEN, '' ),
self::SETTING_FROM_EMAIL => $this->get_setting( self::SETTING_FROM_EMAIL, '' ),
self::SETTING_FORCE_FROM_EMAIL => $this->get_setting( self::SETTING_FORCE_FROM_EMAIL, false ),
self::SETTING_FROM_NAME => $this->get_setting( self::SETTING_FROM_NAME, '' ),
self::SETTING_FORCE_FROM_NAME => $this->get_setting( self::SETTING_FORCE_FROM_NAME, false ),
self::SETTING_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_REPLY_TO_EMAIL, '' ),
self::SETTING_FORCE_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_FORCE_REPLY_TO_EMAIL, false ),
self::SETTING_USE_RETURN_PATH => (bool) $this->get_setting( self::SETTING_USE_RETURN_PATH, false ),
'oauth_url' => 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
'oauth_params' => '&' . $this->get_oauth_params(),
);
}
protected function get_oauth_params() {
/**
* @var Microsoft_Oauth_Handler $oauth_handler
*/
$oauth_handler = Gravity_SMTP::container()->get( Connector_Service_Provider::MICROSOFT_OAUTH_HANDLER );
$params = array(
'response_type' => 'code',
'redirect_uri' => urldecode( $oauth_handler->get_return_url() ),
'response_mode' => 'query',
'scope' => $oauth_handler->get_scope(),
'state' => 1,
);
return http_build_query( $params );
}
/**
* Settings fields.
*
* @since 1.0
*
* @return array
*/
public function settings_fields() {
/**
* @var Microsoft_Oauth_Handler $oauth_handler
*/
$oauth_handler = Gravity_SMTP::container()->get( Connector_Service_Provider::MICROSOFT_OAUTH_HANDLER );
$oauth_handler->handle_response( $this->name );
$token = $oauth_handler->get_access_token( $this->name );
$has_token = $token && ! is_wp_error( $token );
$settings = array(
'title' => esc_html__( '365 / Outlook Settings', 'gravitysmtp' ),
'hide_save' => ( ! $has_token ),
'fields' => array(),
);
if ( ! $token || is_wp_error( $token ) ) {
$settings['fields'][] = array(
'component' => 'Alert',
'props' => array(
'customIconPrefix' => 'gravity-admin-icon',
'theme' => 'cosmos',
'type' => 'notice',
'spacing' => 3,
),
'fields' => array(
array(
'component' => 'Text',
'props' => array(
'content' => esc_html__( 'Please click the button below to initiate a connection with your Microsoft account. Remember to fill out both the Client ID and Client Secret fields before proceeding.', 'gravitysmtp' ),
'customClasses' => array( 'gform--display-block', 'gravitysmtp-integration__notice-message' ),
'size' => 'text-sm',
'spacing' => 4,
'tagName' => 'span',
),
),
array(
'component' => 'Link',
'props' => array(
'content' => esc_html__( 'Read our Microsoft 365 / Outlook documentation', 'gravitysmtp' ),
'customClasses' => array(
'gform-link--theme-cosmos',
'gravitysmtp-integration__notice-link',
'gform-button',
'gform-button--size-height-m',
'gform-button--white',
'gform-button--width-auto'
),
'href' => 'https://docs.gravitysmtp.com/category/integrations/microsoft/',
'target' => '_blank',
),
),
),
);
}
if ( isset( $_GET['code'] ) && ! $has_token ) {
$settings['fields'][] = array(
'component' => 'Alert',
'props' => array(
'customIconPrefix' => 'gravity-admin-icon',
'theme' => 'cosmos',
'type' => 'error',
'spacing' => 3,
),
'fields' => array(
array(
'component' => 'Text',
'props' => array(
'content' => esc_html__( 'Error Connecting to Microsoft. Check your credentials and try again.', 'gravitysmtp' ),
'weight' => 'medium',
'size' => 'text-sm',
'spacing' => 2,
'tagName' => 'span',
),
),
),
);
}
$settings['fields'][] = array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Configuration', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => [ 4, 0, 3, 0 ],
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
);
if ( ! $token || is_wp_error( $token ) ) {
$settings['fields'][] = array(
'component' => 'LinkedHelpTextInput',
'external' => true,
'handle_change' => true,
'links' => array(
array(
'key' => 'link',
'props' => array(
'href' => 'https://portal.azure.com/',
'size' => 'text-xs',
'target' => '_blank',
),
),
),
'props' => array(
'helpTextAttributes' => array(
'content' => esc_html__( 'To obtain an Application ID from 365 / Outlook, login to your {{link}}Microsoft Azure{{link}} dashboard and generate an Application ID.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'labelAttributes' => array(
'label' => esc_html__( 'Application ID', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'name' => self::SETTING_CLIENT_ID,
'spacing' => 4,
'size' => 'size-l',
'value' => $this->get_setting( self::SETTING_CLIENT_ID, '' ),
),
);
$settings['fields'][] = array(
'component' => 'LinkedHelpTextInput',
'external' => true,
'handle_change' => true,
'links' => array(
array(
'key' => 'link',
'props' => array(
'href' => 'https://portal.azure.com/',
'size' => 'text-xs',
'target' => '_blank',
),
),
),
'props' => array(
'helpTextAttributes' => array(
'content' => esc_html__( 'To obtain a Client Secret password, log in to your {{link}}Microsoft Azure{{link}} dashboard and generate a new client secret. Then, copy the secret value (not the secret ID) into this field.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'labelAttributes' => array(
'label' => esc_html__( 'Client Secret', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'name' => self::SETTING_CLIENT_SECRET,
'spacing' => 6,
'size' => 'size-l',
'value' => $this->get_setting( self::SETTING_CLIENT_SECRET, '' ),
),
);
$settings['fields'][] = array(
'component' => 'CopyInput',
'external' => true,
'props' => array(
'actionButtonAttributes' => array(
'customAttributes' => array(
'type' => 'button',
),
'icon' => 'copy',
'iconPrefix' => 'gravity-admin-icon',
'label' => esc_html__( 'Copy', 'gravitysmtp' ),
),
'labelAttributes' => array(
'label' => esc_html__( 'Redirect URI (Personal Accounts)', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'name' => self::VALUE_REDIRECT_URI,
'spacing' => 6,
'size' => 'size-l',
'customAttributes' => array(
'readOnly' => true,
),
'value' => urldecode( $oauth_handler->get_return_url( 'copy' ) ),
'helpTextAttributes' => array(
'content' => esc_html__( 'If your app is set up to support Personal Accounts, copy this URL and enter it as a Redirect URI in your App Settings.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
),
),
);
$settings['fields'][] = array(
'component' => 'CopyInput',
'external' => true,
'props' => array(
'actionButtonAttributes' => array(
'customAttributes' => array(
'type' => 'button',
),
'icon' => 'copy',
'iconPrefix' => 'gravity-admin-icon',
'label' => esc_html__( 'Copy', 'gravitysmtp' ),
),
'labelAttributes' => array(
'label' => esc_html__( 'Redirect URI (School or Work Accounts)', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'name' => self::VALUE_REDIRECT_URI_FULL,
'spacing' => 6,
'size' => 'size-l',
'customAttributes' => array(
'readOnly' => true,
),
'value' => urldecode( $oauth_handler->get_return_url( 'settings' ) ),
'helpTextAttributes' => array(
'content' => esc_html__( 'If your app is set up to support School and Work accounts, copy this URL and enter it as a Redirect URI in your App Settings.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
),
),
);
$settings['fields'][] = array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Authorization', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => [ 4, 0, 3, 0 ],
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
);
$settings['fields'][] = array(
'component' => 'BrandedButton',
'external' => true,
'props' => array(
'label' => esc_html__( 'Sign in with Microsoft', 'gravitysmtp' ),
'spacing' => 6,
'Svg' => 'MicrosoftAltLogo',
'type' => 'color',
),
);
} else {
$settings['fields'][] = array(
'component' => 'Box',
'props' => array(
'customClasses' => array( 'gravitysmtp-google-integration__connected-message' ),
'display' => 'flex',
'spacing' => 3,
),
'fields' => array(
array(
'component' => 'Icon',
'props' => array(
'customClasses' => array(
'gravitysmtp-google-integration__checkmark',
'gform-icon--preset-active',
'gform-icon-preset--status-correct',
'gform-alert__icon'
),
'icon' => 'checkmark-simple',
'iconPrefix' => 'gravity-admin-icon',
),
),
array(
'component' => 'Text',
'props' => array(
'asHtml' => true,
'content' => sprintf(
'%s <span class="gform-text gform-text--color-port gform-typography--size-text-sm gform-typography--weight-medium">%s</span>',
esc_html__( 'Connected with email account:', 'gravitysmtp' ),
esc_html( $oauth_handler->get_connection_details()['email'] )
),
'size' => 'text-sm',
'tagName' => 'span',
),
),
),
);
$disconnect_url = add_query_arg( '_wpnonce', wp_create_nonce( 'gsmtp_disconnect_microsoft' ), admin_url( 'admin-post.php?action=smtp_disconnect_microsoft' ) );
$settings['fields'][] = array(
'component' => 'Text',
'props' => array(
'content' => sprintf( '<a href="%s" class="%s"><span class="gravity-admin-icon gravity-admin-icon--x-circle gform-button__icon"></span>%s</a>', $disconnect_url, 'gform-link gform-link--theme-cosmos gform-button gform-button--size-height-m gform-button--white gform-button--width-auto gform-button--active-type-loader gform-button--loader-after gform-button--icon-leading', __( 'Disconnect from Microsoft', 'gravitysmtp' ) ),
'asHtml' => true,
'spacing' => 6,
),
);
$settings['fields'][] = array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Configuration', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => [ 4, 0, 4, 0 ],
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
);
$settings['fields'][] = array(
'component' => 'Toggle',
'props' => array(
'helpTextAttributes' => array(
'content' => esc_html__( 'If Return Path is enabled this adds the return path to the email header which indicates where non-deliverable notifications should be sent. Bounce messages may be lost if not enabled.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
'spacing' => [ 2, 0, 0, 0 ],
),
'helpTextWidth' => 'full',
'initialChecked' => (bool) $this->get_setting( self::SETTING_USE_RETURN_PATH, false ),
'labelAttributes' => array(
'label' => esc_html__( 'Return Path', 'gravitysmtp' ),
),
'labelPosition' => 'left',
'name' => self::SETTING_USE_RETURN_PATH,
'size' => 'size-m',
'spacing' => 5,
'width' => 'full',
),
);
$settings['fields'] = array_merge( $settings['fields'], $this->get_from_settings_fields(), $this->get_reply_to_settings_fields() );
}
return $settings;
}
protected function get_from_settings_fields() {
$fields = parent::get_from_settings_fields();
$fields[2]['component'] = 'Text';
$fields[2]['props']['size'] = 'text-sm';
$fields[2]['props']['weight'] = 'medium';
$fields[2]['props']['content'] = esc_html__( 'Force From Name', 'gravitysmtp' );
$fields[2]['props']['spacing'] = '2';
$fields[3]['component'] = 'Text';
$fields[3]['props']['content'] = esc_html__( 'Microsoft automatically forces the From Name associated with the From Email configured within their system.', 'gravitysmtp' );
return $fields;
}
public function is_configured() {
if ( Booliesh::get( $this->get_setting( 'access_token', false ) ) ) {
/**
* @var Microsoft_Oauth_Handler $oauth_handler
*/
$oauth_handler = Gravity_SMTP::container()->get( Connector_Service_Provider::MICROSOFT_OAUTH_HANDLER );
$token = $oauth_handler->get_access_token();
return $token;
}
return false;
}
/**
* Reset the PHPMailer instance to prevent carryover from previous send.
*
* @since 1.0
*
* @return void
*/
private function reset_phpmailer() {
$this->php_mailer->clearCustomHeaders();
$this->php_mailer->clearAddresses();
$this->php_mailer->clearBCCs();
$this->php_mailer->clearCCs();
$this->php_mailer->clearAllRecipients();
$this->php_mailer->clearReplyTos();
$this->php_mailer->clearAttachments();
}
}
@@ -0,0 +1,331 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Types;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Base;
use Gravity_Forms\Gravity_SMTP\Utils\Recipient;
/**
* Connector for Generic/Custom SMTP integration.
*
* @since 1.0
*/
class Connector_Phpmail extends Connector_Base {
const SETTING_USE_RETURN_PATH = 'use_return_path';
protected $name = 'phpmail';
protected $title = 'PHP Mail';
protected $disabled = false;
protected $description = '';
protected $logo = 'PHP';
protected $full_logo = 'PHPFull';
public function get_description() {
return __( "Use your server's default PHP Mailer to send email.", 'gravitysmtp' );
}
public function send() {
$to = $this->get_att( 'to', '' );
$subject = $this->get_att( 'subject', '' );
$message = $this->get_att( 'message', '' );
$headers = $this->get_parsed_headers( $this->get_att( 'headers', array() ) );
$attachments = $this->get_att( 'attachments', array() );
$from = $this->get_from( true );
$reply_to = $this->get_reply_to( true );
$source = $this->get_att( 'source' );
$params = $this->get_request_params();
$email = $this->email;
$this->reset_phpmailer();
if ( ! empty( $headers['content-type'] ) ) {
$headers['content-type'] = $this->get_att( 'content_type', $headers['content-type'] );
}
$this->set_email_log_data( $subject, $message, $to, empty( $from['name'] ) ? $from['email'] : sprintf( '%s <%s>', $from['name'], $from['email'] ), $headers, $attachments, $source, $params );
$this->logger->log( $email, 'started', __( 'Starting email send for PHPMail connector.', 'gravitysmtp' ) );
$this->php_mailer->setFrom( $from['email'], empty( $from['name'] ) ? '' : $from['name'] );
foreach( $to->recipients() as $recipient ) {
if ( ! empty( $recipient->name() ) ) {
$this->php_mailer->addAddress( $recipient->email(), $recipient->name() );
} else {
$this->php_mailer->addAddress( $recipient->email() );
}
}
$this->php_mailer->Subject = $subject;
$this->php_mailer->Body = $message;
if ( ! empty( $headers['cc'] ) ) {
foreach ( $headers['cc']->recipients() as $recipient ) {
if ( ! empty( $recipient->name() ) ) {
$this->php_mailer->addCC( $recipient->email(), $recipient->name() );
} else {
$this->php_mailer->addCC( $recipient->email() );
}
}
}
if ( ! empty( $headers['bcc'] ) ) {
foreach ( $headers['bcc']->recipients() as $recipient ) {
if ( ! empty( $recipient->name() ) ) {
$this->php_mailer->addBCC( $recipient->email(), $recipient->name() );
} else {
$this->php_mailer->addBCC( $recipient->email() );
}
}
}
if ( ! empty( $attachments ) ) {
foreach ( $attachments as $attachment ) {
$this->php_mailer->addAttachment( $attachment );
}
}
if ( ! empty( $reply_to ) ) {
foreach( $reply_to as $address ) {
if ( isset( $address['name'] ) ) {
$this->php_mailer->addReplyTo( $address['email'], $address['name'] );
} else {
$this->php_mailer->addReplyTo( $address['email'] );
}
}
}
if ( ! empty( $headers['content-type'] ) && strpos( $headers['content-type'], 'text/html' ) !== false ) {
$this->php_mailer->isHTML( true );
} else {
$this->php_mailer->isHTML( false );
$this->php_mailer->ContentType = 'text/plain';
}
$this->php_mailer->CharSet = 'UTF-8';
$additional_headers = $this->get_filtered_message_headers();
if ( ! empty( $additional_headers ) ) {
foreach ( $additional_headers as $key => $value ) {
$this->php_mailer->addCustomHeader( $key, $value );
}
}
if ( (bool) $this->get_setting( self::SETTING_USE_RETURN_PATH, false ) ) {
$this->php_mailer->Sender = $this->php_mailer->From;
}
if ( $this->is_test_mode() ) {
$this->events->update( array( 'status' => 'sandboxed' ), $email );
$this->logger->log( $email, 'sandboxed', __( 'Email sandboxed.', 'gravitysmtp' ) );
return true;
}
/**
* Fires after PHPMailer is initialized.
*
* @since 2.2.0
*
* @param PHPMailer $phpmailer The PHPMailer instance (passed by reference).
*/
do_action_ref_array( 'phpmailer_init', array( &$this->php_mailer ) );
$mail_data = compact( 'to', 'subject', 'message', 'headers', 'attachments' );
// Send!
try {
$debug_atts = compact( 'to', 'from', 'subject', 'headers', 'source', 'attachments', 'reply_to' );
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Attempting send with the following attributes: ' . json_encode( $debug_atts ) ) );
$send = $this->php_mailer->send();
/**
* Fires after PHPMailer has successfully sent an email.
*
* The firing of this action does not necessarily mean that the recipient(s) received the
* email successfully. It only means that the `send` method above was able to
* process the request without any errors.
*
* @since 5.9.0
*
* @param array $mail_data {
* An array containing the email recipient(s), subject, message, headers, and attachments.
*
* @type string[] $to Email addresses to send message.
* @type string $subject Email subject.
* @type string $message Message contents.
* @type string[] $headers Additional headers.
* @type string[] $attachments Paths to files to attach.
* }
*/
do_action( 'wp_mail_succeeded', $mail_data );
$this->events->update( array( 'status' => 'sent' ), $this->email );
$this->logger->log( $this->email, 'sent', __( 'Email successfully sent.', 'gravitysmtp' ) );
return $send;
} catch ( \PHPMailer\PHPMailer\Exception $e ) {
$mail_data['phpmailer_exception_code'] = $e->getCode();
/**
* Fires after a PHPMailer\PHPMailer\Exception is caught.
*
* @since 4.4.0
*
* @param WP_Error $error A WP_Error object with the PHPMailer\PHPMailer\Exception message, and an array
* containing the mail recipient, subject, message, headers, and attachments.
*/
do_action( 'wp_mail_failed', new \WP_Error( 'wp_mail_failed', $e->getMessage(), $mail_data ) );
$this->log_failure( $this->email, $e->getMessage() );
return $this->email;
}
}
/**
* Get the request parameters for sending email through connector.
*
* @since 1.0
*
* @return array
*/
public function get_request_params() {
return array();
}
/**
* Connector data.
*
* @since 1.0
*
* @return array
*/
public function connector_data() {
return array(
self::SETTING_FROM_EMAIL => $this->get_setting( self::SETTING_FROM_EMAIL, '' ),
self::SETTING_FORCE_FROM_EMAIL => $this->get_setting( self::SETTING_FORCE_FROM_EMAIL, false ),
self::SETTING_FROM_NAME => $this->get_setting( self::SETTING_FROM_NAME, '' ),
self::SETTING_FORCE_FROM_NAME => $this->get_setting( self::SETTING_FORCE_FROM_NAME, false ),
self::SETTING_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_REPLY_TO_EMAIL, '' ),
self::SETTING_FORCE_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_FORCE_REPLY_TO_EMAIL, false ),
self::SETTING_USE_RETURN_PATH => (bool) $this->get_setting( self::SETTING_USE_RETURN_PATH, false ),
);
}
/**
* Settings fields.
*
* @since 1.0
*
* @return array
*/
public function settings_fields() {
return array(
'title' => esc_html__( 'PHP Mail Settings', 'gravitysmtp' ),
'description' => '',
'fields' => array_merge(
array(
array(
'component' => 'Alert',
'props' => array(
'customIconPrefix' => 'gravity-admin-icon',
'theme' => 'cosmos',
'type' => 'info',
'spacing' => 5,
),
'fields' => array(
array(
'component' => 'Text',
'props' => array(
'content' => esc_html__( 'When using PHP Mail, emails might not be delivered reliably. For optimal performance, we recommend using a dedicated email provider.', 'gravitysmtp' ),
'size' => 'text-sm',
'tagName' => 'span',
),
),
),
),
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'General Settings', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => 4,
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
array(
'component' => 'Toggle',
'props' => array(
'helpTextAttributes' => array(
'content' => esc_html__( 'If Return Path is enabled this adds the return path to the email header which indicates where non-deliverable notifications should be sent. Bounce messages may be lost if not enabled.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
'spacing' => [ 2, 0, 0, 0 ],
),
'helpTextWidth' => 'full',
'initialChecked' => (bool) $this->get_setting( self::SETTING_USE_RETURN_PATH, false ),
'labelAttributes' => array(
'label' => esc_html__( 'Return Path', 'gravitysmtp' ),
),
'labelPosition' => 'left',
'name' => self::SETTING_USE_RETURN_PATH,
'size' => 'size-m',
'spacing' => 5,
'width' => 'full',
),
),
),
$this->get_from_settings_fields(),
$this->get_reply_to_settings_fields(),
),
);
}
/**
* Determine if the SMTP credentials are configured correctly.
*
* @since 1.0
*
* @return bool|\WP_Error
*/
public function is_configured() {
global $phpmailer;
return ! empty( $phpmailer );
}
/**
* Logs an email send failure.
*
* @since 1.0
*
* @param string $email The email that failed.
* @param string $error_message The error message.
*/
private function log_failure( $email, $error_message ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $error_message );
}
/**
* Reset the PHPMailer instance to prevent carryover from previous send.
*
* @since 1.0
*
* @return void
*/
private function reset_phpmailer() {
$this->php_mailer->clearCustomHeaders();
$this->php_mailer->clearAddresses();
$this->php_mailer->clearBCCs();
$this->php_mailer->clearCCs();
$this->php_mailer->clearAllRecipients();
$this->php_mailer->clearReplyTos();
$this->php_mailer->clearAttachments();
}
}
@@ -0,0 +1,358 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Types;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Base;
class Connector_Postmark extends Connector_Base {
const SETTING_SERVER_API_TOKEN = 'server_api_token';
protected $name = 'postmark';
protected $title = 'Postmark';
protected $description = '';
protected $logo = 'Postmark';
protected $full_logo = 'PostmarkFull';
protected $url = 'https://api.postmarkapp.com/email';
public function get_description() {
return esc_html__( 'Owned by ActiveCampaign, Postmark is a popular email-sending service with an impressive reputation for reliability and deliverability. Postmark offers a free plan that allows you to send up to 100 emails a month. Over 100, prices vary depending on the number of emails sent. For more information on how to get started with Postmark, read our documentation.', 'gravitysmtp' );
}
protected $sensitive_fields = array(
self::SETTING_SERVER_API_TOKEN,
);
/**
* Sending logic.
*
* @since 1.0
*
* @return bool
*/
public function send() {
try {
$atts = $this->get_send_atts();
$source = $this->get_att( 'source' );
$params = $this->get_request_params();
$email = $this->email;
$this->set_email_log_data( $atts['subject'], $atts['message'], $atts['to'], $atts['from'], $atts['headers'], $atts['attachments'], $source, $params );
$this->logger->log( $email, 'started', __( 'Starting email send for Postmark connector.', 'gravitysmtp' ) );
if ( $this->is_test_mode() ) {
$this->events->update( array( 'status' => 'sandboxed' ), $email );
$this->logger->log( $email, 'sandboxed', __( 'Email sandboxed.', 'gravitysmtp' ) );
return true;
}
$response = wp_safe_remote_post( $this->url, $params );
$response_code = (int) wp_remote_retrieve_response_code( $response );
$response_body = wp_remote_retrieve_body( $response );
if ( $response_code !== 200 ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $response_body );
return $email;
}
$this->events->update( array( 'status' => 'sent' ), $email );
$decoded = json_decode( $response_body, true );
$api_message = isset( $decoded['Message'] ) ? trim( $decoded['Message'] ) : '';
if ( ! empty( $api_message ) && strcasecmp( $api_message, 'OK' ) !== 0 ) {
$sent_message = $api_message;
} elseif ( empty( $api_message ) && ! empty( $response_body ) && ! is_array( $decoded ) ) {
$sent_message = substr( $response_body, 0, 500 );
} else {
$sent_message = __( 'Email successfully sent.', 'gravitysmtp' );
}
$this->logger->log( $email, 'sent', $sent_message );
return true;
} catch ( \Exception $e ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $e->getMessage() );
return $email;
}
}
/**
* Get the request parameters for sending email through connector.
*
* @since 1.0
*
* @return array
*/
public function get_request_params() {
$atts = $this->get_send_atts();
$api_key = $this->get_setting( self::SETTING_SERVER_API_TOKEN );
if ( ! empty( $atts['headers']['content-type'] ) && strpos( $atts['headers']['content-type'], 'text/html' ) !== false ) {
$html_body = $atts['message'];
} else {
$html_body = null;
}
$cc = isset( $atts['headers']['cc'] ) ? $atts['headers']['cc']->as_string( false ) : '';
$bcc = isset( $atts['headers']['bcc'] ) ? $atts['headers']['bcc']->as_string( false ) : '';
// Strip tags from plaintext
$text_body = wp_strip_all_tags( $atts['message'] );
// Remove leftover double-linebreaks from plaintext.
$text_body = preg_replace( "/([\r\n]{2,}|[\n]{2,}|[\r]{2,}|[\r\t]{2,}|[\n\t]{2,})/", "\n", $text_body );
$body = array(
'from' => $atts['from'],
'to' => $atts['to']->as_string( false ),
'subject' => $atts['subject'],
'textBody' => $text_body,
'htmlBody' => $html_body,
'Cc' => $cc,
'Bcc' => $bcc,
);
if ( ! empty( $atts['reply_to'] ) ) {
$body['ReplyTo'] = $atts['reply_to'];
}
if ( ! empty( $atts['attachments'] ) ) {
$body['Attachments'] = $this->get_attachments( $atts['attachments'] );
}
$additional_headers = $this->get_filtered_message_headers();
if ( ! empty( $additional_headers ) ) {
$body['Headers'] = array();
foreach ( $additional_headers as $key => $value ) {
$body['Headers'][] = array(
'Name' => $key,
'Value' => $value,
);
}
}
return array(
'body' => json_encode( $body ),
'headers' => $this->get_request_headers( $api_key ),
);
}
/**
* Get the attributes for sending email.
*
* @since 1.0
*
* @return array
*/
protected function get_send_atts() {
$headers = $this->get_parsed_headers( $this->get_att( 'headers', array() ) );
if ( ! empty( $headers['content-type'] ) ) {
$headers['content-type'] = $this->get_att( 'content_type', $headers['content-type'] );
}
return array(
'to' => $this->get_att( 'to', '' ),
'subject' => $this->get_att( 'subject', '' ),
'message' => $this->get_att( 'message', '' ),
'headers' => $headers,
'attachments' => $this->get_att( 'attachments', array() ),
'from' => $this->get_from(),
'reply_to' => $this->get_reply_to(),
);
}
protected function get_request_headers( $api_key ) {
return array(
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'X-Postmark-Server-Token' => $api_key,
);
}
protected function get_attachments( $attachments ) {
$data = array();
foreach ( $attachments as $custom_name => $attachment ) {
$file = false;
try {
if ( is_file( $attachment ) && is_readable( $attachment ) ) {
$fileName = is_numeric( $custom_name ) ? basename( $attachment ) : $custom_name;
$contentId = wp_hash( $attachment );
$file = file_get_contents( $attachment );
$content = base64_encode( file_get_contents( $attachment ) );
$mimeType = mime_content_type( $attachment );
}
} catch ( \Exception $e ) {
$file = false;
}
if ( $file === false ) {
continue;
}
$data[] = array(
'ContentType' => $mimeType,
'Name' => $fileName,
'ContentId' => $contentId,
'Content' => $content,
);
}
return $data;
}
public function connector_data() {
return array(
self::SETTING_SERVER_API_TOKEN => $this->get_setting( self::SETTING_SERVER_API_TOKEN, '' ),
self::SETTING_FROM_EMAIL => $this->get_setting( self::SETTING_FROM_EMAIL, '' ),
self::SETTING_FORCE_FROM_EMAIL => $this->get_setting( self::SETTING_FORCE_FROM_EMAIL, false ),
self::SETTING_FROM_NAME => $this->get_setting( self::SETTING_FROM_NAME, '' ),
self::SETTING_FORCE_FROM_NAME => $this->get_setting( self::SETTING_FORCE_FROM_NAME, false ),
self::SETTING_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_REPLY_TO_EMAIL, '' ),
self::SETTING_FORCE_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_FORCE_REPLY_TO_EMAIL, false ),
);
}
public function settings_fields() {
return array(
'title' => esc_html__( 'Postmark Settings', 'gravitysmtp' ),
'description' => '',
'fields' => array_merge(
array(
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Configuration', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => [ 4, 0, 4, 0 ],
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
// array(
// 'component' => 'Toggle',
// 'props' => array(
// 'initialChecked' => (bool) $this->get_plugin_setting( 'primary' ) === $this->name,
// 'labelAttributes' => array(
// 'label' => esc_html__( 'If enabled, Postmark will be the default SMTP mailer.', 'gravitysmtp' ),
// ),
// 'labelPosition' => 'left',
// 'name' => 'default-mailer',
// 'size' => 'size-m',
// 'spacing' => 5,
// 'width' => 'full',
// ),
// ),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'Server API Token', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'helpTextAttributes' => array(
'asHtml' => true,
/* translators: 1: opening anchor tag, 2: closing anchor tag */
'content' => sprintf( __( 'To get a Server API Token, go to the %1$sAPI Token%2$s tab on your Postmark account page.', 'gravitysmtp' ), '<a class="gform-link gform-typography--size-text-xs" href="https://account.postmarkapp.com/api_tokens" target="_blank" rel="noopener noreferrer">', '</a>' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'name' => self::SETTING_SERVER_API_TOKEN,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_SERVER_API_TOKEN, '' ),
),
),
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'General Settings', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => 4,
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
),
$this->get_from_settings_fields(),
$this->get_reply_to_settings_fields(),
),
);
}
public function migration_map() {
return array(
array(
'original_key' => 'gravityformsaddon_gravityformspostmark_settings',
'sub_key' => 'serverToken',
'new_key' => self::SETTING_SERVER_API_TOKEN,
),
);
}
/**
* Verify the API key with the API.
*
* @since 1.0
*
* @return true|\WP_Error
*/
private function verify_api_key() {
$api_key = $this->get_setting( self::SETTING_SERVER_API_TOKEN );
$url = str_replace( 'email', 'server', $this->url );
if ( empty( $api_key ) ) {
return new \WP_Error( 'missing_api_key', __( 'No API Key provided.', 'gravitysmtp' ) );
}
$response = wp_remote_get(
$url,
array(
'headers' => $this->get_request_headers( $api_key ),
)
);
if ( wp_remote_retrieve_response_code( $response ) != '200' ) {
return new \WP_Error( 'invalid_api_key', __( 'Invalid API Key provided.', 'gravitysmtp' ) );
}
return true;
}
/**
* Determine if the API credentials are configured correctly.
*
* @since 1.0
*
* @return bool|\WP_Error
*/
public function is_configured() {
$valid_api = $this->verify_api_key();
if ( is_wp_error( $valid_api ) ) {
self::$configured = $valid_api;
return $valid_api;
}
self::$configured = true;
return true;
}
}
@@ -0,0 +1,408 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Types;
use Exception;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Base;
use Gravity_Forms\Gravity_SMTP\Feature_Flags\Feature_Flag_Manager;
use WP_Error;
/**
* Connector for Resend
*
* @since 1.0
*/
class Connector_Resend extends Connector_Base {
const SETTING_API_KEY = 'api_key';
protected $name = 'resend';
protected $title = 'Resend';
protected $disabled = true;
protected $logo = 'Resend';
protected $full_logo = 'ResendFull';
protected $url = 'https://api.resend.com';
protected $sensitive_fields = array(
self::SETTING_API_KEY,
);
public function get_description() {
return esc_html__( 'Email for developers that makes it easy to write, format, and send emails. Deliver transactional and marketing emails at scale.', 'gravitysmtp' );
}
/**
* Sends email via Resend.
*
* @since 1.0
*
* @return int returns the email ID
*/
public function send() {
try {
$atts = $this->get_send_atts();
$source = $this->get_att( 'source' );
$params = $this->get_request_params();
$email = $this->email;
$this->set_email_log_data( $atts['subject'], $atts['message'], $atts['to'], $atts['from']['from'], $atts['headers'], $atts['attachments'], $source, $params );
$this->logger->log( $email, 'started', __( 'Starting email send for Resend connector.', 'gravitysmtp' ) );
if ( $this->is_test_mode() ) {
$this->events->update( array( 'status' => 'sandboxed' ), $email );
$this->logger->log( $email, 'sandboxed', __( 'Email sandboxed.', 'gravitysmtp' ) );
return true;
}
$response = wp_safe_remote_post( $this->url . '/emails', $params );
$is_success = in_array( (int) wp_remote_retrieve_response_code( $response ), array( 200, 201, 202 ) );
if ( ! $is_success ) {
$this->log_failure( $email, wp_remote_retrieve_body( $response ) );
return $email;
}
$this->events->update( array( 'status' => 'sent' ), $email );
$this->logger->log( $email, 'sent', __( 'Email successfully sent.', 'gravitysmtp' ) );
return true;
} catch ( Exception $e ) {
$this->log_failure( $email, $e->getMessage() );
return $email;
}
}
/**
* Get the request parameters for sending email through connector.
*
* @since 1.0
*
* @return array
*/
public function get_request_params() {
$atts = $this->get_send_atts();
$api_key = $this->get_setting( self::SETTING_API_KEY );
$message = array(
'to' => '',
'from' => ! empty( $atts['from']['name'] ) ? sprintf( '%s <%s>', $atts['from']['name'], $atts['from']['email'] ) : $atts['from']['email'],
'subject' => $atts['subject'],
'headers' => array(),
);
$to_value = array();
foreach ( $atts['to']->as_array() as $recipient ) {
if ( ! empty( $recipient['name'] ) ) {
$to_value[] = sprintf( '%s <%s>', $recipient['name'], $recipient['email'] );
} else {
$to_value[] = $recipient['email'];
}
}
$message['to'] = $to_value;
// Setting content
$is_html = ! empty( $atts['headers']['content-type'] ) && strpos( $atts['headers']['content-type'], 'text/html' ) !== false;
if ( $is_html ) {
$message['html'] = $atts['message'];
// Strip tags from plaintext
$text_body = wp_strip_all_tags( $atts['message'] );
// Remove leftover double-linebreaks from plaintext.
$text_body = preg_replace( "/([\r\n]{2,}|[\n]{2,}|[\r]{2,}|[\r\t]{2,}|[\n\t]{2,})/", "\n", $text_body );
$message['text'] = $text_body;
} else {
$message['text'] = $atts['message'];
}
// Setting cc
if ( ! empty( $atts['headers']['cc'] ) ) {
$cc_headers = array();
foreach ( $atts['headers']['cc']->as_array() as $cc_value ) {
$cc_headers[] = ! empty( $cc_value['name'] ) ? sprintf( '%s <%s>', $cc_value['name'], $cc_value['email'] ) : $cc_value['email'];
}
$message['cc'] = $cc_headers;
}
// Setting Bcc
if ( ! empty( $atts['headers']['bcc'] ) ) {
$bcc_headers = array();
foreach ( $atts['headers']['bcc']->as_array() as $bcc_value ) {
$bcc_headers[] = ! empty( $bcc_value['name'] ) ? sprintf( '%s <%s>', $bcc_value['name'], $bcc_value['email'] ) : $bcc_value['email'];
}
$message['bcc'] = $bcc_headers;
}
// Setting reply to
if ( ! empty( $atts['reply_to'] ) ) {
if ( isset( $atts['reply_to']['email'] ) ) {
$reply_to = $atts['reply_to'];
} else {
$reply_to = $atts['reply_to'][0];
}
$message['reply_to'] = $reply_to['email'];
}
// Setting attachments
if ( ! empty( $atts['attachments'] ) ) {
$message['attachments'] = $this->get_attachments( $atts['attachments'] );
}
return array(
'body' => json_encode( $message ),
'headers' => $this->get_request_headers( $api_key ),
);
}
/**
* Get the attributes for sending email.
*
* @since 1.0
*
* @return array
*/
protected function get_send_atts() {
$headers = $this->get_parsed_headers( $this->get_att( 'headers', array() ) );
if ( ! empty( $headers['content-type'] ) ) {
$headers['content-type'] = $this->get_att( 'content_type', $headers['content-type'] );
}
return array(
'to' => $this->get_att( 'to', '' ),
'subject' => $this->get_att( 'subject', '' ),
'message' => $this->get_att( 'message', '' ),
'headers' => $headers,
'attachments' => $this->get_att( 'attachments', array() ),
'from' => $this->get_from( true ),
'reply_to' => $this->get_reply_to( true ),
);
}
/**
* Gets a list of attachments, and returns them in a format that can be used by the API.
*
* @param array $attachments the list of attachments
*
* @since 1.0
*
* @return array Returns an array of attachments. Each item with a 'content' and 'name' property.
*/
protected function get_attachments( $attachments ) {
$data = array();
foreach ( $attachments as $custom_name => $attachment ) {
try {
if ( is_file( $attachment ) && is_readable( $attachment ) ) {
$fileName = is_numeric( $custom_name ) ? basename( $attachment ) : $custom_name;
$content = base64_encode( file_get_contents( $attachment ) );
$data[] = array(
'filename' => $fileName,
'content' => $content,
'content_type' => mime_content_type( $attachment ),
);
}
} catch ( Exception $e ) {
continue;
}
}
return $data;
}
/**
* Gets the headers to be used in the API request.
*
* @since 1.0
*
* @return array returns the header array to be passed to Resend's API
*/
protected function get_request_headers( $api_key ) {
return array(
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $api_key,
);
}
/**
* Logs an email send failure.
*
* @since 1.0
*
* @param string $email the email that failed
* @param string $error_message the error message
*/
private function log_failure( $email, $error_message ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $error_message );
}
/**
* Connector data.
*
* @since 1.0
*
* @return array
*/
public function connector_data() {
return array(
self::SETTING_API_KEY => $this->get_setting( self::SETTING_API_KEY, '' ),
self::SETTING_FROM_EMAIL => $this->get_setting( self::SETTING_FROM_EMAIL, '' ),
self::SETTING_FORCE_FROM_EMAIL => $this->get_setting( self::SETTING_FORCE_FROM_EMAIL, false ),
self::SETTING_FROM_NAME => $this->get_setting( self::SETTING_FROM_NAME, '' ),
self::SETTING_FORCE_FROM_NAME => $this->get_setting( self::SETTING_FORCE_FROM_NAME, false ),
self::SETTING_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_REPLY_TO_EMAIL, '' ),
self::SETTING_FORCE_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_FORCE_REPLY_TO_EMAIL, false ),
);
}
/**
* Settings fields.
*
* @since 1.0
*
* @return array
*/
public function settings_fields() {
return array(
'title' => esc_html__( 'Resend Settings', 'gravitysmtp' ),
'description' => '',
'fields' => array_merge(
array(
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Configuration', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => array( 4, 0, 4, 0 ),
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'API Key', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'helpTextAttributes' => array(
'asHtml' => true,
/* translators: 1: opening anchor tag, 2: closing anchor tag */
'content' => __( 'To generate an API key from Resend, log in to your Resend dashboard and navigate to the Credentials section and then generate your API key.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'name' => self::SETTING_API_KEY,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_API_KEY, '' ),
),
),
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'General Settings', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => 4,
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
),
$this->get_from_settings_fields(),
$this->get_reply_to_settings_fields(),
),
);
}
/**
* Determine if the API credentials are configured correctly.
*
* @since 1.0
*
* @return bool|WP_Error returns true if configured, or a WP_Error object if not
*/
public function is_configured() {
$valid_api = $this->verify_api_key();
if ( is_wp_error( $valid_api ) ) {
self::$configured = $valid_api;
return $valid_api;
}
self::$configured = true;
return true;
}
/**
* Verify the API key with the API.
*
* @since 1.0
*
* @return true|WP_Error
*/
private function verify_api_key() {
$api_key = $this->get_setting( self::SETTING_API_KEY, '' );
$url = $this->url . '/domains';
if ( empty( $api_key ) ) {
return new WP_Error( 'missing_api_key', __( 'No API Key provided.', 'gravitysmtp' ) );
}
$response = wp_remote_get(
$url,
array(
'headers' => $this->get_request_headers( $api_key ),
)
);
$code = wp_remote_retrieve_response_code( $response );
$body = wp_remote_retrieve_body( $response );
// Some API keys are restricted to only sending; we can't verify them until a test send is attempted.
if ( strpos( $body, 'restricted_api_key' ) !== false ) {
return true;
}
if ( wp_remote_retrieve_response_code( $response ) != '200' ) {
return new WP_Error( 'invalid_api_key', __( 'Invalid API Key provided.', 'gravitysmtp' ) );
}
return true;
}
/**
* Get the unique data for this connector, merged with the default/common data for all
* connectors in the system.
*
* @since 1.0
*
* @return array
*/
protected function get_merged_data() {
$data = parent::get_merged_data();
$data['disabled'] = ! Feature_Flag_Manager::is_enabled( 'resend_integration' );
return $data;
}
}
@@ -0,0 +1,453 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Types;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Base;
class Connector_Sendgrid extends Connector_Base {
const SETTING_API_KEY = 'api_key';
const SETTING_REGION = 'region';
const SETTING_IP_POOL_NAME = 'ip_pool_name';
const OPTION_REGION_GLOBAL = 'global';
const OPTION_REGION_EU = 'eu';
const API_URL_GLOBAL = 'https://api.sendgrid.com/v3/mail/send';
const API_URL_EU = 'https://api.eu.sendgrid.com/v3/mail/send';
protected $name = 'sendgrid';
protected $title = 'SendGrid';
protected $description = '';
protected $logo = 'SendGrid';
protected $full_logo = 'SendGridFull';
public function get_description() {
return esc_html__( 'Send at scale with Twilio SendGrid, boasting an industry-leading 99% deliverability rate. SendGrid offers both a free-forever plan of 100 emails a day, and, if you need to exceed that limit, a selection of preset pricing plans, starting at $19.95 per month for up to 50,000 emails. For more information on how to get started with SendGrid, read our documentation.', 'gravitysmtp' );
}
protected $sensitive_fields = array(
self::SETTING_API_KEY,
);
/**
* Get the API URL based on the configured region.
*
* @since 2.2.0
*
* @return string
*/
protected function get_api_url() {
$region = $this->get_setting( self::SETTING_REGION, self::OPTION_REGION_GLOBAL );
return $region === self::OPTION_REGION_EU ? self::API_URL_EU : self::API_URL_GLOBAL;
}
public function send() {
try {
$atts = $this->get_send_atts();
$source = $this->get_att( 'source' );
$params = $this->get_request_params();
$email = $this->email;
$this->set_email_log_data( $atts['subject'], $atts['message'], $atts['to'], empty( $atts['from']['name'] ) ? $atts['from']['email'] : sprintf( '%s <%s>', $atts['from']['name'], $atts['from']['email'] ), $atts['headers'], $atts['attachments'], $source, $params );
$this->logger->log( $email, 'started', __( 'Starting email send for SendGrid connector.', 'gravitysmtp' ) );
if ( $this->is_test_mode() ) {
$this->events->update( array( 'status' => 'sandboxed' ), $email );
$this->logger->log( $email, 'sandboxed', __( 'Email sandboxed.', 'gravitysmtp' ) );
return true;
}
$response = wp_safe_remote_post( $this->get_api_url(), $params );
if ( (int) wp_remote_retrieve_response_code( $response ) > 299 ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', wp_remote_retrieve_body( $response ) );
return $email;
}
$this->events->update( array( 'status' => 'sent' ), $email );
$this->logger->log( $email, 'sent', __( 'Email successfully sent.', 'gravitysmtp' ) );
return true;
} catch ( \Exception $e ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $e->getMessage() );
return $email;
}
}
/**
* Get the request parameters for sending email through connector.
*
* @since 1.0
*
* @return array
*/
public function get_request_params() {
$atts = $this->get_send_atts();
$api_key = $this->get_setting( self::SETTING_API_KEY );
if ( ! empty( $atts['headers']['content-type'] ) && strpos( $atts['headers']['content-type'], 'text/html' ) !== false ) {
$message_type = 'text/html';
} else {
$message_type = 'text/plain';
}
$body = array(
'from' => array( 'email' => $atts['from']['email'], 'name' => $atts['from']['name'] ),
'personalizations' => $this->get_recipients( $atts['to'], $atts['headers'] ),
'subject' => $atts['subject'],
'content' => array(
array(
'value' => $atts['message'],
'type' => $message_type,
),
),
);
if ( ! empty( $atts['reply_to'] ) ) {
$body['reply_to_list'] = $atts['reply_to'];
}
if ( ! empty( $atts['attachments'] ) ) {
$body['attachments'] = $this->get_attachments( $atts['attachments'] );
}
$additional_headers = $this->get_filtered_message_headers();
if ( ! empty( $additional_headers ) ) {
$body['headers'] = $additional_headers;
}
$ip_pool_name = trim( $this->get_setting( self::SETTING_IP_POOL_NAME, '' ) );
if ( ! empty( $ip_pool_name ) ) {
$body['ip_pool_name'] = $ip_pool_name;
}
return array(
'body' => json_encode( $body ),
'headers' => $this->get_request_headers( $api_key ),
);
}
/**
* Get the attributes for sending email.
*
* @since 1.0
*
* @return array
*/
protected function get_send_atts() {
$headers = $this->get_parsed_headers( $this->get_att( 'headers', array() ) );
if ( ! empty( $headers['content-type'] ) ) {
$headers['content-type'] = $this->get_att( 'content_type', $headers['content-type'] );
}
return array(
'to' => $this->get_att( 'to', '' ),
'subject' => $this->get_att( 'subject', '' ),
'message' => $this->get_att( 'message', '' ),
'headers' => $headers,
'attachments' => $this->get_att( 'attachments', array() ),
'from' => $this->get_from( true ),
'reply_to' => $this->get_reply_to( true ),
);
}
protected function get_recipients( $to, $headers ) {
$recipients = array(
'to' => $to->as_array(),
);
if ( ! empty( $headers['cc'] ) ) {
$recipients['cc'] = $headers['cc']->as_array();
}
if ( ! empty( $headers['bcc'] ) ) {
$recipients['bcc'] = $headers['bcc']->as_array();
}
$recipients = array_filter( $recipients );
return array( $recipients );
}
protected function get_request_headers( $api_key ) {
return array(
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $api_key,
);
}
protected function get_attachments( $attachments ) {
$data = array();
foreach ( $attachments as $custom_name => $attachment ) {
$file = false;
try {
if ( is_file( $attachment ) && is_readable( $attachment ) ) {
$fileName = is_numeric( $custom_name ) ? basename( $attachment ) : $custom_name;
$contentId = wp_hash( $attachment );
$file = file_get_contents( $attachment );
$mimeType = mime_content_type( $attachment );
$filetype = str_replace( ';', '', trim( $mimeType ) );
}
} catch ( \Exception $e ) {
$file = false;
}
if ( $file === false ) {
continue;
}
$data[] = array(
'type' => $filetype,
'filename' => $fileName,
'disposition' => 'attachment',
'content_id' => $contentId,
'content' => base64_encode( $file ),
);
}
return $data;
}
public function connector_data() {
return array(
self::SETTING_API_KEY => $this->get_setting( self::SETTING_API_KEY, '' ),
self::SETTING_REGION => $this->get_setting( self::SETTING_REGION, self::OPTION_REGION_GLOBAL ),
self::SETTING_IP_POOL_NAME => $this->get_setting( self::SETTING_IP_POOL_NAME, '' ),
self::SETTING_FROM_EMAIL => $this->get_setting( self::SETTING_FROM_EMAIL, '' ),
self::SETTING_FORCE_FROM_EMAIL => $this->get_setting( self::SETTING_FORCE_FROM_EMAIL, false ),
self::SETTING_FROM_NAME => $this->get_setting( self::SETTING_FROM_NAME, '' ),
self::SETTING_FORCE_FROM_NAME => $this->get_setting( self::SETTING_FORCE_FROM_NAME, false ),
self::SETTING_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_REPLY_TO_EMAIL, '' ),
self::SETTING_FORCE_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_FORCE_REPLY_TO_EMAIL, false ),
);
}
public function settings_fields() {
return array(
'title' => esc_html__( 'SendGrid Settings', 'gravitysmtp' ),
'description' => '',
'fields' => array_merge(
array(
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Configuration', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => [ 4, 0, 4, 0 ],
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'SendGrid API Key', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'helpTextAttributes' => array(
'asHtml' => true,
/* translators: 1: opening anchor tag, 2: closing anchor tag */
'content' => sprintf( __( 'To obtain an API key from SendGrid you will need to %1$sgenerate an API key%2$s. To send emails, the API key only requires \'Mail Send\' access.', 'gravitysmtp' ), '<a class="gform-link gform-typography--size-text-xs" href="https://app.sendgrid.com/settings/api_keys" target="_blank" rel="noopener noreferrer">', '</a>' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'name' => self::SETTING_API_KEY,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_API_KEY, '' ),
),
),
array(
'component' => 'Box',
'props' => array(
'display' => 'block',
'spacing' => 6,
),
'fields' => array(
array(
'component' => 'Label',
'props' => array(
'label' => __( 'Region', 'gravitysmtp' ),
'weight' => 'medium',
'size' => 'text-sm',
'spacing' => 2,
),
),
array(
'component' => 'InputGroup',
'props' => array(
'customAttributes' => array(
'style' => array(
'display' => 'flex',
),
),
'id' => self::SETTING_REGION . '_group',
'initialValue' => $this->get_setting( self::SETTING_REGION, self::OPTION_REGION_GLOBAL ),
'inputType' => 'radio',
'spacing' => 2,
'data' => array(
array(
'id' => self::SETTING_REGION . '_' . self::OPTION_REGION_GLOBAL,
'name' => self::SETTING_REGION,
'value' => self::OPTION_REGION_GLOBAL,
'size' => 'size-md',
'spacing' => array( 0, 4, 0, 0 ),
'labelAttributes' => array(
'label' => __( 'Global', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'regular',
),
),
array(
'id' => self::SETTING_REGION . '_' . self::OPTION_REGION_EU,
'name' => self::SETTING_REGION,
'value' => self::OPTION_REGION_EU,
'size' => 'size-md',
'spacing' => array( 0, 4, 0, 0 ),
'labelAttributes' => array(
'label' => __( 'EU', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'regular',
),
),
),
),
),
array(
'component' => 'Text',
'props' => array(
'asHtml' => true,
/* translators: 1: opening anchor tag, 2: closing anchor tag */
'content' => sprintf( __( 'Choose your SendGrid API region. Select EU for European data residency. Important: the EU region requires an API key created under an EU subuser. For more information, visit %1$sSendGrid Data Residency%2$s.', 'gravitysmtp' ), '<a class="gform-link gform-typography--size-text-xs" href="https://www.twilio.com/docs/sendgrid/data-residency" target="_blank" rel="noopener noreferrer">', '</a>' ),
'size' => 'text-xs',
'weight' => 'regular',
),
),
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'IP Pool Name', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'helpTextAttributes' => array(
'asHtml' => true,
/* translators: 1: opening anchor tag, 2: closing anchor tag */
'content' => sprintf( __( 'Optional. Enter the name of a SendGrid IP pool to route emails through specific IPs (e.g. for EU/GDPR compliance). The pool must already exist in your SendGrid account. For more information, see %1$sSendGrid IP Pools%2$s.', 'gravitysmtp' ), '<a class="gform-link gform-typography--size-text-xs" href="https://docs.sendgrid.com/ui/account-and-settings/ip-pools" target="_blank" rel="noopener noreferrer">', '</a>' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'name' => self::SETTING_IP_POOL_NAME,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_IP_POOL_NAME, '' ),
),
),
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'General Settings', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => 4,
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
),
$this->get_from_settings_fields(),
$this->get_reply_to_settings_fields(),
),
);
}
public function migration_map() {
return array(
array(
'original_key' => 'gravityformsaddon_gravityformssendgrid_settings',
'sub_key' => 'apiKey',
'new_key' => self::SETTING_API_KEY,
),
);
}
/**
* Verify the API key with the API.
*
* @since 1.0
*
* @return true|\WP_Error
*/
private function verify_api_key() {
$api_key = $this->get_setting( self::SETTING_API_KEY );
$url = str_replace( 'mail/send', 'scopes', $this->get_api_url() );
if ( empty( $api_key ) ) {
return new \WP_Error( 'missing_api_key', __( 'No API Key provided.', 'gravitysmtp' ) );
}
$response = wp_remote_get(
$url,
array(
'headers' => $this->get_request_headers( $api_key ),
)
);
$response_code = wp_remote_retrieve_response_code( $response );
if ( $response_code != '200' ) {
return new \WP_Error( 'invalid_api_key', __( 'Invalid API Key provided.', 'gravitysmtp' ) );
}
$scopes = json_decode( wp_remote_retrieve_body( $response ), true );
if ( ! in_array( 'mail.send', $scopes['scopes'] ) ) {
return new \WP_Error( 'insufficient_permissions', __( 'API Key does not have permission to send mail.', 'gravitysmtp' ) );
}
return true;
}
/**
* Determine if the API credentials are configured correctly.
*
* @since 1.0
*
* @return bool|\WP_Error
*/
public function is_configured() {
$valid_api = $this->verify_api_key();
if ( is_wp_error( $valid_api ) ) {
self::$configured = $valid_api;
return $valid_api;
}
self::$configured = true;
return true;
}
}
@@ -0,0 +1,393 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Types;
use Exception;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Base;
use Gravity_Forms\Gravity_SMTP\Feature_Flags\Feature_Flag_Manager;
use WP_Error;
/**
* Connector for SMTP2GO
*
* @since 1.0
*/
class Connector_Smtp2go extends Connector_Base {
const SETTING_API_KEY = 'api_key';
protected $name = 'smtp2go';
protected $title = 'SMTP2GO';
protected $logo = 'SMTP2GO';
protected $full_logo = 'SMTP2GOFull';
protected $url = 'https://api.smtp2go.com/v3/email/send';
protected $sensitive_fields = array(
self::SETTING_API_KEY,
);
public function get_description() {
return esc_html__( 'SMTP2GO is a cloud-based email delivery service that ensures reliable inbox placement with built-in analytics and automatic failover. Offering a free plan and scalable options, SMTP2GO helps businesses send transactional and marketing emails effortlessly.', 'gravitysmtp' );
}
/**
* Sends email via SMTP2GO.
*
* @since 1.0
*
* @return int returns the email ID
*/
public function send() {
try {
$atts = $this->get_send_atts();
$source = $this->get_att( 'source' );
$params = $this->get_request_params();
$email = $this->email;
$this->set_email_log_data( $atts['subject'], $atts['message'], $atts['to'], $atts['from']['from'], $atts['headers'], $atts['attachments'], $source, $params );
$this->logger->log( $email, 'started', __( 'Starting email send for SMTP2GO connector.', 'gravitysmtp' ) );
if ( $this->is_test_mode() ) {
$this->events->update( array( 'status' => 'sandboxed' ), $email );
$this->logger->log( $email, 'sandboxed', __( 'Email sandboxed.', 'gravitysmtp' ) );
return true;
}
$response = wp_safe_remote_post( $this->url, $params );
$is_success = in_array( (int) wp_remote_retrieve_response_code( $response ), array( 200, 201, 202 ) );
if ( ! $is_success ) {
$this->log_failure( $email, wp_remote_retrieve_body( $response ) );
return $email;
}
$this->events->update( array( 'status' => 'sent' ), $email );
$this->logger->log( $email, 'sent', __( 'Email successfully sent.', 'gravitysmtp' ) );
return true;
} catch ( Exception $e ) {
$this->log_failure( $email, $e->getMessage() );
return $email;
}
}
/**
* Get the request parameters for sending email through connector.
*
* @since 1.0
*
* @return array
*/
public function get_request_params() {
$atts = $this->get_send_atts();
$api_key = $this->get_setting( self::SETTING_API_KEY );
$from_value = isset( $atts['from']['name'] )
? sprintf( '"%s" <%s>', iconv_mime_encode( 'From', $atts['from']['name'], array( 'line-length' => apply_filters( 'gravitysmtp_smtp2go_from_name_line_length', 400 ) ) ), $atts['from']['email'] )
: $atts['from']['email'];
$from_value = str_replace( 'From: ', '', $from_value );
$body = array(
'sender' => $from_value,
'subject' => $atts['subject'],
'to' => array(),
);
foreach ( $atts['to']->as_array() as $to_value ) {
$email_value = isset( $to_value['name'] ) ? sprintf( '%s <%s>', $to_value['name'], $to_value['email'] ) : $to_value['email'];
$body['to'][] = $email_value;
}
// Setting content
$is_html = ! empty( $atts['headers']['content-type'] ) && strpos( $atts['headers']['content-type'], 'text/html' ) !== false;
if ( $is_html ) {
$body['html_body'] = $atts['message'];
} else {
$body['text_body'] = $atts['message'];
}
// Setting cc
if ( ! empty( $atts['headers']['cc'] ) ) {
$body['cc'] = array();
foreach ( $atts['headers']['cc']->as_array() as $cc_value ) {
$body['cc'][] = $cc_value['email'];
}
}
// Setting bcc
if ( ! empty( $atts['headers']['bcc'] ) ) {
$body['bcc'] = array();
foreach ( $atts['headers']['bcc']->as_array() as $bcc_value ) {
$body['bcc'][] = $bcc_value['email'];
}
}
$body['custom_headers'] = array();
// Setting reply to
if ( ! empty( $atts['reply_to'] ) ) {
if ( isset( $atts['reply_to']['email'] ) ) {
$reply_to = $atts['reply_to'];
} else {
$reply_to = $atts['reply_to'][0];
}
$body['custom_headers'][] = array(
'header' => 'Reply-To',
'value' => $reply_to['email'],
);
}
// Setting attachments
if ( ! empty( $atts['attachments'] ) ) {
$body['attachments'] = $this->get_attachments( $atts['attachments'] );
}
return array(
'body' => json_encode( $body ),
'headers' => $this->get_request_headers( $api_key ),
'timeout' => 10
);
}
/**
* Get the attributes for sending email.
*
* @since 1.0
*
* @return array
*/
protected function get_send_atts() {
$headers = $this->get_parsed_headers( $this->get_att( 'headers', array() ) );
if ( ! empty( $headers['content-type'] ) ) {
$headers['content-type'] = $this->get_att( 'content_type', $headers['content-type'] );
}
return array(
'to' => $this->get_att( 'to', '' ),
'subject' => $this->get_att( 'subject', '' ),
'message' => $this->get_att( 'message', '' ),
'headers' => $headers,
'attachments' => $this->get_att( 'attachments', array() ),
'from' => $this->get_from( true ),
'reply_to' => $this->get_reply_to( true ),
);
}
/**
* Gets a list of attachments, and returns them in a format that can be used by the API.
*
* @param array $attachments the list of attachments
*
* @since 1.0
*
* @return array Returns an array of attachments. Each item with a 'content' and 'name' property.
*/
protected function get_attachments( $attachments ) {
$data = array();
foreach ( $attachments as $custom_name => $attachment ) {
try {
if ( is_file( $attachment ) && is_readable( $attachment ) ) {
$fileName = is_numeric( $custom_name ) ? basename( $attachment ) : $custom_name;
$content = base64_encode( file_get_contents( $attachment ) );
$data[] = array(
'filename' => $fileName,
'fileblob' => $content,
'mimetype' => mime_content_type( $attachment ),
);
}
} catch ( Exception $e ) {
continue;
}
}
return $data;
}
/**
* Gets the headers to be used in the API request.
*
* @since 1.0
*
* @return array returns the header array to be passed to SMTP2GO's API
*/
protected function get_request_headers( $api_key ) {
return array(
'content-type' => 'application/json',
'accept' => 'application/json',
'X-Smtp2go-Api-Key' => $api_key,
);
}
/**
* Logs an email send failure.
*
* @since 1.0
*
* @param string $email the email that failed
* @param string $error_message the error message
*/
private function log_failure( $email, $error_message ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $error_message );
}
/**
* Connector data.
*
* @since 1.0
*
* @return array
*/
public function connector_data() {
return array(
self::SETTING_API_KEY => $this->get_setting( self::SETTING_API_KEY, '' ),
self::SETTING_FROM_EMAIL => $this->get_setting( self::SETTING_FROM_EMAIL, '' ),
self::SETTING_FORCE_FROM_EMAIL => $this->get_setting( self::SETTING_FORCE_FROM_EMAIL, false ),
self::SETTING_FROM_NAME => $this->get_setting( self::SETTING_FROM_NAME, '' ),
self::SETTING_FORCE_FROM_NAME => $this->get_setting( self::SETTING_FORCE_FROM_NAME, false ),
self::SETTING_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_REPLY_TO_EMAIL, '' ),
self::SETTING_FORCE_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_FORCE_REPLY_TO_EMAIL, false ),
);
}
/**
* Settings fields.
*
* @since 1.0
*
* @return array
*/
public function settings_fields() {
return array(
'title' => esc_html__( 'SMTP2GO Settings', 'gravitysmtp' ),
'description' => '',
'fields' => array_merge(
array(
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Configuration', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => array( 4, 0, 4, 0 ),
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'API Key', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'helpTextAttributes' => array(
'asHtml' => true,
/* translators: 1: opening anchor tag, 2: closing anchor tag */
'content' => sprintf( __( 'To generate an API key from SMTP2GO, log in to your SMTP2GO dashboard and navigate to the API section. %1$sCreate a new API key%2$s and ensure your %3$sverified senders%2$s are configured correctly.', 'gravitysmtp' ), '<a class="gform-link gform-typography--size-text-xs" href="https://docs.gravitysmtp.com/obtaining-your-smtp2go-api-key/" target="_blank" rel="noopener noreferrer">', '</a>', '<a class="gform-link gform-typography--size-text-xs" href="https://docs.gravitysmtp.com/adding-verified-senders-in-smtp2go/" target="_blank" rel="noopener noreferrer">' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'name' => self::SETTING_API_KEY,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_API_KEY, '' ),
),
),
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'General Settings', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => 4,
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
),
$this->get_from_settings_fields(),
$this->get_reply_to_settings_fields(),
),
);
}
/**
* Determine if the API credentials are configured correctly.
*
* @since 1.0
*
* @return bool|WP_Error returns true if configured, or a WP_Error object if not
*/
public function is_configured() {
$valid_api = $this->verify_api_key();
if ( is_wp_error( $valid_api ) ) {
self::$configured = $valid_api;
return $valid_api;
}
self::$configured = true;
return true;
}
/**
* Verify the API key with the API.
*
* @since 1.0
*
* @return true|WP_Error
*/
private function verify_api_key() {
$api_key = $this->get_setting( self::SETTING_API_KEY );
$url = 'https://api.smtp2go.com/v3/stats/email_bounces';
if ( empty( $api_key ) ) {
return new WP_Error( 'missing_api_key', __( 'No API Key provided.', 'gravitysmtp' ) );
}
$response = wp_remote_post(
$url,
array(
'headers' => $this->get_request_headers( $api_key ),
)
);
if ( wp_remote_retrieve_response_code( $response ) != '200' ) {
return new WP_Error( 'invalid_api_key', __( 'Invalid API Key provided.', 'gravitysmtp' ) );
}
return true;
}
/**
* Get the unique data for this connector, merged with the default/common data for all
* connectors in the system.
*
* @since 1.0
*
* @return array
*/
protected function get_merged_data() {
$data = parent::get_merged_data();
$data['disabled'] = ! Feature_Flag_Manager::is_enabled( 'smtp2go_integration' );
return $data;
}
}
@@ -0,0 +1,550 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Types;
use Exception;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Base;
use Gravity_Forms\Gravity_SMTP\Feature_Flags\Feature_Flag_Manager;
use WP_Error;
/**
* Connector for SMTP.com
*
* @since 1.0
*/
class Connector_SMTPCom extends Connector_Base {
const SETTING_API_KEY = 'api_key';
const SETTING_CHANNEL = 'channel';
protected $name = 'smtpcom';
protected $title = 'SMTP.com';
protected $disabled = true;
protected $logo = 'SMTP';
protected $full_logo = 'SMTPFull';
protected $url = 'https://api.smtp.com/v4';
protected $sensitive_fields = array(
self::SETTING_API_KEY,
);
public function get_description() {
return esc_html__( 'Premium email delivery service with a powerful REST API for sending transactional and marketing emails at scale.', 'gravitysmtp' );
}
/**
* Sends email via SMTP.com.
*
* @since 1.0
*
* @return mixed
*/
public function send() {
try {
$atts = $this->get_send_atts();
$source = $this->get_att( 'source' );
$params = $this->get_request_params();
$email = $this->email;
$this->set_email_log_data( $atts['subject'], $atts['message'], $atts['to'], $atts['from']['from'], $atts['headers'], $atts['attachments'], $source, $params );
$this->logger->log( $email, 'started', __( 'Starting email send for SMTP.com connector.', 'gravitysmtp' ) );
if ( $this->is_test_mode() ) {
$this->events->update( array( 'status' => 'sandboxed' ), $email );
$this->logger->log( $email, 'sandboxed', __( 'Email sandboxed.', 'gravitysmtp' ) );
return true;
}
$response = wp_safe_remote_post( $this->url . '/messages', $params );
if ( is_wp_error( $response ) ) {
$this->log_failure( $email, $response->get_error_message() );
return $email;
}
$response_code = (int) wp_remote_retrieve_response_code( $response );
$response_body = wp_remote_retrieve_body( $response );
$response_data = json_decode( $response_body, true );
// Handle HTTP-level errors without valid JSON
if ( empty( $response_data ) || ! is_array( $response_data ) ) {
if ( $response_code !== 200 ) {
$this->log_failure( $email, __( 'Unexpected response from SMTP.com.', 'gravitysmtp' ) );
return $email;
}
}
// Handle HTTP status errors with specific messages
if ( $response_code === 401 ) {
$this->log_failure( $email, __( 'Invalid API key.', 'gravitysmtp' ) );
return $email;
}
if ( $response_code === 403 ) {
$this->log_failure( $email, __( 'Forbidden — check channel permissions.', 'gravitysmtp' ) );
return $email;
}
if ( $response_code === 429 ) {
$this->log_failure( $email, __( 'Rate limit exceeded.', 'gravitysmtp' ) );
return $email;
}
if ( $response_code >= 500 ) {
$this->log_failure( $email, __( 'SMTP.com server error.', 'gravitysmtp' ) );
return $email;
}
// Parse JSend response format
if ( isset( $response_data['status'] ) ) {
if ( $response_data['status'] === 'success' ) {
$this->events->update( array( 'status' => 'sent' ), $email );
$this->logger->log( $email, 'sent', __( 'Email successfully sent.', 'gravitysmtp' ) );
return true;
}
if ( $response_data['status'] === 'error' ) {
$error_message = isset( $response_data['message'] ) ? $response_data['message'] : __( 'Unknown error from SMTP.com.', 'gravitysmtp' );
$this->log_failure( $email, $error_message );
return $email;
}
if ( $response_data['status'] === 'fail' ) {
$error_message = isset( $response_data['data'] ) ? wp_json_encode( $response_data['data'] ) : __( 'Validation failed.', 'gravitysmtp' );
$this->log_failure( $email, $error_message );
return $email;
}
}
// Fallback for 2xx without a recognized JSend status key
if ( $response_code >= 200 && $response_code < 300 ) {
$this->events->update( array( 'status' => 'sent' ), $email );
$this->logger->log( $email, 'sent', __( 'Email accepted (HTTP 2xx) but response did not include a JSend status field.', 'gravitysmtp' ) );
return true;
}
$this->log_failure( $email, $response_body );
return $email;
} catch ( Exception $e ) {
$this->log_failure( $email, $e->getMessage() );
return $email;
}
}
/**
* Get the request parameters for sending email through connector.
*
* @since 1.0
*
* @return array
*/
public function get_request_params() {
$atts = $this->get_send_atts();
$api_key = $this->get_setting( self::SETTING_API_KEY );
$channel = $this->get_setting( self::SETTING_CHANNEL, '' );
$recipients = array( 'to' => $this->build_recipient_list( $atts['to']->as_array() ) );
if ( ! empty( $atts['headers']['cc'] ) ) {
$recipients['cc'] = $this->build_recipient_list( $atts['headers']['cc']->as_array() );
}
if ( ! empty( $atts['headers']['bcc'] ) ) {
$recipients['bcc'] = $this->build_recipient_list( $atts['headers']['bcc']->as_array() );
}
// Build originator
$from = array( 'address' => $atts['from']['email'] );
if ( ! empty( $atts['from']['name'] ) ) {
$from['name'] = $atts['from']['name'];
}
$originator = array( 'from' => $from );
// Build reply-to
if ( ! empty( $atts['reply_to'] ) ) {
if ( isset( $atts['reply_to']['email'] ) ) {
$reply_to_data = $atts['reply_to'];
} else {
$reply_to_data = $atts['reply_to'][0];
}
$reply_to_entry = array( 'address' => $reply_to_data['email'] );
if ( ! empty( $reply_to_data['name'] ) ) {
$reply_to_entry['name'] = $reply_to_data['name'];
}
$originator['reply_to'] = $reply_to_entry;
}
// Build body parts
$is_html = ! empty( $atts['headers']['content-type'] ) && strpos( $atts['headers']['content-type'], 'text/html' ) !== false;
$parts = array();
if ( $is_html ) {
$parts[] = array(
'type' => 'text/html',
'content' => base64_encode( $atts['message'] ),
'charset' => 'utf-8',
'encoding' => 'base64',
);
// Generate plain text fallback
$text_body = wp_strip_all_tags( $atts['message'] );
$text_body = preg_replace( "/([\r\n]{2,}|[\n]{2,}|[\r]{2,}|[\r\t]{2,}|[\n\t]{2,})/", "\n", $text_body );
$parts[] = array(
'type' => 'text/plain',
'content' => base64_encode( $text_body ),
'charset' => 'utf-8',
'encoding' => 'base64',
);
} else {
$parts[] = array(
'type' => 'text/plain',
'content' => base64_encode( $atts['message'] ),
'charset' => 'utf-8',
'encoding' => 'base64',
);
}
$body = array( 'parts' => $parts );
// Build attachments
if ( ! empty( $atts['attachments'] ) ) {
$attachment_data = $this->get_attachments( $atts['attachments'] );
if ( ! empty( $attachment_data ) ) {
$body['attachments'] = $attachment_data;
}
}
// Assemble the full message payload
$message = array(
'channel' => $channel,
'recipients' => $recipients,
'originator' => $originator,
'subject' => $atts['subject'],
'body' => $body,
);
// Build custom headers
$custom_headers = $this->get_filtered_message_headers();
if ( ! empty( $custom_headers ) ) {
$message['custom_headers'] = $custom_headers;
}
return array(
'body' => wp_json_encode( $message ),
'headers' => $this->get_request_headers( $api_key ),
);
}
/**
* Get the attributes for sending email.
*
* @since 1.0
*
* @return array
*/
protected function get_send_atts() {
$headers = $this->get_parsed_headers( $this->get_att( 'headers', array() ) );
if ( ! empty( $headers['content-type'] ) ) {
$headers['content-type'] = $this->get_att( 'content_type', $headers['content-type'] );
}
return array(
'to' => $this->get_att( 'to', '' ),
'subject' => $this->get_att( 'subject', '' ),
'message' => $this->get_att( 'message', '' ),
'headers' => $headers,
'attachments' => $this->get_att( 'attachments', array() ),
'from' => $this->get_from( true ),
'reply_to' => $this->get_reply_to( true ),
);
}
/**
* Gets a list of attachments, and returns them in a format that can be used by the SMTP.com API.
*
* @since 1.0
*
* @param array $attachments The list of attachments.
*
* @return array Returns an array of attachments formatted for SMTP.com.
*/
protected function get_attachments( $attachments ) {
$data = array();
foreach ( $attachments as $custom_name => $attachment ) {
try {
if ( is_file( $attachment ) && is_readable( $attachment ) ) {
$file_name = is_numeric( $custom_name ) ? basename( $attachment ) : $custom_name;
$content = base64_encode( file_get_contents( $attachment ) );
$data[] = array(
'filename' => $file_name,
'content' => $content,
'type' => mime_content_type( $attachment ),
'encoding' => 'base64',
);
}
} catch ( Exception $e ) {
continue;
}
}
return $data;
}
/**
* Gets the headers to be used in the API request.
*
* @since 1.0
*
* @param string $api_key The API key for authentication.
*
* @return array Returns the header array to be passed to SMTP.com's API.
*/
protected function get_request_headers( $api_key ) {
return array(
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'Authorization' => 'Bearer ' . $api_key,
);
}
/**
* Logs an email send failure.
*
* @since 1.0
*
* @param string $email The email that failed.
* @param string $error_message The error message.
*/
private function log_failure( $email, $error_message ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $error_message );
}
/**
* Builds a recipient list formatted for the SMTP.com API.
*
* @since 2.2.0
*
* @param array $recipients Raw recipient array with 'email' and optional 'name' keys.
*
* @return array Formatted recipient list for the API payload.
*/
private function build_recipient_list( $recipients ) {
$list = array();
foreach ( $recipients as $recipient ) {
$entry = array( 'address' => $recipient['email'] );
if ( ! empty( $recipient['name'] ) ) {
$entry['name'] = $recipient['name'];
}
$list[] = $entry;
}
return $list;
}
/**
* Connector data.
*
* @since 1.0
*
* @return array
*/
public function connector_data() {
return array(
self::SETTING_API_KEY => $this->get_setting( self::SETTING_API_KEY, '' ),
self::SETTING_CHANNEL => $this->get_setting( self::SETTING_CHANNEL, '' ),
self::SETTING_FROM_EMAIL => $this->get_setting( self::SETTING_FROM_EMAIL, '' ),
self::SETTING_FORCE_FROM_EMAIL => $this->get_setting( self::SETTING_FORCE_FROM_EMAIL, false ),
self::SETTING_FROM_NAME => $this->get_setting( self::SETTING_FROM_NAME, '' ),
self::SETTING_FORCE_FROM_NAME => $this->get_setting( self::SETTING_FORCE_FROM_NAME, false ),
self::SETTING_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_REPLY_TO_EMAIL, '' ),
self::SETTING_FORCE_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_FORCE_REPLY_TO_EMAIL, false ),
);
}
/**
* Settings fields.
*
* @since 1.0
*
* @return array
*/
public function settings_fields() {
return array(
'title' => esc_html__( 'SMTP.com Settings', 'gravitysmtp' ),
'description' => '',
'fields' => array_merge(
array(
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Configuration', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => array( 4, 0, 4, 0 ),
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'API Key', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'helpTextAttributes' => array(
'asHtml' => true,
'content' => __( 'Enter your SMTP.com API key. You can find this in your SMTP.com dashboard under API Settings.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'name' => self::SETTING_API_KEY,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_API_KEY, '' ),
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'Channel Name', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'helpTextAttributes' => array(
'asHtml' => true,
'content' => __( 'Enter your SMTP.com channel name. You can find your channels in the SMTP.com dashboard under Channels.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'name' => self::SETTING_CHANNEL,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_CHANNEL, '' ),
),
),
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'General Settings', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => 4,
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
),
$this->get_from_settings_fields(),
$this->get_reply_to_settings_fields(),
),
);
}
/**
* Determine if the API credentials are configured correctly.
*
* @since 1.0
*
* @return bool|WP_Error Returns true if configured, or a WP_Error object if not.
*/
public function is_configured() {
$api_key = $this->get_setting( self::SETTING_API_KEY, '' );
if ( empty( $api_key ) ) {
$error = new WP_Error( 'missing_api_key', __( 'API key is required.', 'gravitysmtp' ) );
self::$configured = $error;
return $error;
}
$channel = $this->get_setting( self::SETTING_CHANNEL, '' );
if ( empty( $channel ) ) {
$error = new WP_Error( 'missing_channel', __( 'Channel name is required.', 'gravitysmtp' ) );
self::$configured = $error;
return $error;
}
$response = wp_remote_get(
$this->url . '/account',
array(
'headers' => $this->get_request_headers( $api_key ),
)
);
if ( is_wp_error( $response ) ) {
$error = new WP_Error( 'connection_error', $response->get_error_message() );
self::$configured = $error;
return $error;
}
$response_code = (int) wp_remote_retrieve_response_code( $response );
if ( $response_code === 401 ) {
$error = new WP_Error( 'invalid_api_key', __( 'Invalid API key.', 'gravitysmtp' ) );
self::$configured = $error;
return $error;
}
if ( $response_code !== 200 ) {
$error = new WP_Error( 'connection_error', __( 'Unable to connect to SMTP.com. Please check your credentials.', 'gravitysmtp' ) );
self::$configured = $error;
return $error;
}
self::$configured = true;
return true;
}
/**
* Get the unique data for this connector, merged with the default/common data for all
* connectors in the system.
*
* @since 1.0
*
* @return array
*/
protected function get_merged_data() {
$data = parent::get_merged_data();
$data['disabled'] = ! Feature_Flag_Manager::is_enabled( 'smtpcom_integration' );
return $data;
}
}
@@ -0,0 +1,464 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Types;
use Exception;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Base;
use Gravity_Forms\Gravity_SMTP\Feature_Flags\Feature_Flag_Manager;
use WP_Error;
/**
* Connector for SparkPost
*
* @since 1.0
*/
class Connector_Sparkpost extends Connector_Base {
const SETTING_API_KEY = 'api_key';
const SETTING_ACCOUNT_LOCATION = 'account_location';
const SETTING_USE_RETURN_PATH = 'use_return_path';
protected $name = 'sparkpost';
protected $title = 'SparkPost';
protected $disabled = true;
protected $logo = 'SparkPost';
protected $full_logo = 'SparkPostFull';
protected $url = 'https://api.sparkpost.com/api/v1';
protected $url_eu = 'https://api.eu.sparkpost.com/api/v1';
protected $sensitive_fields = array(
self::SETTING_API_KEY,
);
public function get_description() {
return esc_html__( 'SparkPost provides email delivery services and transactional email for developers at companies of all sizes.', 'gravitysmtp' );
}
/**
* Sends email via SparkPost.
*
* @since 1.0
*
* @return int returns the email ID
*/
public function send() {
try {
$atts = $this->get_send_atts();
$source = $this->get_att( 'source' );
$params = $this->get_request_params();
$email = $this->email;
$this->set_email_log_data( $atts['subject'], $atts['message'], $atts['to'], $atts['from']['from'], $atts['headers'], $atts['attachments'], $source, $params );
$this->logger->log( $email, 'started', __( 'Starting email send for SparkPost connector.', 'gravitysmtp' ) );
if ( $this->is_test_mode() ) {
$this->events->update( array( 'status' => 'sandboxed' ), $email );
$this->logger->log( $email, 'sandboxed', __( 'Email sandboxed.', 'gravitysmtp' ) );
return true;
}
$response = wp_safe_remote_post( $this->get_base_url() . '/transmissions/', $params );
$is_success = in_array( (int) wp_remote_retrieve_response_code( $response ), array( 200, 201, 202 ) );
if ( ! $is_success ) {
$this->log_failure( $email, wp_remote_retrieve_body( $response ) );
return $email;
}
$this->events->update( array( 'status' => 'sent' ), $email );
$this->logger->log( $email, 'sent', __( 'Email successfully sent.', 'gravitysmtp' ) );
return true;
} catch ( Exception $e ) {
$this->log_failure( $email, $e->getMessage() );
return $email;
}
}
protected function get_base_url() {
$location = $this->get_setting( self::SETTING_ACCOUNT_LOCATION, 'us' );
return $location !== 'us' ? $this->url_eu : $this->url;
}
/**
* Get the request parameters for sending email through connector.
*
* @since 1.0
*
* @return array
*/
public function get_request_params() {
$atts = $this->get_send_atts();
$api_key = $this->get_setting( self::SETTING_API_KEY );
$send_as_transactional = apply_filters( 'gravitysmtp_sparkpost_send_as_transactional', true );
$body = array(
'recipients' => array(),
'content' => array(
'from' => array(
'name' => $atts['from']['name'],
'email' => $atts['from']['email'],
),
'subject' => $atts['subject'],
'headers' => array(),
),
'options' => array(
'transactional' => $send_as_transactional,
),
);
foreach ( $atts['to']->as_array() as $recipient ) {
$body['recipients'][] = array( 'address' => $recipient );
}
// Setting content
$is_html = ! empty( $atts['headers']['content-type'] ) && strpos( $atts['headers']['content-type'], 'text/html' ) !== false;
if ( $is_html ) {
$body['content']['html'] = $atts['message'];
} else {
$body['content']['text'] = $atts['message'];
}
$main_recipient = $atts['to']->first()->as_array();
// Setting cc
if ( ! empty( $atts['headers']['cc'] ) ) {
$cc_headers = array();
foreach ( $atts['headers']['cc']->as_array() as $cc_value ) {
$values = array(
'email' => $cc_value['email'],
'name' => ! empty( $cc_value['name'] ) ? $cc_value['name'] : null,
'header_to' => $main_recipient['email'],
);
$body['recipients'][] = array( 'address' => array_filter( $values ) );
$cc_headers[] = $cc_value['email'];
}
$body['content']['headers']['CC'] = implode( ', ', $cc_headers );
}
// Setting bcc
if ( ! empty( $atts['headers']['bcc'] ) ) {
foreach ( $atts['headers']['bcc']->as_array() as $bcc_value ) {
$values = array(
'email' => $bcc_value['email'],
'name' => ! empty( $bcc_value['name'] ) ? $bcc_value['name'] : null,
'header_to' => $main_recipient['email'],
);
$body['recipients'][] = array( 'address' => array_filter( $values ) );
}
}
// Setting reply to
if ( ! empty( $atts['reply_to'] ) ) {
if ( isset( $atts['reply_to']['email'] ) ) {
$reply_to = $atts['reply_to'];
} else {
$reply_to = $atts['reply_to'][0];
}
$body['content']['reply_to'] = $reply_to['email'];
}
// Setting attachments
if ( ! empty( $atts['attachments'] ) ) {
$body['content']['attachments'] = $this->get_attachments( $atts['attachments'] );
}
if ( empty( $body['content']['headers'] ) ) {
unset( $body['content']['headers'] );
}
return array(
'body' => json_encode( $body ),
'headers' => $this->get_request_headers( $api_key ),
);
}
/**
* Get the attributes for sending email.
*
* @since 1.0
*
* @return array
*/
protected function get_send_atts() {
$headers = $this->get_parsed_headers( $this->get_att( 'headers', array() ) );
if ( ! empty( $headers['content-type'] ) ) {
$headers['content-type'] = $this->get_att( 'content_type', $headers['content-type'] );
}
return array(
'to' => $this->get_att( 'to', '' ),
'subject' => $this->get_att( 'subject', '' ),
'message' => $this->get_att( 'message', '' ),
'headers' => $headers,
'attachments' => $this->get_att( 'attachments', array() ),
'from' => $this->get_from( true ),
'reply_to' => $this->get_reply_to( true ),
);
}
/**
* Gets a list of attachments, and returns them in a format that can be used by the API.
*
* @param array $attachments the list of attachments
*
* @since 1.0
*
* @return array Returns an array of attachments. Each item with a 'content' and 'name' property.
*/
protected function get_attachments( $attachments ) {
$data = array();
foreach ( $attachments as $custom_name => $attachment ) {
try {
if ( is_file( $attachment ) && is_readable( $attachment ) ) {
$fileName = is_numeric( $custom_name ) ? basename( $attachment ) : $custom_name;
$content = base64_encode( file_get_contents( $attachment ) );
$data[] = array(
'name' => $fileName,
'data' => $content,
'type' => mime_content_type( $attachment ),
);
}
} catch ( Exception $e ) {
continue;
}
}
return $data;
}
/**
* Gets the headers to be used in the API request.
*
* @since 1.0
*
* @return array returns the header array to be passed to SparkPost's API
*/
protected function get_request_headers( $api_key ) {
return array(
'content-type' => 'application/json',
'accept' => 'application/json',
'Authorization' => $api_key,
);
}
/**
* Logs an email send failure.
*
* @since 1.0
*
* @param string $email the email that failed
* @param string $error_message the error message
*/
private function log_failure( $email, $error_message ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $error_message );
}
/**
* Connector data.
*
* @since 1.0
*
* @return array
*/
public function connector_data() {
return array(
self::SETTING_API_KEY => $this->get_setting( self::SETTING_API_KEY, '' ),
self::SETTING_FROM_EMAIL => $this->get_setting( self::SETTING_FROM_EMAIL, '' ),
self::SETTING_FORCE_FROM_EMAIL => $this->get_setting( self::SETTING_FORCE_FROM_EMAIL, false ),
self::SETTING_FROM_NAME => $this->get_setting( self::SETTING_FROM_NAME, '' ),
self::SETTING_FORCE_FROM_NAME => $this->get_setting( self::SETTING_FORCE_FROM_NAME, false ),
self::SETTING_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_REPLY_TO_EMAIL, '' ),
self::SETTING_FORCE_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_FORCE_REPLY_TO_EMAIL, false ),
);
}
/**
* Settings fields.
*
* @since 1.0
*
* @return array
*/
public function settings_fields() {
return array(
'title' => esc_html__( 'SparkPost Settings', 'gravitysmtp' ),
'description' => '',
'fields' => array_merge(
array(
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Configuration', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => array( 4, 0, 4, 0 ),
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
array(
'component' => 'Select',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'Account Location', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'name' => self::SETTING_ACCOUNT_LOCATION,
'size' => 'size-l',
'spacing' => 6,
'initialValue' => $this->get_setting( self::SETTING_ACCOUNT_LOCATION, 'us' ),
'options' => array(
array(
'label' => __( 'United States', 'gravitysmtp' ),
'value' => 'us',
),
array(
'label' => __( 'Europe', 'gravitysmtp' ),
'value' => 'eu',
),
),
),
),
array(
'component' => 'Input',
'props' => array(
'labelAttributes' => array(
'label' => esc_html__( 'API Key', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'helpTextAttributes' => array(
'asHtml' => true,
/* translators: 1: opening anchor tag, 2: closing anchor tag */
'content' => sprintf( __( 'To generate an API key from SparkPost, log in to your SparkPost dashboard, navigate to the API Keys section, and %1$sgenerate your API key%2$s.', 'gravitysmtp' ), '<a class="gform-link gform-typography--size-text-xs" href="https://app.sparkpost.com/account/api-keys" target="_blank" rel="noopener noreferrer">', '</a>' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'name' => self::SETTING_API_KEY,
'size' => 'size-l',
'spacing' => 6,
'value' => $this->get_setting( self::SETTING_API_KEY, '' ),
),
),
array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'General Settings', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => 4,
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
),
array(
'component' => 'Toggle',
'props' => array(
'helpTextAttributes' => array(
'content' => esc_html__( 'If Return Path is enabled this adds the return path to the email header which indicates where non-deliverable notifications should be sent. Bounce messages may be lost if not enabled.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
'spacing' => array( 2, 0, 0, 0 ),
),
'helpTextWidth' => 'full',
'initialChecked' => (bool) $this->get_setting( self::SETTING_USE_RETURN_PATH, false ),
'labelAttributes' => array(
'label' => esc_html__( 'Return Path', 'gravitysmtp' ),
),
'labelPosition' => 'left',
'name' => self::SETTING_USE_RETURN_PATH,
'size' => 'size-m',
'spacing' => 5,
'width' => 'full',
),
),
),
$this->get_from_settings_fields(),
$this->get_reply_to_settings_fields(),
),
);
}
/**
* Determine if the API credentials are configured correctly.
*
* @since 1.0
*
* @return bool|WP_Error returns true if configured, or a WP_Error object if not
*/
public function is_configured() {
$valid_api = $this->verify_api_key();
if ( is_wp_error( $valid_api ) ) {
self::$configured = $valid_api;
return $valid_api;
}
self::$configured = true;
return true;
}
/**
* Verify the API key with the API.
*
* @since 1.0
*
* @return true|WP_Error
*/
private function verify_api_key() {
$api_key = $this->get_setting( self::SETTING_API_KEY );
$url = $this->get_base_url() . '/sending-domains?ownership_verified=true';
if ( empty( $api_key ) ) {
return new WP_Error( 'missing_api_key', __( 'No API Key provided.', 'gravitysmtp' ) );
}
$response = wp_remote_get(
$url,
array(
'headers' => $this->get_request_headers( $api_key ),
)
);
if ( wp_remote_retrieve_response_code( $response ) != '200' ) {
return new WP_Error( 'invalid_api_key', __( 'Invalid API Key provided.', 'gravitysmtp' ) );
}
return true;
}
/**
* Get the unique data for this connector, merged with the default/common data for all
* connectors in the system.
*
* @since 1.0
*
* @return array
*/
protected function get_merged_data() {
$data = parent::get_merged_data();
$data['disabled'] = ! Feature_Flag_Manager::is_enabled( 'sparkpost_integration' );
return $data;
}
}
@@ -0,0 +1,593 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Connectors\Types;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Base;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Connectors\Oauth\Zoho_Oauth_Handler;
use Gravity_Forms\Gravity_SMTP\Enums\Zoho_Datacenters_Enum;
use Gravity_Forms\Gravity_SMTP\Feature_Flags\Feature_Flag_Manager;
use Gravity_Forms\Gravity_SMTP\Gravity_SMTP;
use Gravity_Forms\Gravity_SMTP\Utils\Booliesh;
/**
* Connector for Zoho
*
* @since 1.0
*/
class Connector_Zoho extends Connector_Base {
const SETTING_ACCESS_TOKEN = 'access_token';
const SETTING_CLIENT_ID = 'client_id';
const SETTING_CLIENT_SECRET = 'client_secret';
const SETTING_DATA_CENTER_REGION = 'data_center_region';
const SETTING_ACCOUNT_ID = 'account_id';
const VALUE_REDIRECT_URI = 'redirect_uri';
const VALUE_REDIRECT_URI_FULL = 'redirect_uri_full';
protected $name = 'zoho';
protected $title = 'Zoho Mail';
protected $logo = 'Zoho';
protected $full_logo = 'ZohoFull';
protected $sensitive_fields = array(
self::SETTING_ACCESS_TOKEN,
self::SETTING_CLIENT_ID,
self::SETTING_CLIENT_SECRET,
);
/**
* Sending logic.
*
* @since 1.0
*
* @return bool
*/
public function send() {
$atts = $this->get_send_atts();
$email = $this->email;
$source = $this->get_att( 'source' );
$params = $this->get_request_body( $atts );
$this->set_email_log_data( $atts['subject'], $atts['message'], $atts['to'], $atts['from']['email'], $atts['headers'], $atts['attachments'], $source, $params );
$args = array(
'headers' => $this->get_request_headers(),
'body' => json_encode( $params ),
);
$this->set_email_log_data( $atts['subject'], $atts['message'], $atts['to'], $atts['from']['from'], $atts['headers'], $atts['attachments'], $source, $params );
$this->logger->log( $email, 'started', __( 'Starting email send for Zoho connector.', 'gravitysmtp' ) );
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Starting email send with Zoho connector and the following params: ' . json_encode( $params ) ) );
if ( $this->is_test_mode() ) {
$this->events->update( array( 'status' => 'sandboxed' ), $email );
$this->logger->log( $email, 'sandboxed', __( 'Email sandboxed.', 'gravitysmtp' ) );
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Test mode is enabled, sandboxing email.' ) );
return true;
}
$request_url = $this->get_api_url( sprintf( 'api/accounts/%s/messages', $this->get_setting( self::SETTING_ACCOUNT_ID, '' ) ) );
$request = wp_remote_post( $request_url, $args );
$response_code = wp_remote_retrieve_response_code( $request );
$body = wp_remote_retrieve_body( $request );
$decoded = json_decode( $body, true );
if ( $response_code >= 300 ) {
$this->log_failure( $email, $body );
$this->debug_logger->log_error( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Email failed to send. Details: ' . $body ) );
return $email;
}
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Received response of: ' . $body ) );
$this->events->update( array( 'status' => 'sent' ), $email );
$this->logger->log( $email, 'sent', __( 'Email successfully sent.', 'gravitysmtp' ) );
$this->debug_logger->log_debug( $this->wrap_debug_with_details( __FUNCTION__, $email, 'Email successfully sent.' ) );
return true;
}
private function get_request_headers() {
return array(
'Authorization' => 'Zoho-oauthtoken ' . $this->get_setting( self::SETTING_ACCESS_TOKEN ),
'Content-Type' => 'application/json',
);
}
private function get_request_body( $atts ) {
$body = array(
'fromAddress' => $atts['from']['email'],
'toAddress' => $atts['to']->first()->email,
'subject' => $atts['subject'],
'content' => $atts['message'],
'encoding' => 'UTF-8',
);
$is_html = ! empty( $atts['headers']['content-type'] ) && strpos( $atts['headers']['content-type'], 'text/html' ) !== false;
$body['mailFormat'] = $is_html ? 'html' : 'plaintext';
if ( ! empty( $atts['attachments'] ) ) {
$body['attachments'] = $this->handle_attachments( $atts['attachments'] );
}
return $body;
}
private function handle_attachments( $attachments ) {
$data = [];
$headers = $this->get_request_headers();
$headers['Content-Type'] = 'application/octet-stream';
foreach ( $attachments as $attachment ) {
if ( ! file_exists( $attachment ) ) {
continue;
}
$file = file_get_contents( $attachment );
if ( $file === false ) {
continue;
}
$file_name = basename( $attachment );
// Upload the attachment via Zoho API.
$url = add_query_arg(
'fileName',
$file_name,
$this->get_api_url( sprintf( 'api/accounts/%s/messages/attachments', $this->get_setting( self::SETTING_ACCOUNT_ID, '' ) ) )
);
$params = array(
'headers' => $headers,
'body' => $file,
);
$response = wp_safe_remote_post( $url, $params );
if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) {
continue;
}
$body = json_decode( wp_remote_retrieve_body( $response ), true );
if ( ! empty( $body['data'] ) ) {
$data[] = $body['data'];
}
}
return $data;
}
/**
* Get the attributes for sending email.
*
* @since 1.0
*
* @return array
*/
private function get_send_atts() {
$headers = $this->get_parsed_headers( $this->get_att( 'headers', array() ) );
if ( ! empty( $headers['content-type'] ) ) {
$headers['content-type'] = $this->get_att( 'content_type', $headers['content-type'] );
}
return array(
'to' => $this->get_att( 'to', '' ),
'subject' => $this->get_att( 'subject', '' ),
'message' => $this->get_att( 'message', '' ),
'headers' => $headers,
'attachments' => $this->get_att( 'attachments', array() ),
'from' => $this->get_from( true ),
'reply_to' => $this->get_reply_to( true ),
);
}
private function get_api_url( $endpoint ) {
$data_center_location = $this->get_setting( self::SETTING_DATA_CENTER_REGION, 'us' );
$base = Zoho_Datacenters_Enum::url_for_datacenter( $data_center_location );
return trailingslashit( $base ) . $endpoint;
}
public function get_description() {
return esc_html__( 'Reach inboxes when it matters most. Send email notifications to your contacts with Zoho Mail.', 'gravitysmtp' );
}
protected function get_merged_data() {
$data = parent::get_merged_data();
$data['disabled'] = ! Feature_Flag_Manager::is_enabled( 'zoho_integration' );
return $data;
}
/**
* Connector data.
*
* @since 1.0
*
* @return array
*/
public function connector_data() {
return array(
self::SETTING_CLIENT_ID => $this->get_setting( self::SETTING_CLIENT_ID, '' ),
self::SETTING_CLIENT_SECRET => $this->get_setting( self::SETTING_CLIENT_SECRET, '' ),
self::SETTING_ACCESS_TOKEN => $this->get_setting( self::SETTING_ACCESS_TOKEN, '' ),
self::SETTING_FROM_EMAIL => $this->get_setting( self::SETTING_FROM_EMAIL, '' ),
self::SETTING_FORCE_FROM_EMAIL => $this->get_setting( self::SETTING_FORCE_FROM_EMAIL, false ),
self::SETTING_FROM_NAME => $this->get_setting( self::SETTING_FROM_NAME, '' ),
self::SETTING_FORCE_FROM_NAME => $this->get_setting( self::SETTING_FORCE_FROM_NAME, false ),
self::SETTING_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_REPLY_TO_EMAIL, '' ),
self::SETTING_FORCE_REPLY_TO_EMAIL => $this->get_setting( self::SETTING_FORCE_REPLY_TO_EMAIL, false ),
'oauth_url' => 'https://accounts.zoho.com/oauth/v2/auth',
'oauth_params' => '&' . $this->get_oauth_params(),
);
}
protected function get_oauth_params() {
/**
* @var Zoho_Oauth_Handler $oauth_handler
*/
$oauth_handler = Gravity_SMTP::container()->get( Connector_Service_Provider::ZOHO_OAUTH_HANDLER );
$params = array(
'response_type' => 'code',
'redirect_uri' => urldecode( $oauth_handler->get_return_url() ),
'scope' => $oauth_handler->get_scope(),
'state' => 1,
'access_type' => 'offline',
'prompt' => 'consent',
);
return http_build_query( $params );
}
public function is_configured() {
if ( Booliesh::get( $this->get_setting( 'access_token', false ) ) ) {
/**
* @var Zoho_Oauth_Handler $oauth_handler
*/
$oauth_handler = Gravity_SMTP::container()->get( Connector_Service_Provider::ZOHO_OAUTH_HANDLER );
$token = $oauth_handler->get_access_token();
return $token;
}
return false;
}
/**
* Settings fields.
*
* @since 1.0
*
* @return array
*/
public function settings_fields() {
/**
* @var Zoho_Oauth_Handler $oauth_handler
*/
$oauth_handler = Gravity_SMTP::container()->get( Connector_Service_Provider::ZOHO_OAUTH_HANDLER );
$oauth_handler->handle_response( $this->name );
$token = $oauth_handler->get_access_token( $this->name );
$has_token = $token && ! is_wp_error( $token );
$settings = array(
'title' => esc_html__( 'Zoho Mail Settings', 'gravitysmtp' ),
'hide_save' => ( ! $has_token ),
'fields' => array(),
);
if ( ! $token || is_wp_error( $token ) ) {
$settings['fields'][] = array(
'component' => 'Alert',
'props' => array(
'customIconPrefix' => 'gravity-admin-icon',
'theme' => 'cosmos',
'type' => 'notice',
'spacing' => 3,
),
'fields' => array(
array(
'component' => 'Text',
'props' => array(
'content' => esc_html__( 'Please click the button below to initiate a connection with your Zoho Mail account. Remember to fill out both the Client ID and Client Secret fields before proceeding.', 'gravitysmtp' ),
'customClasses' => array(
'gform--display-block',
'gravitysmtp-integration__notice-message'
),
'size' => 'text-sm',
'spacing' => 4,
'tagName' => 'span',
),
),
array(
'component' => 'Link',
'props' => array(
'content' => esc_html__( 'Read our Zoho Mail documentation', 'gravitysmtp' ),
'customClasses' => array(
'gform-link--theme-cosmos',
'gravitysmtp-integration__notice-link',
'gform-button',
'gform-button--size-height-m',
'gform-button--white',
'gform-button--width-auto'
),
'href' => 'https://docs.gravitysmtp.com/category/integrations/zoho/',
'target' => '_blank',
),
),
),
);
}
if ( isset( $_GET['code'] ) && ! $has_token ) {
$settings['fields'][] = array(
'component' => 'Alert',
'props' => array(
'customIconPrefix' => 'gravity-admin-icon',
'theme' => 'cosmos',
'type' => 'error',
'spacing' => 3,
),
'fields' => array(
array(
'component' => 'Text',
'props' => array(
'content' => esc_html__( 'Error Connecting to Zoho Mail. Check your credentials and try again.', 'gravitysmtp' ),
'weight' => 'medium',
'size' => 'text-sm',
'spacing' => 2,
'tagName' => 'span',
),
),
),
);
}
$settings['fields'][] = array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Configuration', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => [ 4, 0, 3, 0 ],
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
);
$settings['fields'][] = array(
'component' => 'Select',
'props' => array(
'name' => self::SETTING_DATA_CENTER_REGION,
'size' => 'size-l',
'spacing' => [ 4, 0, 3, 0 ],
'helpTextAttributes' => array(
'content' => esc_html__( 'If you are unsure about your Datacenter location, check your Zoho account.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'labelAttributes' => array(
'label' => esc_html__( 'Datacenter Region', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'options' => Zoho_Datacenters_Enum::select_component_options(),
'initialValue' => $this->get_setting( self::SETTING_DATA_CENTER_REGION, 'us' ),
),
);
if ( ! $token || is_wp_error( $token ) ) {
$settings['fields'][] = array(
'component' => 'LinkedHelpTextInput',
'external' => true,
'handle_change' => true,
'links' => array(
array(
'key' => 'link',
'props' => array(
'href' => 'https://api-console.zoho.com/',
'size' => 'text-xs',
'target' => '_blank',
),
),
),
'props' => array(
'helpTextAttributes' => array(
'content' => esc_html__( 'To obtain an Client ID from Zoho Mail, login to your {{link}}Zoho API{{link}} dashboard and generate a Client ID.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'labelAttributes' => array(
'label' => esc_html__( 'Client ID', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'name' => self::SETTING_CLIENT_ID,
'spacing' => 4,
'size' => 'size-l',
'value' => $this->get_setting( self::SETTING_CLIENT_ID, '' ),
),
);
$settings['fields'][] = array(
'component' => 'LinkedHelpTextInput',
'external' => true,
'handle_change' => true,
'links' => array(
array(
'key' => 'link',
'props' => array(
'href' => 'https://api-console.zoho.com/',
'size' => 'text-xs',
'target' => '_blank',
),
),
),
'props' => array(
'helpTextAttributes' => array(
'content' => esc_html__( 'To obtain a Client Secret password, log in to your {{link}}Zoho API{{link}} dashboard and generate a new client secret. Then, copy the value into this field.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
),
'labelAttributes' => array(
'label' => esc_html__( 'Client Secret', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'name' => self::SETTING_CLIENT_SECRET,
'spacing' => 6,
'size' => 'size-l',
'value' => $this->get_setting( self::SETTING_CLIENT_SECRET, '' ),
),
);
$settings['fields'][] = array(
'component' => 'CopyInput',
'external' => true,
'props' => array(
'actionButtonAttributes' => array(
'customAttributes' => array(
'type' => 'button',
),
'icon' => 'copy',
'iconPrefix' => 'gravity-admin-icon',
'label' => esc_html__( 'Copy', 'gravitysmtp' ),
),
'labelAttributes' => array(
'label' => esc_html__( 'Redirect URI', 'gravitysmtp' ),
'size' => 'text-sm',
'weight' => 'medium',
),
'name' => self::VALUE_REDIRECT_URI,
'spacing' => 6,
'size' => 'size-l',
'customAttributes' => array(
'readOnly' => true,
),
'value' => urldecode( $oauth_handler->get_return_url( 'copy' ) . '?page=gravitysmtp-settings&integration=zoho&tab=integrations' ),
'helpTextAttributes' => array(
'content' => __( 'Copy this URL into the "Authorized redirect URIs" field of your Zoho Mail application.', 'gravitysmtp' ),
'size' => 'text-xs',
'weight' => 'regular',
),
),
);
$settings['fields'][] = array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Authorization', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => [ 4, 0, 3, 0 ],
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
);
$settings['fields'][] = array(
'component' => 'BrandedButton',
'external' => true,
'props' => array(
'label' => esc_html__( 'Sign in with Zoho Mail', 'gravitysmtp' ),
'spacing' => 6,
'Svg' => 'ZohoAltLogo',
'type' => 'color',
),
);
} else {
$settings['fields'][] = array(
'component' => 'Box',
'props' => array(
'customClasses' => array( 'gravitysmtp-google-integration__connected-message' ),
'display' => 'flex',
'spacing' => 3,
),
'fields' => array(
array(
'component' => 'Icon',
'props' => array(
'customClasses' => array(
'gravitysmtp-google-integration__checkmark',
'gform-icon--preset-active',
'gform-icon-preset--status-correct',
'gform-alert__icon'
),
'icon' => 'checkmark-simple',
'iconPrefix' => 'gravity-admin-icon',
),
),
array(
'component' => 'Text',
'props' => array(
'asHtml' => true,
'content' => sprintf(
'%s <span class="gform-text gform-text--color-port gform-typography--size-text-sm gform-typography--weight-medium">%s</span>',
esc_html__( 'Connected to Zoho Mail with account:', 'gravitysmtp' ),
esc_html( $oauth_handler->get_connection_details()['account_id'] )
),
'size' => 'text-sm',
'tagName' => 'span',
),
),
),
);
$disconnect_url = add_query_arg( '_wpnonce', wp_create_nonce( 'gsmtp_disconnect_zoho' ), admin_url( 'admin-post.php?action=smtp_disconnect_zoho' ) );
$settings['fields'][] = array(
'component' => 'Text',
'props' => array(
'content' => sprintf( '<a href="%s" class="%s"><span class="gravity-admin-icon gravity-admin-icon--x-circle gform-button__icon"></span>%s</a>', $disconnect_url, 'gform-link gform-link--theme-cosmos gform-button gform-button--size-height-m gform-button--white gform-button--width-auto gform-button--active-type-loader gform-button--loader-after gform-button--icon-leading', __( 'Disconnect from Zoho Mail', 'gravitysmtp' ) ),
'asHtml' => true,
'spacing' => 6,
),
);
$settings['fields'][] = array(
'component' => 'Heading',
'props' => array(
'content' => esc_html__( 'Configuration', 'gravitysmtp' ),
'size' => 'text-sm',
'spacing' => [ 4, 0, 4, 0 ],
'tagName' => 'h3',
'type' => 'boxed',
'weight' => 'medium',
),
);
$settings['fields'] = array_merge( $settings['fields'], $this->get_from_settings_fields(), $this->get_reply_to_settings_fields() );
}
return $settings;
}
/**
* Logs an email send failure.
*
* @since 1.4.0
*
* @param string $email The email that failed.
* @param string $error_message The error message.
*/
private function log_failure( $email, $error_message ) {
$this->events->update( array( 'status' => 'failed' ), $email );
$this->logger->log( $email, 'failed', $error_message );
}
}
@@ -0,0 +1,30 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Data_Store;
class Const_Data_Store implements Data_Store {
public function get( $setting_name, $connector ) {
$const_name = sprintf( 'GRAVITYSMTP_%s_%s', strtoupper( $connector ), strtoupper( $setting_name ) );
if ( defined( $const_name ) ) {
return constant( $const_name );
}
return null;
}
public function save( $setting_name, $value, $connector ) {
return;
}
public function get_plugin_const( $setting_name ) {
$const_name = sprintf( 'GRAVITYSMTP_%s', strtoupper( $setting_name ) );
if ( defined( $const_name ) ) {
return constant( $const_name );
}
return null;
}
}
@@ -0,0 +1,105 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Data_Store;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Save_Connector_Settings_Endpoint;
use Gravity_Forms\Gravity_SMTP\Enums\Connector_Status_Enum;
class Data_Store_Router {
protected $const_data_store;
protected $opts_data_store;
protected $plugin_opts_data_store;
public function __construct( $const_data_store, $opts_data_store, $plugin_opts_data_store ) {
$this->const_data_store = $const_data_store;
$this->opts_data_store = $opts_data_store;
$this->plugin_opts_data_store = $plugin_opts_data_store;
}
/**
* Helper method for retrieving plugin settings (i.e., settings for the plugin globally
* and not specific to this connector).
*
* @since 1.0
*
* @param $setting_name
* @param $default
*
* @return mixed|null
*/
public function get_plugin_setting( $setting_name, $default = null ) {
if ( ! is_null( $this->const_data_store->get_plugin_const( $setting_name ) ) ) {
return $this->const_data_store->get_plugin_const( $setting_name );
}
$val = $this->plugin_opts_data_store->get( $setting_name );
if ( is_null( $val ) ) {
return $default;
}
return $val;
}
/**
* Helper method to retrieve a saved setting specifically for this connector.
*
* @since 1.0
*
* @param $connector
* @param $setting_name
* @param $default
*
* @return mixed
*/
public function get_setting( $connector, $setting_name, $default = null ) {
if ( ! is_null( $this->const_data_store->get( $setting_name, $connector ) ) ) {
return $this->const_data_store->get( $setting_name, $connector );
}
$val = $this->opts_data_store->get( $setting_name, $connector );
if ( is_null( $val ) ) {
return $default;
}
return $val;
}
public function get_active_connector( $default = false ) {
$connectors = $this->get_plugin_setting( Save_Connector_Settings_Endpoint::SETTING_ENABLED_CONNECTOR, array() );
$connectors = array_filter( $connectors );
$connector = empty( $connectors ) ? false : array_key_first( $connectors );
if ( empty( $connector ) ) {
return $default;
}
return $connector;
}
public function get_connector_status_of_type( $status_type, $default = false ) {
$const_check = sprintf( 'GRAVITYSMTP_INTEGRATION_%s', strtoupper( $status_type ) );
if ( defined( $const_check ) ) {
return constant( $const_check );
}
$setting = Connector_Status_Enum::setting_for_status( $status_type );
$connectors = $this->get_plugin_setting( $setting, array() );
$connectors = array_filter( $connectors, function( $enabled ) {
return ! empty( $enabled ) && $enabled !== false && $enabled !== 'false';
} );
$connector = empty( $connectors ) ? false : array_key_first( $connectors );
if ( empty( $connector ) ) {
return $default;
}
return $connector;
}
}
@@ -0,0 +1,56 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Data_Store;
class Opts_Data_Store implements Data_Store {
public function get( $setting_name, $connector ) {
$opts = $this->get_opts( $connector );
return isset( $opts[ $setting_name ] ) ? $opts[ $setting_name ] : null;
}
public function save( $setting_name, $value, $connector ) {
$opts = $this->get_opts( $connector );
$opts_name = sprintf( 'gravitysmtp_%s', strtolower( $connector ) );
$opts[ $setting_name ] = $value;
update_option( $opts_name, json_encode( $opts ) );
}
public function save_all( $value, $connector ) {
$opts = $this->get_opts( $connector );
$opts_name = sprintf( 'gravitysmtp_%s', strtolower( $connector ) );
foreach( $value as $key => $val ) {
if ( $val === '****************' ){
continue;
}
if ( $val === 'true' ) {
$val = true;
}
if ( $val === 'false' ) {
$val = false;
}
$opts[ $key ] = $val;
}
update_option( $opts_name, json_encode( $opts ) );
}
public function get_opts( $connector ) {
$opts_name = sprintf( 'gravitysmtp_%s', strtolower( $connector ) );
$opts = get_option( $opts_name, '{}' );
$opts = json_decode( $opts, true );
return $opts;
}
public function delete_all( $connector ) {
$opts_name = sprintf( 'gravitysmtp_%s', strtolower( $connector ) );
delete_option( $opts_name );
}
}
@@ -0,0 +1,37 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Data_Store;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Save_Connector_Settings_Endpoint;
class Plugin_Opts_Data_Store implements Data_Store {
public function get( $setting_name, $connector = 'config', $default = null ) {
$opts = $this->get_opts();
return isset( $opts[ $setting_name ] ) ? $opts[ $setting_name ] : $default;
}
public function save( $setting_name, $value, $connector = 'config' ) {
$opts_name = sprintf( 'gravitysmtp_%s', strtolower( $connector ) );
$opts = $this->get_opts();
$opts[ $setting_name ] = $value;
update_option( $opts_name, json_encode( $opts ) );
}
public function save_all( $value, $connector = 'config' ) {
$opts_name = sprintf( 'gravitysmtp_%s', strtolower( $connector ) );
update_option( $opts_name, json_encode( $value ) );
}
private function get_opts() {
$opts_name = 'gravitysmtp_config';
$opts = get_option( $opts_name, '{}' );
$opts = json_decode( $opts, true );
return $opts;
}
}
@@ -0,0 +1,11 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Data_Store;
interface Data_Store {
public function get( $setting_name, $connector );
public function save( $setting_name, $value, $connector );
}
@@ -0,0 +1,56 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Email_Management;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Email_Management\Config\Managed_Email_Types_Config;
use Gravity_Forms\Gravity_SMTP\Feature_Flags\Feature_Flag_Manager;
use Gravity_Forms\Gravity_SMTP\Managed_Email_Types;
use Gravity_Forms\Gravity_Tools\Providers\Config_Service_Provider;
use Gravity_Forms\Gravity_Tools\Service_Container;
class Email_Management_Service_Provider extends Config_Service_Provider {
const EMAIL_STOPPER = 'email_stopper';
const MANAGED_EMAIL_TYPES = 'managed_email_types';
const MANAGED_EMAIL_TYPES_CONFIG = 'managed_email_types_config';
protected $configs = array(
self::MANAGED_EMAIL_TYPES_CONFIG => Managed_Email_Types_Config::class,
);
public function register( Service_Container $container ) {
parent::register( $container );
$container->add( self::EMAIL_STOPPER, function () use ( $container ) {
return new Email_Stopper( $container->get( Connector_Service_Provider::DATA_STORE_ROUTER ), $container->get( Connector_Service_Provider::DATA_STORE_PLUGIN_OPTS ) );
} );
$container->add( self::MANAGED_EMAIL_TYPES, function () {
$emails = new Managed_Email_Types();
return $emails->types();
} );
}
public function init( \Gravity_Forms\Gravity_Tools\Service_Container $container ) {
$email_types = $container->get( self::MANAGED_EMAIL_TYPES );
/**
* @var Email_Stopper $stopper
*/
$stopper = $container->get( self::EMAIL_STOPPER );
add_action( 'init', function () use ( $stopper, $email_types ) {
foreach ( $email_types as $values ) {
$type = new Managed_Email( $values['key'], $values['label'], $values['description'], $values['category'], $values['disable_callback'] );
$stopper->add( $type );
}
}, 11 );
add_action( 'init', function() use ( $container ) {
$container->get( self::EMAIL_STOPPER )->stop_all();
}, 12 );
}
}
@@ -0,0 +1,129 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Email_Management;
use Gravity_Forms\Gravity_SMTP\Data_Store\Data_Store_Router;
use Gravity_Forms\Gravity_SMTP\Data_Store\Plugin_Opts_Data_Store;
use Gravity_Forms\Gravity_SMTP\Utils\Booliesh;
class Email_Stopper {
protected $category;
protected $key;
/**
* @var Data_Store_Router
*/
protected $data;
/**
* @var Plugin_Opts_Data_Store
*/
protected $data_save;
/**
* @var Managed_Email[]
*/
protected $email_types = array();
public function __construct( Data_Store_Router $data, Plugin_Opts_Data_Store $data_save ) {
$this->data = $data;
$this->data_save = $data_save;
}
public function get_settings_info() {
$info = array();
foreach ( $this->get_email_types() as $type => $data ) {
$category = $data->category();
if ( ! isset( $info[ $category ] ) ) {
$info[ $category ] = array(
'category' => $category,
'items' => array(),
);
}
$info[ $category ]['items'][] = array(
'key' => $data->get_option_key(),
'value' => ! $this->is_blocked( $type ),
'label' => $data->label(),
'description' => $data->description(),
);
}
$info = array_values( $info );
return $info;
}
public function add( Managed_Email $managed_email ) {
$key = $managed_email->key();
$this->email_types[ $key ] = $managed_email;
}
public function remove( $key ) {
unset( $this->email_types[ $key ] );
}
protected function is_blocked( $type ) {
if ( ! isset( $this->get_email_types()[ $type ] ) ) {
return false;
}
$type = $this->get_email_types()[ $type ];
$key = $type->get_option_key();
$allowed = $this->data->get_plugin_setting( $key, true );
return ! Booliesh::get( $allowed );
}
public function block( $type ) {
if ( ! isset( $this->get_email_types()[ $type ] ) ) {
return;
}
$type = $this->get_email_types()[ $type ];
$key = $type->get_option_key();
$this->data_save->save( $key, false );
}
public function allow( $type ) {
if ( ! isset( $this->get_email_types()[ $type ] ) ) {
return;
}
$type = $this->get_email_types()[ $type ];
$key = $type->get_option_key();
$this->data_save->save( $key, true );
}
public function stop_all() {
foreach ( $this->email_types as $type ) {
if ( ! $this->is_blocked( $type->key() ) ) {
continue;
}
$type->trigger_disable_callback();
}
}
public function stop( $type ) {
if ( ! isset( $this->get_email_types()[ $type ] ) ) {
return;
}
$type = $this->get_email_types()[ $type ];
$type->trigger_disable_callback();
}
protected function get_email_types() {
/**
* Allows third-parties to add custom managed email types to the system.
*
* @param array $email_types An array of currently-registered email types.
*
* @return array
*/
return apply_filters( 'gravitysmtp_managed_email_types', $this->email_types );
}
}
@@ -0,0 +1,350 @@
<?php
namespace Gravity_Forms\Gravity_SMTP;
class Managed_Email_Types {
public function types() {
$types = array_merge(
$this->email_type_change_of_admin_email(),
$this->email_type_automatic_updates(),
$this->email_type_comments()
);
if (
( current_user_can( 'manage_sites' )
|| current_user_can( 'create_sites' )
|| current_user_can( 'manage_network' )
|| ( defined( 'GRAVITYSMTP_DISPLAY_ALL_EMAIL_SETTINGS' ) && GRAVITYSMTP_DISPLAY_ALL_EMAIL_SETTINGS ) )
) {
$types = array_merge( $types, $this->email_type_new_site() );
}
$types = array_merge( $types,
$this->email_type_new_user(),
$this->email_type_personal_data_requests(),
$this->email_type_change_of_user_email_password()
);
return $types;
}
private function email_type_change_of_admin_email() {
$items = array(
array(
'key' => 'change_of_site_admin_email_address_is_attempted',
'label' => __( 'Site Admin Email Change Attempt', 'gravitysmtp' ),
'category' => __( 'Admin', 'gravitysmtp' ),
'description' => __( 'Sent to the proposed new Site Admin email address when the Administration Email Address is changed in WordPress General Settings.', 'gravitysmtp' ),
'disable_callback' => function () {
add_action( 'admin_init', function() {
remove_action( 'add_option_new_admin_email', 'update_option_new_admin_email' );
remove_action( 'update_option_new_admin_email', 'update_option_new_admin_email' );
}, 10 );
},
),
array(
'key' => 'site_admin_email_address_is_changed',
'label' => __( 'Site Admin Email Changed', 'gravitysmtp' ),
'category' => __( 'Admin', 'gravitysmtp' ),
'description' => __( 'Sent to the old Site Admin email address when the Administration Email Address change has been confirmed.', 'gravitysmtp' ),
'disable_callback' => function () {
add_filter( 'send_site_admin_email_change_email', '__return_false' );
},
)
);
if ( current_user_can( 'manage_network_users' ) || ( defined( 'GRAVITYSMTP_DISPLAY_ALL_EMAIL_SETTINGS' ) && GRAVITYSMTP_DISPLAY_ALL_EMAIL_SETTINGS ) ) {
$items[] = array(
'key' => 'change_of_network_admin_email_address_is_attempted',
'label' => __( 'Network Admin Email Change Attempt', 'gravitysmtp' ),
'category' => __( 'Admin', 'gravitysmtp' ),
'description' => __( 'Sent to the proposed new Network Admin email address when the Network Admin Email is changed in Network Settings.', 'gravitysmtp' ),
'disable_callback' => function () {
remove_action( 'add_site_option_new_admin_email', 'update_network_option_new_admin_email' );
remove_action( 'update_site_option_new_admin_email', 'update_network_option_new_admin_email' );
},
);
$items[] = array(
'key' => 'network_admin_email_address_is_changed',
'label' => __( 'Network Admin Email Changed', 'gravitysmtp' ),
'category' => __( 'Admin', 'gravitysmtp' ),
'description' => __( 'Sent to the old Network Admin email address when the Network Admin Email change has been confirmed.', 'gravitysmtp' ),
'disable_callback' => function () {
add_filter( 'send_network_admin_email_change_email', '__return_false' );
},
);
}
return $items;
}
private function email_type_change_of_user_email_password() {
return array(
array(
'key' => 'user_or_administrator_requests_a_password_reset',
'label' => __( 'User Password Reset Request', 'gravitysmtp' ),
'category' => __( 'User', 'gravitysmtp' ),
'description' => __( 'Sent to the User email address when a password reset is requested by the User or an administrator.', 'gravitysmtp' ),
'disable_callback' => function () {
add_filter( 'send_retrieve_password_email', '__return_false' );
},
),
array(
'key' => 'user_resets_their_password',
'label' => __( 'User Password Reset', 'gravitysmtp' ),
'category' => __( 'User', 'gravitysmtp' ),
'description' => __( 'Sent to the Site Admin email address when a User resets their password.', 'gravitysmtp' ),
'disable_callback' => function () {
remove_action( 'after_password_reset', 'wp_password_change_notification' );
add_filter( 'woocommerce_disable_password_change_notification', '__return_true' );
},
),
array(
'key' => 'user_changes_their_password',
'label' => __( 'User Password Changed', 'gravitysmtp' ),
'category' => __( 'User', 'gravitysmtp' ),
'description' => __( 'Sent to the User when their password is changed.', 'gravitysmtp' ),
'disable_callback' => function () {
add_filter( 'send_password_change_email', '__return_false' );
},
),
array(
'key' => 'user_attempts_to_change_their_email_address',
'label' => __( 'User Email Change Attempt', 'gravitysmtp' ),
'category' => __( 'User', 'gravitysmtp' ),
'description' => __( 'Sent to the proposed new User email address when a User attempts to change their email address.', 'gravitysmtp' ),
'disable_callback' => function () {
remove_action( 'personal_options_update', 'send_confirmation_on_profile_email' );
},
),
array(
'key' => 'user_changes_their_email_address',
'label' => __( 'User Email Changed', 'gravitysmtp' ),
'category' => __( 'User', 'gravitysmtp' ),
'description' => __( 'Sent to the User email address when they confirm their email address change.', 'gravitysmtp' ),
'disable_callback' => function () {
add_filter( 'send_email_change_email', '__return_false' );
},
),
);
}
private function email_type_personal_data_requests() {
$admin_type = is_multisite() ? __( 'Network Admin', 'gravitysmtp' ) : __( 'Site Admin', 'gravitysmtp' );
return array(
array(
'key' => 'user_confirms_personal_data_export_or_erasure_request',
'label' => __( 'Personal Data Request Confirmation', 'gravitysmtp' ),
'category' => __( 'Personal Data', 'gravitysmtp' ),
'description' => __( 'Sent to the Site Admin email address when a User confirms a Personal Data Export or Erasure Request.', 'gravitysmtp' ),
'disable_callback' => function () {
remove_action( 'user_request_action_confirmed', '_wp_privacy_send_request_confirmation_notification' );
},
),
array(
'key' => 'site_admin_sends_link_to_a_personal_data_export',
'label' => __( 'Personal Data Export Sent', 'gravitysmtp' ),
'category' => __( 'Personal Data', 'gravitysmtp' ),
/* translators: %s: Site Admin or Network Admin */
'description' => sprintf( __( 'Sent to the Requester email address when an administrator responds to a Personal Data Export Request.', 'gravitysmtp' ), $admin_type ),
'disable_callback' => function () {
remove_action( 'wp_privacy_personal_data_export_page', 'wp_privacy_send_personal_data_export_email' );
},
),
array(
'key' => 'site_admin_erases_personal_data_to_fulfill_a_data_erasure_request',
'label' => __( 'Personal Data Erased', 'gravitysmtp' ),
'category' => __( 'Personal Data', 'gravitysmtp' ),
'description' => __( 'Sent to the Requester email address when an administrator has processed a Personal Data Erasure Request.', 'gravitysmtp' ),
'disable_callback' => function () {
remove_action( 'wp_privacy_personal_data_erased', '_wp_privacy_send_erasure_fulfillment_notification' );
},
),
);
}
private function email_type_automatic_updates() {
$admin_type = is_multisite() ? __( 'Network Admin', 'gravitysmtp' ) : __( 'Site Admin', 'gravitysmtp' );
return array(
array(
'key' => 'automatic_plugin_updates',
'label' => __( 'Automatic Plugin Update', 'gravitysmtp' ),
'category' => __( 'Automatic Updates', 'gravitysmtp' ),
/* translators: %s: Site Admin or Network Admin */
'description' => sprintf( __( 'Sent to the %s when a background automatic update to a plugin completes or fails.', 'gravitysmtp' ), $admin_type ),
'disable_callback' => function () {
add_filter( 'auto_plugin_update_send_email', '__return_false' );
},
),
array(
'key' => 'automatic_theme_updates',
'label' => __( 'Automatic Theme Update', 'gravitysmtp' ),
'category' => __( 'Automatic Updates', 'gravitysmtp' ),
/* translators: %s: Site Admin or Network Admin */
'description' => sprintf( __( 'Sent to the %s when a background automatic update to a theme completes or fails.', 'gravitysmtp' ), $admin_type ),
'disable_callback' => function () {
add_filter( 'auto_theme_update_send_email', '__return_false' );
},
),
array(
'key' => 'automatic_core_update',
'label' => __( 'Automatic Core Update', 'gravitysmtp' ),
'category' => __( 'Automatic Updates', 'gravitysmtp' ),
/* translators: %s: Site Admin or Network Admin */
'description' => sprintf( __( 'Sent to the %s when a background automatic update to WordPress core completes or fails.', 'gravitysmtp' ), $admin_type ),
'disable_callback' => function () {
add_filter( 'auto_core_update_send_email', '__return_false' );
add_filter( 'send_core_update_notification_email', '__return_false' );
},
),
array(
'key' => 'full_log_of_background_update_results',
'label' => __( 'Full Background Update Result Log', 'gravitysmtp' ),
'category' => __( 'Automatic Updates', 'gravitysmtp' ),
/* translators: %s: Site Admin or Network Admin */
'description' => sprintf( __( 'Sent to the %s. Only sent when using a development version of WordPress.', 'gravitysmtp' ), $admin_type ),
'disable_callback' => function () {
add_filter( 'automatic_updates_send_debug_email', '__return_false' );
},
),
);
}
private function email_type_new_user() {
$items = array();
if ( current_user_can( 'manage_network_users' ) || ( defined( 'GRAVITYSMTP_DISPLAY_ALL_EMAIL_SETTINGS' ) && GRAVITYSMTP_DISPLAY_ALL_EMAIL_SETTINGS ) ) {
$items[] = array(
'key' => 'a_new_user_is_invited_to_join_a_site',
'label' => __( 'New User Invited to Site', 'gravitysmtp' ),
'category' => __( 'New User', 'gravitysmtp' ),
'description' => __( 'Sent to the User email address when they are invited to join a site.', 'gravitysmtp' ),
'disable_callback' => function () {
add_filter( 'wpmu_signup_user_notification', '__return_false' );
},
);
$items[] = array(
'key' => 'a_new_user_account_is_created',
'label' => __( 'New User Created', 'gravitysmtp' ),
'category' => __( 'New User', 'gravitysmtp' ),
'description' => __( 'Sent to the Network Admin email address when a new user is created via wpmu_create_user().', 'gravitysmtp' ),
'disable_callback' => function () {
remove_action( 'wpmu_new_user', 'newuser_notify_siteadmin' );
},
);
$items[] = array(
'key' => 'a_user_is_added,_or_their_account_activation_is_successful',
'label' => __( 'User Added or Activated', 'gravitysmtp' ),
'category' => __( 'New User', 'gravitysmtp' ),
'description' => __( 'Sent to the User email address when they are added or their account is activated.', 'gravitysmtp' ),
'disable_callback' => function () {
add_filter( 'wpmu_welcome_user_notification', '__return_false' );
},
);
}
$items[] = array(
'key' => 'a_new_user_is_created_admin',
'label' => __( 'New User Admin Notification', 'gravitysmtp' ),
'category' => __( 'New User', 'gravitysmtp' ),
'description' => __( 'Sent to the Site Admin email address when a new user is created.', 'gravitysmtp' ),
'disable_callback' => function () {
add_filter( 'wp_send_new_user_notification_to_admin', '__return_false' );
},
);
$items[] = array(
'key' => 'a_new_user_is_created_user',
'label' => __( 'New User Notification', 'gravitysmtp' ),
'category' => __( 'New User', 'gravitysmtp' ),
'description' => __( 'Sent to the User email address when their account is created.', 'gravitysmtp' ),
'disable_callback' => function () {
add_filter( 'wp_send_new_user_notification_to_user', '__return_false' );
},
);
return $items;
}
private function email_type_comments() {
return array(
array(
'key' => 'comment_is_awaiting_moderation',
'label' => __( 'Comment Awaiting Moderation', 'gravitysmtp' ),
'category' => __( 'Comments', 'gravitysmtp' ),
'description' => __( 'Sent to the Site Admin and Post Author (if they have the ability to edit comments) email address when a user or visitor submits a comment and it is awaiting moderation.', 'gravitysmtp' ),
'disable_callback' => function () {
add_filter( 'notify_moderator', '__return_false' );
},
),
array(
'key' => 'comment_is_published',
'label' => __( 'Comment is Published', 'gravitysmtp' ),
'category' => __( 'Comments', 'gravitysmtp' ),
'description' => __( 'Sent to the Post Author email address when a comment is published.', 'gravitysmtp' ),
'disable_callback' => function () {
add_filter( 'notify_post_author', '__return_false' );
},
),
);
}
private function email_type_new_site() {
$items = array();
if ( current_user_can( 'manage_sites' ) || ( defined( 'GRAVITYSMTP_DISPLAY_ALL_EMAIL_SETTINGS' ) && GRAVITYSMTP_DISPLAY_ALL_EMAIL_SETTINGS ) ) {
$items[] = array(
'key' => 'a_new_site_is_created',
'label' => __( 'New Site Created', 'gravitysmtp' ),
'category' => __( 'New Site', 'gravitysmtp' ),
'description' => __( 'Sent to the Network Admin email address when a New Site is created from Network Admin.', 'gravitysmtp' ),
'disable_callback' => function () {
add_filter( 'send_new_site_email', '__return_false' );
},
);
}
if ( current_user_can( 'create_sites' ) || ( defined( 'GRAVITYSMTP_DISPLAY_ALL_EMAIL_SETTINGS' ) && GRAVITYSMTP_DISPLAY_ALL_EMAIL_SETTINGS ) ) {
$items[] = array(
'key' => 'user_registers_for_a_new_site',
'label' => __( 'User Registers New Site', 'gravitysmtp' ),
'category' => __( 'New Site', 'gravitysmtp' ),
'description' => __( 'Sent to the Site Admin email address when a visitor registers a new user account and site when site registration is enabled.', 'gravitysmtp' ),
'disable_callback' => function () {
add_filter( 'wpmu_signup_blog_notification', '__return_false' );
},
);
}
if ( current_user_can( 'manage_network' ) || ( defined( 'GRAVITYSMTP_DISPLAY_ALL_EMAIL_SETTINGS' ) && GRAVITYSMTP_DISPLAY_ALL_EMAIL_SETTINGS ) ) {
$items[] = array(
'key' => 'user_activates_their_new_site_or_site_added_from_network_admin',
'label' => __( 'New Site Network Admin Notification', 'gravitysmtp' ),
'category' => __( 'New Site', 'gravitysmtp' ),
'description' => __( 'Sent to the Network Admin email address when a user activates a new site, or a site is added from the Network Admin.', 'gravitysmtp' ),
'disable_callback' => function () {
remove_action( 'wpmu_new_blog', 'newblog_notify_siteadmin' );
remove_action( 'wp_initialize_site', 'newblog_notify_siteadmin' );
},
);
}
if ( current_user_can( 'manage_sites' ) || ( defined( 'GRAVITYSMTP_DISPLAY_ALL_EMAIL_SETTINGS' ) && GRAVITYSMTP_DISPLAY_ALL_EMAIL_SETTINGS ) ) {
$items[] = array(
'key' => 'user_activates_their_new_site_or_site_added_from_network_admin_site_admin',
'label' => __( 'New Site Admin Notification', 'gravitysmtp' ),
'category' => __( 'New Site', 'gravitysmtp' ),
'description' => __( 'Sent to new Site Admin email address when user activates a new site, or a site is added from the Network Admin.', 'gravitysmtp' ),
'disable_callback' => function () {
add_filter( 'wpmu_welcome_notification', '__return_false' );
},
);
}
return $items;
}
}
@@ -0,0 +1,81 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Email_Management;
class Managed_Email {
/**
* @var string
*/
protected $key;
/**
* @var string
*/
protected $label;
/**
* @var string
*/
protected $description;
/**
* @var string
*/
protected $category;
/**
* @var callable
*/
protected $disable_callback;
public function __construct( $key, $label, $description, $category, $disable_callback ) {
$this->key = $key;
$this->label = $label;
$this->description = $description;
$this->category = $category;
$this->disable_callback = $disable_callback;
}
/**
* @return string
*/
public function get_option_key() {
return sprintf( 'gravitysmtp_email_stopper_' . $this->key );
}
/**
* @return string
*/
public function key() {
return $this->key;
}
/**
* @return string
*/
public function label() {
return $this->label;
}
/**
* @return string
*/
public function category() {
return $this->category;
}
/**
* @return string
*/
public function description() {
return $this->description;
}
/**
* @return callable
*/
public function trigger_disable_callback() {
return call_user_func( $this->disable_callback );
}
}
@@ -0,0 +1,41 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Email_Management\Config;
use Gravity_Forms\Gravity_SMTP\Apps\App_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Save_Plugin_Settings_Endpoint;
use Gravity_Forms\Gravity_SMTP\Email_Management\Email_Management_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Gravity_SMTP;
use Gravity_Forms\Gravity_Tools\Config;
use Gravity_Forms\Gravity_Tools\License\License_Statuses;
use Gravity_Forms\Gravity_Tools\Updates\Updates_Service_Provider;
use Gravity_Forms\Gravity_Tools\Utils\Utils_Service_Provider;
class Managed_Email_Types_Config extends Config {
protected $script_to_localize = 'gravitysmtp_scripts_admin';
protected $name = 'gravitysmtp_admin_config';
public function should_enqueue() {
$page = filter_input( INPUT_GET, 'page', FILTER_DEFAULT );
return is_admin() && $page === 'gravitysmtp-settings';
}
public function data() {
$container = Gravity_SMTP::container();
$stopper = $container->get( Email_Management_Service_Provider::EMAIL_STOPPER );
return array(
'components' => array(
'settings' => array(
'data' => array(
'managed_email_types' => $stopper->get_settings_info(),
),
),
),
);
}
}
@@ -0,0 +1,29 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Enums;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Save_Connector_Settings_Endpoint;
class Connector_Status_Enum {
const ENABLED = 'enabled';
const PRIMARY = 'primary';
const BACKUP = 'backup';
public static function setting_for_status( $status_type ) {
switch( $status_type ) {
case self::ENABLED:
default:
$setting = Save_Connector_Settings_Endpoint::SETTING_ENABLED_CONNECTOR;
break;
case self::PRIMARY:
$setting = Save_Connector_Settings_Endpoint::SETTING_PRIMARY_CONNECTOR;
break;
case self::BACKUP:
$setting = Save_Connector_Settings_Endpoint::SETTING_BACKUP_CONNECTOR;
}
return $setting;
}
}
@@ -0,0 +1,97 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Enums;
class Integration_Enum {
/**
* Get the title for a given service key.
*
* @param string $service
*
* @return string
*/
public static function title( $service ) {
$title = '';
switch ( $service ) {
case 'amazon-ses':
$title = 'Amazon SES';
break;
case 'brevo':
$title = 'Brevo';
break;
case 'cloudflare':
$title = 'Cloudflare';
break;
case 'generic':
$title = 'Custom SMTP';
break;
case 'elastic_email':
$title = 'Elastic Email';
break;
case 'emailit':
$title = 'Emailit';
break;
case 'google':
$title = 'Google';
break;
case 'mailchimp':
$title = 'Mailchimp';
break;
case 'mailersend':
$title = 'MailerSend';
break;
case 'mailgun':
$title = 'Mailgun';
break;
case 'mailjet':
$title = 'Mailjet';
break;
case 'mandrill':
$title = 'Mandrill';
break;
case 'microsoft':
$title = 'Microsoft';
break;
case 'outlook':
$title = 'Outlook';
break;
case 'postmark':
$title = 'Postmark';
break;
case 'resend':
$title = 'Resend';
break;
case 'sendgrid':
$title = 'SendGrid';
break;
case 'smtp2go':
$title = 'SMTP2GO';
break;
case 'sparkpost':
$title = 'Sparkpost';
break;
case 'zoho-mail':
$title = 'Zoho';
break;
case 'wp_mail':
$title = 'WordPress';
break;
}
return $title;
}
/**
* Get the svg title for the grid cell of an integration.
*
* @param string $service
*
* @return string
*/
public static function svg_title( $service ) {
/* translators: 1: the name of the integration (only used if $service does not equal 'wp_mail'). */
return $service == 'wp_mail' ? esc_html__( 'The default WordPress mailer was used to send this email', 'gravitysmtp' ) : sprintf( esc_html__( 'The %1$s integration was used to send this email', 'gravitysmtp' ), self::title( $service ) );
}
}
@@ -0,0 +1,61 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Enums;
class Status_Enum {
/**
* Get the label for a given status key.
*
* @param string $key
*
* @return string
*/
public static function label( $key ) {
$labels = self::get_labels();
if ( ! isset( $labels[ $key ] ) ) {
return $key;
}
return $labels[ $key ];
}
/**
* Get the indicator type for a given status key.
*
* @param string $key
*
* @return string
*/
public static function indicator( $key ) {
$indicators = self::get_status_map();
if ( ! isset( $indicators[ $key ] ) ) {
return 'error';
}
return $indicators[ $key ];
}
private static function get_status_map() {
return array(
'pending' => 'warning',
'sent' => 'active',
'failed' => 'error',
'sandboxed' => 'warning',
'suppressed' => 'warning',
);
}
private static function get_labels() {
return array(
'pending' => __( 'Pending', 'gravitysmtp' ),
'sent' => __( 'Sent', 'gravitysmtp' ),
'failed' => __( 'Failed', 'gravitysmtp' ),
'sandboxed' => __( 'Sandboxed', 'gravitysmtp' ),
'suppressed' => __( 'Suppressed', 'gravitysmtp' ),
);
}
}
@@ -0,0 +1,53 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Enums;
class Suppression_Reason_Enum {
/**
* Get the label for a given suppression key.
*
* @param string $key
*
* @return string
*/
public static function label( $key ) {
$labels = self::get_labels();
if ( ! isset( $labels[ $key ] ) ) {
return $key;
}
return $labels[ $key ];
}
/**
* Get the indicator type for a given suppression key.
*
* @param string $key
*
* @return string
*/
public static function indicator( $key ) {
$indicators = self::get_status_map();
if ( ! isset( $indicators[ $key ] ) ) {
return 'error';
}
return $indicators[ $key ];
}
private static function get_status_map() {
return array(
'manually_added' => 'warning',
);
}
private static function get_labels() {
return array(
'manually_added' => __( 'Manually Suppressed', 'gravitysmtp' ),
);
}
}
@@ -0,0 +1,55 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Enums;
class Zoho_Datacenters_Enum {
protected static function map() {
return array(
__( 'United States', 'gravitysmtp' ) => 'us',
__( 'Europe', 'gravitysmtp' ) => 'eu',
__( 'India', 'gravitysmtp' ) => 'in',
__( 'Australia', 'gravitysmtp' ) => 'au',
__( 'Japan', 'gravitysmtp' ) => 'jp',
__( 'Canada', 'gravitysmtp' ) => 'ca',
__( 'Saudi Arabia', 'gravitysmtp' ) => 'sa',
);
}
protected static function datacenter_to_url() {
return array(
'us' => 'https://mail.zoho.com',
'eu' => 'https://mail.zoho.uk',
'in' => 'https://mail.zoho.in',
'au' => 'https://mail.zoho.com.au',
'jp' => 'https://mail.zoho.jp',
'ca' => 'https://mail.zoho.ca',
'sa' => 'https://mail.zoho.sa',
);
}
public static function url_for_datacenter( $datacenter ) {
$map = self::datacenter_to_url();
if ( isset( $map[ $datacenter ] ) ) {
return $map[ $datacenter ];
}
return $map['us'];
}
public static function select_component_options() {
$values = self::map();
$return = array();
foreach ( $values as $label => $key ) {
$return[] = array(
'label' => $label,
'value' => $key
);
}
return $return;
}
}
@@ -0,0 +1,15 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Environment;
class Environment_Details {
public function get_min() {
return defined( 'GRAVITYSMTP_SCRIPT_DEBUG' ) && GRAVITYSMTP_SCRIPT_DEBUG ? '' : '.min';
}
public function get_version() {
return defined( 'GRAVITYSMTP_SCRIPT_DEBUG' ) && GRAVITYSMTP_SCRIPT_DEBUG ? time() : time();
}
}
@@ -0,0 +1,33 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Environment;
use Gravity_Forms\Gravity_SMTP\Environment\Config\Environment_Endpoints_Config;
use Gravity_Forms\Gravity_SMTP\Environment\Endpoints\Uninstall_Endpoint;
use Gravity_Forms\Gravity_Tools\Service_Container;
use Gravity_Forms\Gravity_Tools\Providers\Config_Service_Provider;
class Environment_Service_Provider extends Config_Service_Provider {
const UNINSTALL_ENDPOINT = 'uninstall_endpoint';
const ENVIRONMENT_ENDPOINTS_CONFIG = 'environment_endpoints_config';
protected $configs = array(
self::ENVIRONMENT_ENDPOINTS_CONFIG => Environment_Endpoints_Config::class,
);
public function register( Service_Container $container ) {
parent::register( $container );
$container->add( self::UNINSTALL_ENDPOINT, function() {
return new Uninstall_Endpoint();
} );
}
public function init( Service_Container $container ) {
add_action( 'wp_ajax_' . Uninstall_Endpoint::ACTION_NAME, function() use ( $container ) {
$container->get( self::UNINSTALL_ENDPOINT )->handle();
} );
}
}
@@ -0,0 +1,36 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Environment\Config;
use Gravity_Forms\Gravity_SMTP\Environment\Endpoints\Uninstall_Endpoint;
use Gravity_Forms\Gravity_Tools\Config;
class Environment_Endpoints_Config extends Config {
protected $script_to_localize = 'gravitysmtp_scripts_admin';
protected $name = 'gravitysmtp_admin_config';
public function should_enqueue() {
return is_admin();
}
public function data() {
return array(
'common' => array(
'endpoints' => array(
Uninstall_Endpoint::ACTION_NAME => array(
'action' => array(
'value' => Uninstall_Endpoint::ACTION_NAME,
'default' => 'mock_endpoint',
),
'nonce' => array(
'value' => wp_create_nonce( Uninstall_Endpoint::ACTION_NAME ),
'default' => 'nonce',
),
),
),
),
);
}
}
@@ -0,0 +1,53 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Environment\Endpoints;
use Gravity_Forms\Gravity_SMTP\Users\Roles;
use Gravity_Forms\Gravity_Tools\Endpoints\Endpoint;
class Uninstall_Endpoint extends Endpoint {
const ACTION_NAME = 'gravitysmtp_uninstall_plugin';
protected $minimum_cap = Roles::EDIT_UNINSTALL;
public function handle() {
if ( ! current_user_can( Roles::EDIT_UNINSTALL ) ) {
wp_send_json_error( __( 'You do not have permission to perform this action.', 'gravitysmtp' ), 403 );
}
if ( ! $this->validate() ) {
wp_send_json_error( __( 'Missing required parameters.', 'gravitysmtp' ), 400 );
}
$this->delete_options();
$this->delete_tables();
$this->deactivate_plugin();
wp_send_json_success( __( 'Gravity SMTP successfully uninstalled.', 'gravitysmtp' ) );
}
public function get_nonce_name() {
return self::ACTION_NAME;
}
private function delete_options() {
global $wpdb;
$query = $wpdb->prepare( "DELETE FROM {$wpdb->prefix}options WHERE option_name LIKE '%%%s%%'", 'gravitysmtp_' );
$wpdb->query( $query );
$query = $wpdb->prepare( "DELETE FROM {$wpdb->prefix}options WHERE option_name LIKE '%%%s%%'", 'gsmtp_' );
$wpdb->query( $query );
}
private function delete_tables() {
global $wpdb;
$query = "DROP TABLE IF EXISTS {$wpdb->prefix}gravitysmtp_events, {$wpdb->prefix}gravitysmtp_event_logs";
$wpdb->query( $query );
}
private function deactivate_plugin() {
deactivate_plugins( '/gravitysmtp/gravitysmtp.php' );
}
}
@@ -0,0 +1,31 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Errors;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Logging\Logging_Service_Provider;
use Gravity_Forms\Gravity_Tools\Service_Container;
use Gravity_Forms\Gravity_Tools\Service_Provider;
class Error_Handler_Service_Provider extends Service_Provider {
const ERROR_HANDLER = 'error_handler';
public function register( Service_Container $container ) {
$container->add( self::ERROR_HANDLER, function() use ( $container ) {
$event_log_details = $container->get( Logging_Service_Provider::LOGGER );
$events_model = $container->get( Connector_Service_Provider::EVENT_MODEL );
$debug_logger = $container->get( Logging_Service_Provider::DEBUG_LOGGER );
return new Error_Handler( $event_log_details, $events_model, $debug_logger );
});
}
public function init( Service_Container $container ) {
add_filter( 'pre_determine_locale', function( $data ) use ( $container ) {
$container->get( self::ERROR_HANDLER )->handle();
return $data;
});
}
}
@@ -0,0 +1,63 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Errors;
use Gravity_Forms\Gravity_SMTP\Logging\Debug\Debug_Logger;
use Gravity_Forms\Gravity_SMTP\Logging\Log\Logger;
use Gravity_Forms\Gravity_SMTP\Models\Event_Model;
use Gravity_Forms\Gravity_SMTP\Models\Log_Details_Model;
class Error_Handler {
/**
* @var Log_Details_Model
*/
private $logger;
/**
* @var Event_Model
*/
private $events;
/**
* @var Debug_Logger
*/
private $debug_logger;
public function __construct( Logger $logger, Event_Model $events, Debug_Logger $debug_logger ) {
$this->logger = $logger;
$this->events = $events;
$this->debug_logger = $debug_logger;
}
public function handle() {
$error = error_get_last();
if ( ! $error ) {
return;
}
if ( ! in_array( $error['type'], array( E_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR, E_CORE_ERROR ) ) ) {
return;
}
$email_id = $this->events->get_latest_id();
if ( is_null( $email_id ) ) {
return;
}
$error_prefix = __( 'A fatal error occured when sending', 'gravitysmtp' );
$this->logger->log( $email_id, 'failed', sprintf( '%s: %s', $error_prefix, $error['message'] ) );
$this->events->update( array( 'status' => 'failed' ), $email_id );
$this->debug_logger->log_fatal( $error['message'] );
if ( wp_doing_ajax() ) {
wp_send_json_error( sprintf( '%s: %s', $error_prefix, $error['message'] ), 500 );
}
}
}
@@ -0,0 +1,43 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Experimental_Features;
use Gravity_Forms\Gravity_SMTP\Data_Store\Data_Store_Router;
use Gravity_Forms\Gravity_SMTP\Utils\Booliesh;
class Experiment_Features_Handler {
const ENABLED_EXPERIMENTS_PARAM = 'enabled_experimental_features';
protected $experiments = array(
'alerts_management',
);
/**
* @var Data_Store_Router
*/
protected $data_router;
public function __construct( Data_Store_Router $data_router ) {
$this->data_router = $data_router;
}
public function feature_flag_callback( $is_enabled, $flag_slug ) {
if ( ! in_array( $flag_slug, $this->experiments ) ) {
return $is_enabled;
}
$enabled_experiments = $this->data_router->get_plugin_setting( self::ENABLED_EXPERIMENTS_PARAM, array() );
if ( empty( $enabled_experiments ) ) {
return false;
}
if ( ! isset( $enabled_experiments[ $flag_slug ] ) ) {
return false;
}
return Booliesh::get( $enabled_experiments[ $flag_slug ] );
}
}
@@ -0,0 +1,26 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Experimental_Features;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Feature_Flags\Feature_Flag_Repository;
use Gravity_Forms\Gravity_Tools\Service_Container;
use Gravity_Forms\Gravity_Tools\Service_Provider;
class Experimental_Features_Service_Provider extends Service_Provider {
const EXPERIMENTAL_FEATURE_HANDLER = 'experimental_feature_handler';
public function register( Service_Container $container ) {
$container->add( self::EXPERIMENTAL_FEATURE_HANDLER, function() use ( $container ) {
return new Experiment_Features_Handler( $container->get( Connector_Service_Provider::DATA_STORE_ROUTER ) );
} );
}
public function init( Service_Container $container ) {
add_filter( Feature_Flag_Repository::FILTER_SINGLE_FEATURE_FLAG, function( $is_enabled, $flag_slug ) use ( $container ) {
return $container->get( self::EXPERIMENTAL_FEATURE_HANDLER )->feature_flag_callback( $is_enabled, $flag_slug );
}, 10, 2 );
}
}
@@ -0,0 +1,32 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Feature_Flags;
use Gravity_Forms\Gravity_SMTP\Gravity_SMTP;
class Feature_Flag_Manager {
protected $repo;
public function __construct( Feature_Flag_Repository $repo ) {
$this->repo = $repo;
}
public function __call( $name, $arguments ) {
if ( ! method_exists( $this->repo, $name ) ) {
return null;
}
return call_user_func_array( array( $this->repo, $name ), $arguments );
}
public static function __callStatic( $name, $arguments ) {
$self = Gravity_SMTP::$container->get( Feature_Flags_Service_Provider::FEATURE_FLAG_MANAGER );
if ( ! method_exists( $self->repo, $name ) ) {
return null;
}
return call_user_func_array( array( $self->repo, $name ), $arguments );
}
}
@@ -0,0 +1,67 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Feature_Flags;
use Gravity_Forms\Gravity_SMTP\Gravity_SMTP;
class Feature_Flag_Repository {
const FILTER_ALL_FEATURE_FLAGS = 'gravitysmtp_feature_flags';
const FILTER_SINGLE_FEATURE_FLAG = 'gravitysmtp_feature_flag';
public function flags() {
return apply_filters( self::FILTER_ALL_FEATURE_FLAGS, array() );
}
public function add( $flag_slug, $flag_label ) {
add_filter( self::FILTER_ALL_FEATURE_FLAGS, function( $flags ) use ( $flag_slug, $flag_label ) {
$flags[ $flag_slug ] = $flag_label;
return $flags;
} );
}
public function is_enabled( $flag_slug ) {
return apply_filters( self::FILTER_SINGLE_FEATURE_FLAG, false, $flag_slug );
}
public function enable_flag( $flag_slug, $priority = PHP_INT_MAX ) {
add_filter( self::FILTER_SINGLE_FEATURE_FLAG, function ( $is_enabled, $checked_flag ) use ( $flag_slug ) {
if ( $checked_flag === $flag_slug ) {
return true;
}
return $is_enabled;
}, $priority, 2 );
}
public function disable_flag( $flag_slug, $priority = PHP_INT_MAX ) {
add_filter( self::FILTER_SINGLE_FEATURE_FLAG, function ( $is_enabled, $checked_flag ) use ( $flag_slug ) {
if ( $checked_flag === $flag_slug ) {
return false;
}
return $is_enabled;
}, $priority, 2 );
}
public function enabled_flags() {
$all_flags = $this->flags();
$self = $this;
return array_filter( $all_flags, function ( $flag_slug ) use ( $self ) {
return $this->is_enabled( $flag_slug );
}, ARRAY_FILTER_USE_KEY );
}
public function flags_by_status() {
$all_flags = $this->flags();
$response = array();
foreach ( $all_flags as $flag_slug => $label ) {
$response[ $flag_slug ] = $this->is_enabled( $flag_slug );
}
return $response;
}
}
@@ -0,0 +1,36 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Feature_Flags;
use Gravity_Forms\Gravity_SMTP\Feature_Flags\Config\Feature_Flags_Config;
use Gravity_Forms\Gravity_Tools\Providers\Config_Service_Provider;
use Gravity_Forms\Gravity_Tools\Service_Container;
class Feature_Flags_Service_Provider extends Config_Service_Provider {
const FEATURE_FLAG_REPOSITORY = 'feature_flag_repository';
const FEATURE_FLAG_MANAGER = 'feature_flag_manager';
const FEATURE_FLAGS_CONFIG = 'feature_flags_config';
protected $configs = array(
self::FEATURE_FLAGS_CONFIG => Feature_Flags_Config::class,
);
public function register( Service_Container $container ) {
parent::register( $container );
$container->add( self::FEATURE_FLAG_REPOSITORY, function () {
return new Feature_Flag_Repository();
} );
$container->add( self::FEATURE_FLAG_MANAGER, function () use ( $container ) {
return new Feature_Flag_Manager( $container->get( self::FEATURE_FLAG_REPOSITORY ) );
} );
}
public function init( \Gravity_Forms\Gravity_Tools\Service_Container $container ) {
}
}
@@ -0,0 +1,31 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Feature_Flags\Config;
use Gravity_Forms\Gravity_SMTP\Feature_Flags\Feature_Flag_Manager;
use Gravity_Forms\Gravity_Tools\Config;
class Feature_Flags_Config extends Config {
protected $script_to_localize = 'gravitysmtp_scripts_admin';
protected $name = 'gravitysmtp_admin_config';
public function should_enqueue() {
return is_admin();
}
public function data() {
return array(
'common' => array(
'feature_flags' => array(
'data' => array(
'all' => Feature_Flag_Manager::flags(),
'enabled' => Feature_Flag_Manager::enabled_flags(),
'statuses' => Feature_Flag_Manager::flags_by_status(),
),
),
),
);
}
}
@@ -0,0 +1,49 @@
<?php
use Gravity_Forms\Gravity_SMTP\Handler\Handler_Service_Provider;
if ( ! function_exists( 'get_option' ) ) {
return;
}
$is_configured = \Gravity_Forms\Gravity_SMTP\Handler\Mail_Handler::is_minimally_configured();
$test_mode = \Gravity_Forms\Gravity_SMTP\Handler\Mail_Handler::is_test_mode();
if ( ! function_exists( 'wp_mail' ) && $is_configured ) {
function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() ) {
/**
* Perform an action before sending an email.
*
* @param array $atts the attributes sent to wp_mail for this request
*/
do_action( 'gravitysmtp_before_email_send', compact( 'to', 'subject', 'message', 'headers', 'attachments' ) );
if ( \gsmtp_fi_third_party_needs_init() ) {
\Gravity_Forms\Gravity_SMTP\Gravity_SMTP::load_plugin();
}
return \Gravity_Forms\Gravity_SMTP\Gravity_SMTP::container()->get( \Gravity_Forms\Gravity_SMTP\Handler\Handler_Service_Provider::HANDLER )->mail( $to, $subject, $message, $headers, $attachments );
}
}
if ( ! function_exists( 'wp_mail' ) && ! $is_configured && $test_mode ) {
function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() ) {
$test_mode = true;
$atts = apply_filters( 'wp_mail', compact( 'to', 'subject', 'message', 'headers', 'attachments', 'test_mode' ) );
return true;
}
}
if ( ! function_exists( 'gsmtp_fi_third_party_needs_init' ) ) {
function gsmtp_fi_third_party_needs_init() {
$container = \Gravity_Forms\Gravity_SMTP\Gravity_SMTP::container();
$handler = $container->get( Handler_Service_Provider::HANDLER );
if ( ! is_null( $handler ) ) {
return false;
}
return true;
}
}
@@ -0,0 +1,120 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Handler;
use Gravity_Forms\Gravity_SMTP\Apps\App_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Feature_Flags\Feature_Flag_Manager;
use Gravity_Forms\Gravity_SMTP\Handler\Config\Handler_Endpoints_Config;
use Gravity_Forms\Gravity_SMTP\Handler\Endpoints\Resend_Email_Endpoint;
use Gravity_Forms\Gravity_SMTP\Handler\External\Gravity_Forms_Note_Handler;
use Gravity_Forms\Gravity_SMTP\Logging\Logging_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Models\Event_Model;
use Gravity_Forms\Gravity_SMTP\Suppression\Suppression_Service_Provider;
use Gravity_Forms\Gravity_Tools\Providers\Config_Service_Provider;
use Gravity_Forms\Gravity_Tools\Service_Container;
use Gravity_Forms\Gravity_Tools\Utils\Utils_Service_Provider;
class Handler_Service_Provider extends Config_Service_Provider {
const HANDLER = 'mail_handler';
const HANDLER_ENDPOINTS_CONFIG = 'handler_endpoints_config';
const NOTE_HANDLER = 'note_handler';
const RESEND_EMAIL_ENDPOINT = 'resend_email_endpoint';
protected $configs = array(
self::HANDLER_ENDPOINTS_CONFIG => Handler_Endpoints_Config::class,
);
public function register( Service_Container $container ) {
parent::register( $container );
$container->add( self::HANDLER, function () use ( $container ) {
$factory = $container->get( Connector_Service_Provider::CONNECTOR_FACTORY );
$data_store = $container->get( Connector_Service_Provider::DATA_STORE_ROUTER );
$source_parser = $container->get( Utils_Service_Provider::SOURCE_PARSER );
$suppressed_model = $container->get( Suppression_Service_Provider::SUPPRESSED_EMAILS_MODEL );
return new Mail_Handler( $factory, $data_store, $source_parser, $suppressed_model );
} );
$container->add( self::RESEND_EMAIL_ENDPOINT, function () use ( $container ) {
return new Resend_Email_Endpoint( $container->get( Connector_Service_Provider::EVENT_MODEL ), $container->get( Logging_Service_Provider::DEBUG_LOGGER ), $container->get( Utils_Service_Provider::ATTACHMENTS_SAVER ) );
} );
$container->add( self::NOTE_HANDLER, function() {
return new Gravity_Forms_Note_Handler();
} );
}
public function init( Service_Container $container ) {
add_action( 'wp_ajax_' . Resend_Email_Endpoint::ACTION_NAME, function () use ( $container ) {
$container->get( self::RESEND_EMAIL_ENDPOINT )->handle();
} );
if ( ! Feature_Flag_Manager::is_enabled( 'gravityforms_entry_note' ) ) {
return;
}
$is_configured = Mail_Handler::is_minimally_configured();
$test_mode = Mail_Handler::is_test_mode();
if ( ! $is_configured && ! $test_mode ) {
return;
}
/**
* @var Mail_Handler $handler
*/
$handler = $container->get( self::HANDLER );
/**
* @var Event_Model $model
*/
$model = $container->get( Connector_Service_Provider::EVENT_MODEL );
/**
* @var Gravity_Forms_Note_Handler $note_handler
*/
$note_handler = $container->get( self::NOTE_HANDLER );
add_filter( 'gform_pre_send_email', function( $email_args, $format, $notification, $entry ) use ( $handler, $note_handler ) {
$note_handler->store_id( $entry['id'], $handler );
return $email_args;
}, 99, 4 );
add_filter( 'gform_notification_note', function ( $note_args, $entry_id, $result ) use ( $handler, $model, $note_handler ) {
if ( $result !== true ) {
return $note_args;
}
$note_args['text'] = $note_handler->get_modified_entry_note( $note_args['text'], $entry_id, $handler, $model );
return $note_args;
}, 10, 3 );
// When an email fails to send, clear the configuration cache for oauth providers to ensure the UI reflects any errors.
add_action( 'gravitysmtp_on_send_failure', function( $email_id ) use ( $container ) {
$events_model = $container->get( Connector_Service_Provider::EVENT_MODEL );
$event = $events_model->get( $email_id );
// Couldn't find event, bail.
if ( empty( $event ) ) {
return;
}
$service = $event['service'];
// Not an oAuth service, bail.
if ( ! in_array( $service, array( 'google', 'microsoft', 'zoho' ) ) ) {
return;
}
$configured_key = sprintf( 'gsmtp_connector_configured_%s', $service );
delete_transient( $configured_key );
} );
}
}
@@ -0,0 +1,224 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Handler;
use Gravity_Forms\Gravity_SMTP\Apps\Config\Email_Log_Config;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Factory;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Save_Connector_Settings_Endpoint;
use Gravity_Forms\Gravity_SMTP\Connectors\Endpoints\Save_Plugin_Settings_Endpoint;
use Gravity_Forms\Gravity_SMTP\Data_Store\Data_Store_Router;
use Gravity_Forms\Gravity_SMTP\Feature_Flags\Feature_Flag_Manager;
use Gravity_Forms\Gravity_SMTP\Models\Suppressed_Emails_Model;
use Gravity_Forms\Gravity_SMTP\Utils\Source_Parser;
class Mail_Handler {
private static $configuration_status;
/**
* @var Connector_Factory $connector_factory
*/
private $connector_factory;
/**
* @var Data_Store_Router
*/
private $data_store;
/**
* @var Source_Parser
*/
private $source_parser;
/**
* @var Suppressed_Emails_Model
*/
private $suppressed_model;
/**
* @var null A way to store the entry ID being acted upon.
*/
protected $entry_id = null;
public function __construct( $connector_factory, $data_store, $source_parser, $suppressed_model ) {
$this->connector_factory = $connector_factory;
$this->data_store = $data_store;
$this->source_parser = $source_parser;
$this->suppressed_model = $suppressed_model;
}
public function set_entry_id( $entry_id ) {
$this->entry_id = $entry_id;
}
public function get_entry_id() {
return $this->entry_id;
}
private function get_connector( $type ) {
return $this->connector_factory->create( $type );
}
public static function is_minimally_configured() {
if ( ! is_null( self::$configuration_status ) ) {
return self::$configuration_status;
}
if ( defined( 'GRAVITYSMTP_INTEGRATION_PRIMARY' ) ) {
self::$configuration_status = true;
return true;
}
$connectors = self::get_connectors_from_options( Save_Connector_Settings_Endpoint::SETTING_PRIMARY_CONNECTOR );
$configured = ! empty( array_filter( $connectors, function( $enabled ) {
return ! empty( $enabled ) && $enabled !== false && $enabled !== 'false';
} ) );
if ( $configured ) {
self::$configuration_status = true;
return true;
}
$connectors = self::get_connectors_from_options( Save_Connector_Settings_Endpoint::SETTING_BACKUP_CONNECTOR );
$configured = ! empty( array_filter( $connectors, function( $enabled ) {
return ! empty( $enabled ) && $enabled !== false && $enabled !== 'false';
} ) );
self::$configuration_status = $configured;
return $configured;
}
public static function get_connectors_from_options( $type ) {
$opts_name = 'gravitysmtp_config';
$opts = get_option( $opts_name, '{}' );
$opts = json_decode( $opts, true );
return isset( $opts[ $type ] ) ? $opts[ $type ] : array();
}
public static function is_test_mode() {
$opts_name = 'gravitysmtp_config';
$opts = get_option( $opts_name, '{}' );
$opts = json_decode( $opts, true );
$test_mode = isset( $opts[ Save_Plugin_Settings_Endpoint::PARAM_TEST_MODE ] ) ? $opts[ Save_Plugin_Settings_Endpoint::PARAM_TEST_MODE ] : null;
return ! empty( $test_mode ) ? $test_mode !== 'false' : false;
}
public function mail( $to, $subject, $message, $headers = '', $attachments = array() ) {
// Clear sources cache to ensure up-to-date info
delete_transient( Email_Log_Config::SOURCE_LIST_ITEMS_TRANSIENT );
// Re-send attempts put the source in the $headers array.
if ( is_array( $headers ) && isset( $headers['source'] ) ) {
$source = $headers['source'];
} else {
$debug = debug_backtrace();
$source = $this->source_parser->get_source_from_trace( $debug );
}
if ( ! empty( $attachments ) && ! is_array( $attachments ) ) {
$attachments = array( $attachments );
}
/**
* Filters the wp_mail() arguments.
*
* @since 2.2.0
*
* @param array $args A compacted array of wp_mail() arguments, including the "to" email,
* subject, message, headers, and attachments values.
*/
$atts = apply_filters( 'wp_mail', compact( 'to', 'subject', 'message', 'headers', 'attachments' ) );
/**
* Filters whether to preempt sending an email.
*
* Returning a non-null value will short-circuit wp_mail(), returning
* that value instead. A boolean return value should be used to indicate whether
* the email was successfully sent.
*
* @since 1.9.5
*
* @param null|bool $return Short-circuit return value.
* @param array $atts {
* Array of the `wp_mail()` arguments.
*
* @type string|string[] $to Array or comma-separated list of email addresses to send message.
* @type string $subject Email subject.
* @type string $message Message contents.
* @type string|string[] $headers Additional headers.
* @type string|string[] $attachments Paths to files to attach.
* }
*/
$pre_wp_mail = apply_filters( 'pre_wp_mail', null, $atts );
if ( null !== $pre_wp_mail ) {
return $pre_wp_mail;
}
/**
* Allows external code to modify which connector type is used for sending this email.
*
* Used primarily by the Backup Connection and Conditional Routing mechanisms.
*
* @since 1.2
*
* @param $current_type The current type being returned.
* @param $email_data An array of all the email data being used for this call.
*
* @return string $type The connector type to use for sending.
*/
$type = apply_filters( 'gravitysmtp_connector_for_sending', false, array( 'to' => $to, 'subject' => $subject, 'message' => $message, 'headers' => $headers, 'attachments' => $attachments ) );
$skip_retry = false;
if ( is_array( $type ) && isset( $type['force'] ) ) {
$skip_retry = true;
$type = $type['connector'];
}
// Either no connector is defined, or the router has determined that this email shouldn't send.
if ( $type === false ) {
do_action( 'gravitysmtp_on_send_failure', 0 );
return false;
}
$connector = $this->get_connector( $type );
$connector->init( $to, $subject, $message, $headers, $attachments, $source );
$to_email = $connector->get_att( 'to' )->first()->email();
if ( Feature_Flag_Manager::is_enabled( 'email_suppression' ) && $this->suppressed_model->is_email_suppressed( $to_email ) ) {
$connector->handle_suppressed_email( $to_email, $source );
return false;
}
$send = $connector->send();
if ( $send === true ) {
return true;
}
if ( $send !== true && $skip_retry ) {
$failed_email_id = $send;
do_action( 'gravitysmtp_on_send_failure', $failed_email_id );
return false;
}
/**
* Allows third-parties to act when the primary connector has failed.
*
* @param int The ID of the failed email send.
*
* @since 2.2
*
* @return void
*/
do_action( 'gravitysmtp_on_primary_failure', $send );
return $this->mail( $to, $subject, $message, $headers, $attachments );
}
}
@@ -0,0 +1,38 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Handler\Config;
use Gravity_Forms\Gravity_SMTP\Handler\Endpoints\Resend_Email_Endpoint;
use Gravity_Forms\Gravity_Tools\Config;
class Handler_Endpoints_Config extends Config {
protected $script_to_localize = 'gravitysmtp_scripts_admin';
protected $name = 'gravitysmtp_admin_config';
public function should_enqueue() {
return is_admin();
}
public function data() {
return array(
'components' => array(
'activity_log' => array(
'endpoints' => array(
Resend_Email_Endpoint::ACTION_NAME => array(
'action' => array(
'value' => Resend_Email_Endpoint::ACTION_NAME,
'default' => 'mock_endpoint',
),
'nonce' => array(
'value' => wp_create_nonce( Resend_Email_Endpoint::ACTION_NAME ),
'default' => 'nonce',
),
),
),
),
),
);
}
}
@@ -0,0 +1,175 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Handler\Endpoints;
use Gravity_Forms\Gravity_SMTP\Logging\Debug\Debug_Logger;
use Gravity_Forms\Gravity_SMTP\Models\Event_Model;
use Gravity_Forms\Gravity_SMTP\Users\Roles;
use Gravity_Forms\Gravity_SMTP\Utils\Attachments_Saver;
use Gravity_Forms\Gravity_SMTP\Utils\Recipient;
use Gravity_Forms\Gravity_SMTP\Utils\Recipient_Collection;
use Gravity_Forms\Gravity_SMTP\Utils\Recipient_Parser;
use Gravity_Forms\Gravity_Tools\Endpoints\Endpoint;
class Resend_Email_Endpoint extends Endpoint {
const ACTION_NAME = 'gravitysmtp_resend_email';
const PARAM_EMAIL_ID = 'email_id';
// Optional override for recipient address(es) when resending
const PARAM_RECIPIENT = 'recipient';
const PARAM_CC = 'cc';
const PARAM_BCC = 'bcc';
protected $minimum_cap = Roles::EDIT_EMAIL_LOG_DETAILS;
/**
* @var Event_Model
*/
protected $events;
/**
* @var Debug_Logger
*/
protected $logger;
/**
* @var Attachments_Saver
*/
protected $attachments_handler;
protected $required_params = array(
self::PARAM_EMAIL_ID,
);
public function __construct( $event_model, $logger, $attachments_handler ) {
$this->events = $event_model;
$this->logger = $logger;
$this->attachments_handler = $attachments_handler;
}
protected function get_nonce_name() {
return self::ACTION_NAME;
}
public function handle() {
if ( ! $this->validate() ) {
wp_send_json_error( __( 'Missing required parameters.', 'gravitysmtp' ), 400 );
}
$email_id = filter_input( INPUT_POST, self::PARAM_EMAIL_ID, FILTER_SANITIZE_NUMBER_INT );
$email = $this->events->get( $email_id );
$extra = unserialize( $email['extra'], array( 'allowed_classes' => array( Recipient_Collection::class, Recipient::class ) ) );
if ( ! is_array( $extra ) ) {
wp_send_json_error( __( 'Could not read stored email data.', 'gravitysmtp' ) );
}
$headers = $extra['headers'];
// Use SANITIZE_FULL_SPECIAL_CHARS for cc/bcc (plain email lists).
// Use sanitize_text_field for recipient since it may contain mailbox format Name <email>.
$cc_raw = filter_input( INPUT_POST, self::PARAM_CC, FILTER_SANITIZE_FULL_SPECIAL_CHARS );
$bcc_raw = filter_input( INPUT_POST, self::PARAM_BCC, FILTER_SANITIZE_FULL_SPECIAL_CHARS );
$recipient_raw = isset( $_POST[ self::PARAM_RECIPIENT ] ) ? sanitize_text_field( wp_unslash( $_POST[ self::PARAM_RECIPIENT ] ) ) : null;
$to = $extra['to']; // default to original recipient
if ( null !== $recipient_raw ) {
$collection = $this->parse_recipients( $recipient_raw );
if ( is_wp_error( $collection ) ) {
wp_send_json_error( $collection->get_error_message() );
}
$to = $collection->as_string();
}
// Sanity check to ensure we don't try resending an un-sendable email.
if ( ! $email['can_resend'] ) {
// @translators: %s represents the email ID as a numeric string.
$error_message = __( 'Attempted to resend email %s, but could not due to either the message body not being stored, or attachments not being saved.', 'gravitysmtp' );
$this->logger->log_warning( sprintf( $error_message, $email_id ) );
wp_send_json_error( __( 'Email could not be resent as it was not stored with all required values.', 'gravitysmtp' ) );
}
if ( ! empty( $extra['attachments'] ) ) {
foreach( $extra['attachments'] as $key => $og_path ) {
$new_path = $this->attachments_handler->get_saved_attachment( $email_id, $og_path );
$extra['attachments'][ $key ] = $new_path;
}
}
$cc_str = null !== $cc_raw ? trim( $cc_raw ) : '';
if ( $cc_str !== '' ) {
$cc_collection = $this->parse_recipients( $cc_str );
if ( is_wp_error( $cc_collection ) ) {
wp_send_json_error( $cc_collection->get_error_message() );
}
$headers['cc'] = $cc_collection->as_string();
} else {
unset( $headers['cc'] );
}
$bcc_str = null !== $bcc_raw ? trim( $bcc_raw ) : '';
if ( $bcc_str !== '' ) {
$bcc_collection = $this->parse_recipients( $bcc_str );
if ( is_wp_error( $bcc_collection ) ) {
wp_send_json_error( $bcc_collection->get_error_message() );
}
$headers['bcc'] = $bcc_collection->as_string();
} else {
unset( $headers['bcc'] );
}
$headers['source'] = $extra['source'];
foreach ( $headers as $idx => $header ) {
if ( is_a( $header, Recipient_Collection::class ) ) {
$emails = $header->recipients();
$emails_array = array();
foreach ( $emails as $email_recipient ) {
$emails_array[] = $email_recipient->email();
}
$headers[ $idx ] = implode( ', ', $emails_array );
}
}
$success = wp_mail( $to, $email['subject'], $email['message'], $headers, $extra['attachments'] );
if ( ! $success ) {
wp_send_json_error( __( 'Email could not be resent; check your logs for more details.', 'gravitysmtp' ) );
}
wp_send_json_success( $success );
}
/**
* Parse a raw email string into a validated Recipient_Collection.
*
* @since 2.2.0
*
* @param string $raw_value The raw comma-separated email string.
*
* @return Recipient_Collection|\WP_Error Collection of recipients, or WP_Error if empty/invalid.
*/
private function parse_recipients( $raw_value ) {
$parser = new Recipient_Parser();
$collection = $parser->parse( $raw_value );
if ( $collection->count() === 0 ) {
return new \WP_Error( 'empty_email_list', __( 'Email address list is empty.', 'gravitysmtp' ) );
}
// Validate each parsed email address.
foreach ( $collection->recipients() as $recipient ) {
if ( ! is_email( $recipient->email() ) ) {
return new \WP_Error(
'invalid_email',
// translators: %s is the invalid email address.
sprintf( __( 'Invalid email address: %s', 'gravitysmtp' ), $recipient->email() )
);
}
}
return $collection;
}
}
@@ -0,0 +1,35 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Handler\External;
class Gravity_Forms_Note_Handler {
public function store_id( $id, $mail_handler ) {
$mail_handler->set_entry_id( $id );
}
public function get_modified_entry_note( $og_text, $entry_id, $mail_handler, $model ) {
$stored_entry_id = $mail_handler->get_entry_id();
if ( (int) $stored_entry_id !== (int) $entry_id ) {
return $og_text;
}
$email_id = $model->get_latest_id();
if ( empty( $email_id ) ) {
return $og_text;
}
$opening_tag = sprintf( '<a href="%s" target="_blank" style="flex: 0 0 100%%">', admin_url( 'admin.php?page=gravitysmtp-activity-log&tab=log-details&event_id=' . $email_id ) );
// @translators - the first %s represents an opening <a> tag, while the second represents a closing </a> tag.
$smtp_note = __( ' Email sent via Gravity SMTP. %sView Email%s', 'gravitysmtp' );
$smtp_note = sprintf( $smtp_note, $opening_tag, '</a>' );
$new_text = sprintf( '<div><div>%s</div><div>%s</div></div>', $og_text, $smtp_note );
return $new_text;
}
}
@@ -0,0 +1,226 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Logging;
use Gravity_Forms\Gravity_SMTP\Apps\App_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Apps\Config\Tools_Config;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Data_Store\Const_Data_Store;
use Gravity_Forms\Gravity_SMTP\Data_Store\Data_Store_Router;
use Gravity_Forms\Gravity_SMTP\Data_Store\Opts_Data_Store;
use Gravity_Forms\Gravity_SMTP\Data_Store\Plugin_Opts_Data_Store;
use Gravity_Forms\Gravity_SMTP\Handler\Mail_Handler;
use Gravity_Forms\Gravity_SMTP\Logging\Config\Logging_Endpoints_Config;
use Gravity_Forms\Gravity_SMTP\Logging\Debug\Debug_Log_Event_Handler;
use Gravity_Forms\Gravity_SMTP\Logging\Debug\Debug_Logger;
use Gravity_Forms\Gravity_SMTP\Logging\Endpoints\Delete_Debug_Logs_Endpoint;
use Gravity_Forms\Gravity_SMTP\Logging\Endpoints\Delete_Email_Endpoint;
use Gravity_Forms\Gravity_SMTP\Logging\Endpoints\Delete_Events_Endpoint;
use Gravity_Forms\Gravity_SMTP\Logging\Endpoints\Get_Email_Message_Endpoint;
use Gravity_Forms\Gravity_SMTP\Logging\Endpoints\Get_Paginated_Debug_Log_Items_Endpoint;
use Gravity_Forms\Gravity_SMTP\Logging\Endpoints\Get_Paginated_Items_Endpoint;
use Gravity_Forms\Gravity_SMTP\Logging\Endpoints\Log_Item_Endpoint;
use Gravity_Forms\Gravity_SMTP\Logging\Endpoints\View_Log_Endpoint;
use Gravity_Forms\Gravity_SMTP\Logging\Log\Logger;
use Gravity_Forms\Gravity_SMTP\Logging\Log\WP_Mail_Logger;
use Gravity_Forms\Gravity_SMTP\Logging\Scheduling\Handler;
use Gravity_Forms\Gravity_SMTP\Utils\Attachments_Saver;
use Gravity_Forms\Gravity_Tools\Providers\Config_Service_Provider;
use Gravity_Forms\Gravity_Tools\Service_Container;
use Gravity_Forms\Gravity_Tools\Service_Provider;
use Gravity_Forms\Gravity_Tools\Utils\Utils_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Models\Debug_Log_Model;
use Gravity_Forms\Gravity_Tools\Logging\DB_Logging_Provider;
use Gravity_Forms\Gravity_Tools\Logging\Parsers\File_Log_Parser;
class Logging_Service_Provider extends Config_Service_Provider {
const LOGGER = 'logger';
const WP_MAIL_LOGGER = 'wp_mail_logger';
const GET_PAGINATED_ITEMS_ENDPOINT = 'get_paginated_items_endpoint';
const GET_PAGINATED_DEBUG_LOG_ITEMS_ENDPOINT = 'get_paginated_debug_log_items_endpoint';
const DELETE_DEBUG_LOGS_ENDPOINT = 'delete_debug_logs_endpoint';
const DELETE_EMAIL_ENDPOINT = 'delete_email_endpoint';
const DELETE_EVENTS_ENDPOINT = 'delete_events_endpoint';
const GET_EMAIL_MESSAGE_ENDPOINT = 'get_email_message_endpoint';
const SCHEDULING_HANDLER = 'scheduling_handler';
const LOG_ITEM_ENDPOINT = 'log_item_endpoint';
const DEBUG_LOGGER = 'debug_logger_util';
const VIEW_DEBUG_LOG_ENDPOINT = 'view_debug_log_endpoint';
const DEBUG_LOG_DIR = 'debug_log_dir';
const DEBUG_LOG_FILEPATH = 'debug_log_filepath';
const DEBUG_LOG_MODEL = 'debug_log_model';
const DB_LOGGING_PROVIDER = 'db_logging_provider';
const DEBUG_LOG_EVENT_HANDLER = 'debug_log_event_handler';
const LOGGING_ENDPOINTS_CONFIG = 'logging_endpoints_config';
const RETENTION_ACTION_NAME = 'gravitysmtp_scheduler_handle_log_retention';
const DEBUG_LOG_RETENTION_CRON_HOOK = 'gravitysmtp_scheduler_handle_debug_retention';
protected $configs = array(
self::LOGGING_ENDPOINTS_CONFIG => Logging_Endpoints_Config::class,
);
public function register( Service_Container $container ) {
parent::register( $container );
$this->container->add( Connector_Service_Provider::DATA_STORE_CONST, function () {
return new Const_Data_Store();
} );
$this->container->add( Connector_Service_Provider::DATA_STORE_OPTS, function () {
return new Opts_Data_Store();
} );
$this->container->add( Connector_Service_Provider::DATA_STORE_PLUGIN_OPTS, function () {
return new Plugin_Opts_Data_Store();
} );
$this->container->add( Connector_Service_Provider::DATA_STORE_ROUTER, function () use ( $container ) {
return new Data_Store_Router( $container->get( Connector_Service_Provider::DATA_STORE_CONST ), $container->get( Connector_Service_Provider::DATA_STORE_OPTS ), $container->get( Connector_Service_Provider::DATA_STORE_PLUGIN_OPTS ) );
} );
$this->container->add( self::LOGGER, function () use ( $container ) {
return new Logger( $container->get( Connector_Service_Provider::LOG_DETAILS_MODEL ) );
} );
$this->container->add( self::WP_MAIL_LOGGER, function () use ( $container ) {
return new WP_Mail_Logger( $container->get( self::LOGGER ), $container->get( Connector_Service_Provider::EVENT_MODEL ), $container->get( Utils_Service_Provider::SOURCE_PARSER ), $container->get( Utils_Service_Provider::HEADER_PARSER ) );
} );
$this->container->add( self::DEBUG_LOG_MODEL, function () use ( $container ) {
return new Debug_Log_Model();
} );
$this->container->add( self::GET_PAGINATED_ITEMS_ENDPOINT, function () use ( $container ) {
return new Get_Paginated_Items_Endpoint( $container->get( Connector_Service_Provider::EVENT_MODEL ), $container->get( Utils_Service_Provider::RECIPIENT_PARSER ) );
} );
$this->container->add( self::GET_PAGINATED_DEBUG_LOG_ITEMS_ENDPOINT, function () use ( $container ) {
return new Get_Paginated_Debug_Log_Items_Endpoint( $container->get( self::DEBUG_LOG_MODEL ) );
} );
$this->container->add( self::DELETE_DEBUG_LOGS_ENDPOINT, function () use ( $container ) {
return new Delete_Debug_Logs_Endpoint( $container->get( self::DEBUG_LOG_MODEL ) );
} );
$this->container->add( self::DELETE_EMAIL_ENDPOINT, function () use ( $container ) {
return new Delete_Email_Endpoint( $container->get( Connector_Service_Provider::EVENT_MODEL ) );
} );
$this->container->add( self::DELETE_EVENTS_ENDPOINT, function () use ( $container ) {
return new Delete_Events_Endpoint( $container->get( Connector_Service_Provider::EVENT_MODEL ) );
} );
$this->container->add( self::GET_EMAIL_MESSAGE_ENDPOINT, function () use ( $container ) {
return new Get_Email_Message_Endpoint( $container->get( Connector_Service_Provider::EVENT_MODEL ) );
} );
$this->container->add( self::SCHEDULING_HANDLER, function () use ( $container ) {
return new Handler( $container->get( Connector_Service_Provider::DATA_STORE_ROUTER ), $container->get( Connector_Service_Provider::EVENT_MODEL ), $container->get( Connector_Service_Provider::LOG_DETAILS_MODEL ) );
} );
$this->container->add( self::DB_LOGGING_PROVIDER, function () use ( $container ) {
return new DB_Logging_Provider( $container->get( self::DEBUG_LOG_MODEL ) );
} );
$this->container->add( self::DEBUG_LOGGER, function () use ( $container ) {
$data = $container->get( Connector_Service_Provider::DATA_STORE_ROUTER );
$log_level = $data->get_plugin_setting( Tools_Config::SETTING_DEBUG_LOG_LEVEL, DB_Logging_Provider::DEBUG );
return new Debug_Logger( $container->get( self::DB_LOGGING_PROVIDER ), $log_level );
} );
$this->container->add( self::LOG_ITEM_ENDPOINT, function () use ( $container ) {
return new Log_Item_Endpoint( $container->get( self::DEBUG_LOGGER ) );
} );
$this->container->add( self::VIEW_DEBUG_LOG_ENDPOINT, function () use ( $container ) {
$debug_logger = $container->get( self::DEBUG_LOGGER );
$debug_model = $container->get( self::DEBUG_LOG_MODEL );
return new View_Log_Endpoint( $container->get( Connector_Service_Provider::DATA_STORE_ROUTER ), $debug_logger, $debug_model );
} );
$this->container->add( self::DEBUG_LOG_EVENT_HANDLER, function () use ( $container ) {
return new Debug_Log_Event_Handler( $container->get( self::DEBUG_LOGGER ), $container->get( Connector_Service_Provider::DATA_STORE_ROUTER ) );
} );
$this->container->add( Utils_Service_Provider::ATTACHMENTS_SAVER, function () use ( $container ) {
return new Attachments_Saver( $container->get( Logging_Service_Provider::DEBUG_LOGGER ) );
} );
}
public function init( Service_Container $container ) {
add_action( 'wp_ajax_' . Get_Paginated_Items_Endpoint::ACTION_NAME, function () use ( $container ) {
$container->get( self::GET_PAGINATED_ITEMS_ENDPOINT )->handle();
} );
add_action( 'wp_ajax_' . Get_Paginated_Debug_Log_Items_Endpoint::ACTION_NAME, function () use ( $container ) {
$container->get( self::GET_PAGINATED_DEBUG_LOG_ITEMS_ENDPOINT )->handle();
} );
add_action( 'wp_ajax_' . Delete_Debug_Logs_Endpoint::ACTION_NAME, function () use ( $container ) {
$container->get( self::DELETE_DEBUG_LOGS_ENDPOINT )->handle();
} );
add_action( 'wp_ajax_' . Delete_Email_Endpoint::ACTION_NAME, function () use ( $container ) {
$container->get( self::DELETE_EMAIL_ENDPOINT )->handle();
} );
add_action( 'wp_ajax_' . Delete_Events_Endpoint::ACTION_NAME, function () use ( $container ) {
$container->get( self::DELETE_EVENTS_ENDPOINT )->handle();
} );
add_action( 'wp_ajax_' . Get_Email_Message_Endpoint::ACTION_NAME, function () use ( $container ) {
$container->get( self::GET_EMAIL_MESSAGE_ENDPOINT )->handle();
} );
add_action( 'wp_ajax_' . Log_Item_Endpoint::ACTION_NAME, function () use ( $container ) {
$container->get( self::LOG_ITEM_ENDPOINT )->handle();
} );
add_action( 'wp_ajax_' . View_Log_Endpoint::ACTION_NAME, function () use ( $container ) {
$container->get( self::VIEW_DEBUG_LOG_ENDPOINT )->handle();
} );
add_action( 'wp_ajax_nopriv_' . View_Log_Endpoint::ACTION_NAME, function () use ( $container ) {
$container->get( self::VIEW_DEBUG_LOG_ENDPOINT )->handle();
} );
add_action( self::RETENTION_ACTION_NAME, function () use ( $container ) {
return $container->get( self::SCHEDULING_HANDLER )->run_log_retention();
} );
if ( ! Mail_Handler::is_minimally_configured() ) {
add_filter( 'wp_mail', function ( $mail_info ) use ( $container ) {
$container->get( self::WP_MAIL_LOGGER )->create_log( $mail_info );
return $mail_info;
} );
add_action( 'wp_mail_failed', function ( $wp_error ) use ( $container ) {
$container->get( self::WP_MAIL_LOGGER )->handle_failed( $wp_error );
} );
}
if ( ! wp_next_scheduled( self::RETENTION_ACTION_NAME ) ) {
wp_schedule_event( time(), 'daily', self::RETENTION_ACTION_NAME );
}
add_action( 'gravitysmtp_save_plugin_setting', function ( $setting, $value ) use ( $container ) {
$container->get( self::DEBUG_LOG_EVENT_HANDLER )->on_setting_update( $setting, $value );
}, 10, 2 );
if ( ! wp_next_scheduled( self::DEBUG_LOG_RETENTION_CRON_HOOK ) ) {
wp_schedule_event( time(), 'daily', self::DEBUG_LOG_RETENTION_CRON_HOOK );
}
add_action( self::DEBUG_LOG_RETENTION_CRON_HOOK, function () use ( $container ) {
$container->get( self::DEBUG_LOG_EVENT_HANDLER )->on_retention_cron();
} );
}
}
@@ -0,0 +1,102 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Logging\Config;
use Gravity_Forms\Gravity_SMTP\Logging\Endpoints\Delete_Debug_Logs_Endpoint;
use Gravity_Forms\Gravity_SMTP\Logging\Endpoints\Delete_Email_Endpoint;
use Gravity_Forms\Gravity_SMTP\Logging\Endpoints\Delete_Events_Endpoint;
use Gravity_Forms\Gravity_SMTP\Logging\Endpoints\Get_Email_Message_Endpoint;
use Gravity_Forms\Gravity_SMTP\Logging\Endpoints\Get_Paginated_Debug_Log_Items_Endpoint;
use Gravity_Forms\Gravity_SMTP\Logging\Endpoints\Get_Paginated_Items_Endpoint;
use Gravity_Forms\Gravity_SMTP\Logging\Endpoints\Log_Item_Endpoint;
use Gravity_Forms\Gravity_Tools\Config;
class Logging_Endpoints_Config extends Config {
protected $script_to_localize = 'gravitysmtp_scripts_admin';
protected $name = 'gravitysmtp_admin_config';
public function should_enqueue() {
return is_admin();
}
public function data() {
return array(
'common' => array(
'endpoints' => array(
Delete_Email_Endpoint::ACTION_NAME => array(
'action' => array(
'value' => Delete_Email_Endpoint::ACTION_NAME,
'default' => 'mock_endpoint',
),
'nonce' => array(
'value' => wp_create_nonce( Delete_Email_Endpoint::ACTION_NAME ),
'default' => 'nonce',
),
),
Delete_Events_Endpoint::ACTION_NAME => array(
'action' => array(
'value' => Delete_Events_Endpoint::ACTION_NAME,
'default' => 'mock_endpoint',
),
'nonce' => array(
'value' => wp_create_nonce( Delete_Events_Endpoint::ACTION_NAME ),
'default' => 'nonce',
),
),
Get_Email_Message_Endpoint::ACTION_NAME => array(
'action' => array(
'value' => Get_Email_Message_Endpoint::ACTION_NAME,
'default' => 'mock_endpoint',
),
'nonce' => array(
'value' => wp_create_nonce( Get_Email_Message_Endpoint::ACTION_NAME ),
'default' => 'nonce',
),
),
'activity_log_page' => array(
'action' => array(
'value' => Get_Paginated_Items_Endpoint::ACTION_NAME,
'default' => 'mock_endpoint',
),
'nonce' => array(
'value' => wp_create_nonce( Get_Paginated_Items_Endpoint::ACTION_NAME ),
'default' => 'nonce',
),
),
'debug_log_page' => array(
'action' => array(
'value' => Get_Paginated_Debug_Log_Items_Endpoint::ACTION_NAME,
'default' => 'mock_endpoint',
),
'nonce' => array(
'value' => wp_create_nonce( Get_Paginated_Debug_Log_Items_Endpoint::ACTION_NAME ),
'default' => 'nonce',
),
),
Delete_Debug_Logs_Endpoint::ACTION_NAME => array(
'action' => array(
'value' => Delete_Debug_Logs_Endpoint::ACTION_NAME,
'default' => 'mock_endpoint',
),
'nonce' => array(
'value' => wp_create_nonce( Delete_Debug_Logs_Endpoint::ACTION_NAME ),
'default' => 'nonce',
),
),
Log_Item_Endpoint::ACTION_NAME => array(
'action' => array(
'value' => Log_Item_Endpoint::ACTION_NAME,
'default' => 'mock_endpoint',
),
'nonce' => array(
'value' => wp_create_nonce( Log_Item_Endpoint::ACTION_NAME ),
'default' => 'nonce',
),
),
),
),
);
}
}
@@ -0,0 +1,78 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Logging\Debug;
use Gravity_Forms\Gravity_SMTP\Apps\Config\Tools_Config;
use Gravity_Forms\Gravity_SMTP\Data_Store\Data_Store_Router;
use Gravity_Forms\Gravity_SMTP\Gravity_SMTP;
use Gravity_Forms\Gravity_SMTP\Logging\Endpoints\View_Log_Endpoint;
use Gravity_Forms\Gravity_SMTP\Logging\Logging_Service_Provider;
class Debug_Log_Event_Handler {
const DEBUG_LOG_ENABLE_TIME = 'debug_log_enable_time';
/**
* @var Debug_Logger
*/
protected $debug_logger;
/**
* @var Data_Store_Router
*/
protected $data;
public function __construct( Debug_Logger $debug_logger, Data_Store_Router $data ) {
$this->debug_logger = $debug_logger;
$this->data = $data;
}
public function on_setting_update( $setting, $value ) {
if ( $setting !== Tools_Config::SETTING_DEBUG_LOG_ENABLED ) {
return;
}
// Delete verification key when disabled.
if ( $value === false || $value === 0 || $value === '0' || $value === 'false' ) {
delete_option( View_Log_Endpoint::OPTION_VERIFICATION_KEY );
delete_option( self::DEBUG_LOG_ENABLE_TIME );
$delete_log_on_deactivate = apply_filters( 'gravitysmtp_delete_log_on_deactivate', false );
if ( $delete_log_on_deactivate ) {
$this->debug_logger->delete_log();
}
return;
}
// Refresh verficiation key when enabled.
$bytes = random_bytes( 12 );
$random = bin2hex( $bytes );
update_option( View_Log_Endpoint::OPTION_VERIFICATION_KEY, $random );
update_option( self::DEBUG_LOG_ENABLE_TIME, time() );
}
public function on_retention_cron() {
$enabled = get_option( self::DEBUG_LOG_ENABLE_TIME );
if ( empty( $enabled ) ) {
return;
}
$period_in_days = $this->data->get_plugin_setting( Tools_Config::SETTING_DEBUG_LOG_RETENTION, 7 );
$now = date_create( 'now' );
$enabled = date_create( date( 'Y-m-d H:i:s', $enabled ) );
$interval = date_diff( $now, $enabled );
$diff = $interval->format( '%a' );
if ( (int) $diff < (int) $period_in_days ) {
return;
}
$this->debug_logger->delete_log();
}
}
@@ -0,0 +1,73 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Logging\Debug;
use Gravity_Forms\Gravity_SMTP\Apps\Config\Tools_Config;
use Gravity_Forms\Gravity_SMTP\Connectors\Connector_Service_Provider;
use Gravity_Forms\Gravity_SMTP\Gravity_SMTP;
use Gravity_Forms\Gravity_SMTP\Logging\Logging_Service_Provider;
use Gravity_Forms\Gravity_Tools\Logging\DB_Logging_Provider;
use Gravity_Forms\Gravity_Tools\Logging\Logger;
use Gravity_Forms\Gravity_Tools\Logging\Logging_Provider;
class Debug_Logger extends Logger {
protected $log_level;
protected $priority_map = array(
'debug' => DB_Logging_Provider::DEBUG,
'info' => DB_Logging_Provider::INFO,
'warning' => DB_Logging_Provider::WARN,
'error' => DB_Logging_Provider::ERROR,
'fatal' => DB_Logging_Provider::FATAL,
);
public function __construct( Logging_Provider $provider, $log_level ) {
parent::__construct( $provider );
$this->log_level = $log_level;
}
public static function log_message( $message, $priority ) {
$container = Gravity_SMTP::$container;
/**
* @var self $logger
*/
$logger = $container->get( Logging_Service_Provider::DEBUG_LOGGER );
$logger->log( $message, $priority );
}
public function should_log( $log_level = 'all' ) {
$container = Gravity_SMTP::container();
$data = $container->get( Connector_Service_Provider::DATA_STORE_ROUTER );
$enabled = $data->get_plugin_setting( Tools_Config::SETTING_DEBUG_LOG_ENABLED, false );
if ( $enabled === false || $enabled === 0 || $enabled === '0' || $enabled === 'false' ) {
return false;
}
if ( $log_level === 'all' ) {
return true;
}
$level_prio = $this->map_priority_string( $log_level );
return $level_prio >= $this->log_level;
}
public function delete_log() {
$this->provider->delete_log();
}
public function map_priority_string( $priority_string ) {
if ( isset( $this->priority_map[ $priority_string ] ) ) {
return $this->priority_map[ $priority_string ];
}
return DB_Logging_Provider::DEBUG;
}
public function get_log_items() {
return $this->provider->get_lines();
}
}
@@ -0,0 +1,17 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Logging\Debug;
use Gravity_Forms\Gravity_Tools\Logging\Logger;
class Null_Logger extends Logger {
protected function should_log() {
return false;
}
protected function delete_log() {
return;
}
}
@@ -0,0 +1,44 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Logging\Debug;
use Gravity_Forms\Gravity_Tools\Logging\Logging_Provider;
class Null_Logging_Provider implements Logging_Provider {
public function log_info( $line ) {
return;
}
public function log_debug( $line ) {
return;
}
public function log_warning( $line ) {
return;
}
public function log_error( $line ) {
return;
}
public function log_fatal( $line ) {
return;
}
public function log( $line, $priority ) {
return;
}
public function delete_log() {
return;
}
public function write_line_to_log( $line ) {
return;
}
public function get_lines() {
return;
}
}
@@ -0,0 +1,48 @@
<?php
namespace Gravity_Forms\Gravity_SMTP\Logging\Endpoints;
use Gravity_Forms\Gravity_SMTP\Models\Debug_Log_Model;
use Gravity_Forms\Gravity_SMTP\Users\Roles;
use Gravity_Forms\Gravity_Tools\Endpoints\Endpoint;
class Delete_Debug_Logs_Endpoint extends Endpoint {
const PARAM_ALL_LOGS = 'all_logs';
const ACTION_NAME = 'delete_debug_logs';
protected $minimum_cap = Roles::DELETE_DEBUG_LOG;
/**
* @var Debug_Log_Model
*/
protected $logs;
protected $required_params = array(
self::PARAM_ALL_LOGS,
);
public function __construct( Debug_Log_Model $logs ) {
$this->logs = $logs;
}
protected function get_nonce_name() {
return self::ACTION_NAME;
}
public function handle() {
if ( ! $this->validate() ) {
wp_send_json_error( __( 'Missing required parameters.', 'gravitysmtp' ), 400 );
}
$delete_all_logs = filter_input( INPUT_POST, self::PARAM_ALL_LOGS );
$delete_all_logs = htmlspecialchars( $delete_all_logs );
if ( $delete_all_logs == '1' ) {
$this->logs->clear();
wp_send_json_success( array( 'message' => __( 'All logs deleted successfully', 'gravitysmtp' ) ), 200 );
}
}
}

Some files were not shown because too many files have changed in this diff Show More