Post SMTP Mailer/Email Log - Version 1.7.6

Version Description

  • 2017-10-17
  • Missing sendgrid files
  • Fixed: Localization slug
Download this release

Release Info

Developer yehudah
Plugin Icon 128x128 Post SMTP Mailer/Email Log
Version 1.7.6
Comparing to
See all releases

Code changes from version 1.7.5 to 1.7.6

Postman/Postman-Mail/PostmanMyMailConnector.php CHANGED
@@ -1,182 +1,181 @@
1
<?php
2
- define ( 'MYMAIL_POSTMAN_REQUIRED_VERSION', '2.0' );
3
- define ( 'MYMAIL_POSTMAN_ID', 'postman' );
4
5
/**
6
* Enables MyMail to deliver via Postman
7
*
8
* @author jasonhendriks
9
- *
10
*/
11
- if (! class_exists ( 'PostmanMyMailConnector' )) {
12
class PostmanMyMailConnector {
13
-
14
// PostmanLogger
15
private $logger;
16
-
17
/**
18
* No-argument constructor
19
*/
20
- public function __construct($file) {
21
- register_activation_hook ( $file, array (
22
$this,
23
- 'activate'
24
) );
25
- register_deactivation_hook ( $file, array (
26
$this,
27
- 'deactivate'
28
) );
29
-
30
- add_action ( 'init', array (
31
$this,
32
- 'init'
33
), 1 );
34
}
35
-
36
/**
37
* Initialize the Connector
38
*/
39
public function init() {
40
- if (! defined ( 'MYMAIL_VERSION' ) || version_compare ( MYMAIL_POSTMAN_REQUIRED_VERSION, MYMAIL_VERSION, '>' )) {
41
// no-op
42
} else {
43
// create an instance of the Logger
44
- $this->logger = new PostmanLogger ( get_class ( $this ) );
45
- $this->logger->debug ( 'Starting' );
46
-
47
- add_filter ( 'mymail_delivery_methods', array (
48
&$this,
49
- 'delivery_method'
50
) );
51
- add_action ( 'mymail_deliverymethod_tab_postman', array (
52
&$this,
53
- 'deliverytab'
54
) );
55
-
56
- if (mymail_option ( 'deliverymethod' ) == MYMAIL_POSTMAN_ID) {
57
- add_action ( 'mymail_initsend', array (
58
&$this,
59
- 'initsend'
60
) );
61
- add_action ( 'mymail_presend', array (
62
&$this,
63
- 'presend'
64
) );
65
- add_action ( 'mymail_dosend', array (
66
&$this,
67
- 'dosend'
68
) );
69
- add_action ( 'MYMAIL_POSTMAN_cron', array (
70
&$this,
71
- 'reset'
72
) );
73
}
74
}
75
}
76
-
77
/**
78
* initsend function.
79
*
80
* uses mymail_initsend hook to set initial settings
81
*
82
* @access public
83
- * @param mixed $mailobject
84
* @return void
85
*/
86
- public function initsend($mailobject) {
87
- $this->logger->trace ( 'initsend' );
88
// disable dkim
89
$mailobject->dkim = false;
90
}
91
-
92
/**
93
* presend function.
94
*
95
* uses the mymail_presend hook to apply setttings before each mail
96
*
97
* @access public
98
- * @param mixed $mailobject
99
* @return void
100
*/
101
- public function presend($mailobject) {
102
-
103
// embedding images doesn't work
104
$mailobject->embed_images = false;
105
-
106
// use pre_send from the main class
107
// need the raw email body to send so we use the same option
108
- $mailobject->pre_send ();
109
}
110
-
111
/**
112
* dosend function.
113
*
114
* uses the mymail_dosend hook and triggers the send
115
*
116
* @access public
117
- * @param mixed $mailobject
118
* @return void
119
*/
120
- public function dosend($mailobject) {
121
- $this->logger->trace ( 'dosend' );
122
- $this->logger->trace ( $mailobject->mailer );
123
-
124
// create a PostmanWpMail instance
125
- $postmanWpMail = new PostmanWpMail ();
126
- $postmanWpMail->init ();
127
-
128
// create a PostmanMessage instance
129
- $message = $postmanWpMail->createNewMessage ();
130
- $message->addHeaders ( $mailobject->headers );
131
- $message->setBodyTextPart ( $mailobject->mailer->AltBody );
132
- $message->setBodyHtmlPart ( $mailobject->mailer->Body );
133
- $message->setBody ( $mailobject->mailer->AltBody . $mailobject->mailer->Body );
134
- $message->setSubject ( $mailobject->subject );
135
- $message->addTo ( $mailobject->to );
136
- $message->setReplyTo ( $mailobject->reply_to );
137
- $message->setAttachments ( $mailobject->attachments );
138
-
139
// create a PostmanEmailLog instance
140
- $log = new PostmanEmailLog ();
141
-
142
// send the message and store the result
143
- $mailobject->sent = $postmanWpMail->sendMessage ( $message, $log );
144
-
145
// give error message back to MyMail
146
- $result = apply_filters ( 'postman_wp_mail_result', null );
147
- if (! $mailobject->sent) {
148
- $mailobject->set_error ( $result ['exception']->getMessage () );
149
}
150
}
151
-
152
/**
153
* reset function.
154
*
155
* resets the current time
156
*
157
* @access public
158
- * @param mixed $message
159
* @return array
160
*/
161
public function reset() {
162
- update_option ( '_transient__mymail_send_period_timeout', false );
163
- update_option ( '_transient__mymail_send_period', 0 );
164
}
165
-
166
/**
167
* delivery_method function.
168
*
169
* add the delivery method to the options
170
*
171
* @access public
172
- * @param mixed $delivery_methods
173
* @return void
174
*/
175
- public function delivery_method($delivery_methods) {
176
- $delivery_methods [MYMAIL_POSTMAN_ID] = __ ( 'Postman SMTP', Postman::TEXT_DOMAIN );
177
return $delivery_methods;
178
}
179
-
180
/**
181
* deliverytab function.
182
*
@@ -186,9 +185,9 @@ if (! class_exists ( 'PostmanMyMailConnector' )) {
186
* @return void
187
*/
188
public function deliverytab() {
189
- apply_filters ( 'print_postman_status', null );
190
}
191
-
192
/**
193
* activate function.
194
*
@@ -196,12 +195,12 @@ if (! class_exists ( 'PostmanMyMailConnector' )) {
196
* @return void
197
*/
198
public function activate() {
199
- if (defined ( 'MYMAIL_VERSION' ) && version_compare ( MYMAIL_POSTMAN_REQUIRED_VERSION, MYMAIL_VERSION, '<=' )) {
200
- mymail_notice ( sprintf ( __ ( 'MyMail: Change the delivery method in the %s!', Postman::TEXT_DOMAIN ), sprintf ( '<a href="options-general.php?page=newsletter-settings&mymail_remove_notice=mymail_delivery_method#delivery">%s</a>', __ ( 'Settings', 'postman-smtp' ) ) ), '', false, 'delivery_method' );
201
- $this->reset ();
202
}
203
}
204
-
205
/**
206
* deactivate function.
207
*
@@ -209,12 +208,11 @@ if (! class_exists ( 'PostmanMyMailConnector' )) {
209
* @return void
210
*/
211
public function deactivate() {
212
- d;
213
- if (defined ( 'MYMAIL_VERSION' ) && function_exists ( 'mymail_option' ) && version_compare ( MYMAIL_POSTMAN_REQUIRED_VERSION, MYMAIL_VERSION, '<=' )) {
214
- if (mymail_option ( 'deliverymethod' ) == MYMAIL_POSTMAN_ID) {
215
- mymail_update_option ( 'deliverymethod', 'simple' );
216
/* Translators where %s is the name of the page */
217
- mymail_notice ( sprintf ( __ ( 'MyMail: Change the delivery method in the %s!', Postman::TEXT_DOMAIN ), sprintf ( '<a href="options-general.php?page=newsletter-settings&mymail_remove_notice=mymail_delivery_method#delivery">%s</a>', __ ( 'Settings', 'postman-smtp' ) ) ), '', false, 'delivery_method' );
218
}
219
}
220
}
1
<?php
2
+ define( 'MYMAIL_POSTMAN_REQUIRED_VERSION', '2.0' );
3
+ define( 'MYMAIL_POSTMAN_ID', 'postman' );
4
5
/**
6
* Enables MyMail to deliver via Postman
7
*
8
* @author jasonhendriks
9
*/
10
+ if ( ! class_exists( 'PostmanMyMailConnector' ) ) {
11
class PostmanMyMailConnector {
12
+
13
// PostmanLogger
14
private $logger;
15
+
16
/**
17
* No-argument constructor
18
*/
19
+ public function __construct( $file ) {
20
+ register_activation_hook( $file, array(
21
$this,
22
+ 'activate',
23
) );
24
+ register_deactivation_hook( $file, array(
25
$this,
26
+ 'deactivate',
27
) );
28
+
29
+ add_action( 'init', array(
30
$this,
31
+ 'init',
32
), 1 );
33
}
34
+
35
/**
36
* Initialize the Connector
37
*/
38
public function init() {
39
+ if ( ! defined( 'MYMAIL_VERSION' ) || version_compare( MYMAIL_POSTMAN_REQUIRED_VERSION, MYMAIL_VERSION, '>' ) ) {
40
// no-op
41
} else {
42
// create an instance of the Logger
43
+ $this->logger = new PostmanLogger( get_class( $this ) );
44
+ $this->logger->debug( 'Starting' );
45
+
46
+ add_filter( 'mymail_delivery_methods', array(
47
&$this,
48
+ 'delivery_method',
49
) );
50
+ add_action( 'mymail_deliverymethod_tab_postman', array(
51
&$this,
52
+ 'deliverytab',
53
) );
54
+
55
+ if ( mymail_option( 'deliverymethod' ) == MYMAIL_POSTMAN_ID ) {
56
+ add_action( 'mymail_initsend', array(
57
&$this,
58
+ 'initsend',
59
) );
60
+ add_action( 'mymail_presend', array(
61
&$this,
62
+ 'presend',
63
) );
64
+ add_action( 'mymail_dosend', array(
65
&$this,
66
+ 'dosend',
67
) );
68
+ add_action( 'MYMAIL_POSTMAN_cron', array(
69
&$this,
70
+ 'reset',
71
) );
72
}
73
}
74
}
75
+
76
/**
77
* initsend function.
78
*
79
* uses mymail_initsend hook to set initial settings
80
*
81
* @access public
82
+ * @param mixed $mailobject
83
* @return void
84
*/
85
+ public function initsend( $mailobject ) {
86
+ $this->logger->trace( 'initsend' );
87
// disable dkim
88
$mailobject->dkim = false;
89
}
90
+
91
/**
92
* presend function.
93
*
94
* uses the mymail_presend hook to apply setttings before each mail
95
*
96
* @access public
97
+ * @param mixed $mailobject
98
* @return void
99
*/
100
+ public function presend( $mailobject ) {
101
+
102
// embedding images doesn't work
103
$mailobject->embed_images = false;
104
+
105
// use pre_send from the main class
106
// need the raw email body to send so we use the same option
107
+ $mailobject->pre_send();
108
}
109
+
110
/**
111
* dosend function.
112
*
113
* uses the mymail_dosend hook and triggers the send
114
*
115
* @access public
116
+ * @param mixed $mailobject
117
* @return void
118
*/
119
+ public function dosend( $mailobject ) {
120
+ $this->logger->trace( 'dosend' );
121
+ $this->logger->trace( $mailobject->mailer );
122
+
123
// create a PostmanWpMail instance
124
+ $postmanWpMail = new PostmanWpMail();
125
+ $postmanWpMail->init();
126
+
127
// create a PostmanMessage instance
128
+ $message = $postmanWpMail->createNewMessage();
129
+ $message->addHeaders( $mailobject->headers );
130
+ $message->setBodyTextPart( $mailobject->mailer->AltBody );
131
+ $message->setBodyHtmlPart( $mailobject->mailer->Body );
132
+ $message->setBody( $mailobject->mailer->AltBody . $mailobject->mailer->Body );
133
+ $message->setSubject( $mailobject->subject );
134
+ $message->addTo( $mailobject->to );
135
+ $message->setReplyTo( $mailobject->reply_to );
136
+ $message->setAttachments( $mailobject->attachments );
137
+
138
// create a PostmanEmailLog instance
139
+ $log = new PostmanEmailLog();
140
+
141
// send the message and store the result
142
+ $mailobject->sent = $postmanWpMail->sendMessage( $message, $log );
143
+
144
// give error message back to MyMail
145
+ $result = apply_filters( 'postman_wp_mail_result', null );
146
+ if ( ! $mailobject->sent ) {
147
+ $mailobject->set_error( $result ['exception']->getMessage() );
148
}
149
}
150
+
151
/**
152
* reset function.
153
*
154
* resets the current time
155
*
156
* @access public
157
+ * @param mixed $message
158
* @return array
159
*/
160
public function reset() {
161
+ update_option( '_transient__mymail_send_period_timeout', false );
162
+ update_option( '_transient__mymail_send_period', 0 );
163
}
164
+
165
/**
166
* delivery_method function.
167
*
168
* add the delivery method to the options
169
*
170
* @access public
171
+ * @param mixed $delivery_methods
172
* @return void
173
*/
174
+ public function delivery_method( $delivery_methods ) {
175
+ $delivery_methods [ MYMAIL_POSTMAN_ID ] = __( 'Postman SMTP', Postman::TEXT_DOMAIN );
176
return $delivery_methods;
177
}
178
+
179
/**
180
* deliverytab function.
181
*
185
* @return void
186
*/
187
public function deliverytab() {
188
+ apply_filters( 'print_postman_status', null );
189
}
190
+
191
/**
192
* activate function.
193
*
195
* @return void
196
*/
197
public function activate() {
198
+ if ( defined( 'MYMAIL_VERSION' ) && version_compare( MYMAIL_POSTMAN_REQUIRED_VERSION, MYMAIL_VERSION, '<=' ) ) {
199
+ mymail_notice( sprintf( __( 'MyMail: Change the delivery method in the %s!', Postman::TEXT_DOMAIN ), sprintf( '<a href="options-general.php?page=newsletter-settings&mymail_remove_notice=mymail_delivery_method#delivery">%s</a>', __( 'Settings', 'postman-smtp' ) ) ), '', false, 'delivery_method' );
200
+ $this->reset();
201
}
202
}
203
+
204
/**
205
* deactivate function.
206
*
208
* @return void
209
*/
210
public function deactivate() {
211
+ if ( defined( 'MYMAIL_VERSION' ) && function_exists( 'mymail_option' ) && version_compare( MYMAIL_POSTMAN_REQUIRED_VERSION, MYMAIL_VERSION, '<=' ) ) {
212
+ if ( mymail_option( 'deliverymethod' ) == MYMAIL_POSTMAN_ID ) {
213
+ mymail_update_option( 'deliverymethod', 'simple' );
214
/* Translators where %s is the name of the page */
215
+ mymail_notice( sprintf( __( 'MyMail: Change the delivery method in the %s!', Postman::TEXT_DOMAIN ), sprintf( '<a href="options-general.php?page=newsletter-settings&mymail_remove_notice=mymail_delivery_method#delivery">%s</a>', __( 'Settings', 'postman-smtp' ) ) ), '', false, 'delivery_method' );
216
}
217
}
218
}
Postman/Postman.php CHANGED
@@ -15,30 +15,28 @@
15
* @copyright Jan 16, 2015
16
*/
17
class Postman {
18
-
19
- //
20
- const ADMINISTRATOR_ROLE_NAME = 'administrator';
21
const MANAGE_POSTMAN_CAPABILITY_NAME = 'manage_postman_smtp';
22
- const TEXT_DOMAIN = 'postman-smtp';
23
-
24
- //
25
private $logger;
26
private $messageHandler;
27
private $wpMailBinder;
28
private $pluginData;
29
private $rootPluginFilenameAndPath;
30
-
31
/**
32
* The constructor
33
*
34
* @param unknown $rootPluginFilenameAndPath
35
* - the __FILE__ of the caller
36
*/
37
- public function __construct($rootPluginFilenameAndPath, $version) {
38
- assert ( ! empty ( $rootPluginFilenameAndPath ) );
39
- assert ( ! empty ( $version ) );
40
$this->rootPluginFilenameAndPath = $rootPluginFilenameAndPath;
41
-
42
// load the dependencies
43
require_once 'PostmanOptions.php';
44
require_once 'PostmanState.php';
@@ -55,88 +53,88 @@ class Postman {
55
require_once 'PostmanConfigTextHelper.php';
56
require_once 'Postman-Email-Log/PostmanEmailLogPostType.php';
57
require_once 'Postman-Mail/PostmanMyMailConnector.php';
58
-
59
// get plugin metadata - alternative to get_plugin_data
60
- $this->pluginData = array (
61
- 'name' => __ ( 'Postman SMTP', Postman::TEXT_DOMAIN ),
62
- 'version' => $version
63
);
64
-
65
// register the plugin metadata filter (part of the Postman API)
66
- add_filter ( 'postman_get_plugin_metadata', array (
67
$this,
68
- 'getPluginMetaData'
69
) );
70
-
71
// create an instance of the logger
72
- $this->logger = new PostmanLogger ( get_class ( $this ) );
73
- if ($this->logger->isDebug ()) {
74
- $this->logger->debug ( sprintf ( '%1$s v%2$s starting', $this->pluginData ['name'], $this->pluginData ['version'] ) );
75
}
76
-
77
- if (isset ( $_REQUEST ['page'] ) && $this->logger->isTrace ()) {
78
- $this->logger->trace ( 'Current page: ' . $_REQUEST ['page'] );
79
}
80
-
81
// register the email transports
82
- $this->registerTransports ( $rootPluginFilenameAndPath );
83
-
84
// store an instance of the WpMailBinder
85
- $this->wpMailBinder = PostmanWpMailBinder::getInstance ();
86
-
87
// bind to wp_mail - this has to happen before the "init" action
88
// this design allows other plugins to register a Postman transport and call bind()
89
// bind may be called more than once
90
- $this->wpMailBinder->bind ();
91
-
92
// registers the custom post type for all callers
93
- PostmanEmailLogPostType::automaticallyCreatePostType ();
94
-
95
// run the DatastoreUpgrader any time there is a version mismatch
96
- if (PostmanState::getInstance ()->getVersion () != $this->pluginData ['version']) {
97
// manually trigger the activation hook
98
- if ($this->logger->isInfo ()) {
99
- $this->logger->info ( sprintf ( "Upgrading datastore from version %s to %s", PostmanState::getInstance ()->getVersion (), $this->pluginData ['version'] ) );
100
}
101
require_once 'PostmanInstaller.php';
102
- $upgrader = new PostmanInstaller ();
103
- $upgrader->activatePostman ();
104
}
105
-
106
// MyMail integration
107
- new PostmanMyMailConnector ( $rootPluginFilenameAndPath );
108
-
109
// register the shortcode handler on the add_shortcode event
110
- add_shortcode ( 'postman-version', array (
111
$this,
112
- 'version_shortcode'
113
) );
114
-
115
// hook on the plugins_loaded event
116
- add_action ( 'plugins_loaded', array (
117
$this,
118
- 'on_plugins_loaded'
119
) );
120
-
121
// hook on the wp_loaded event
122
- add_action ( 'wp_loaded', array (
123
$this,
124
- 'on_wp_loaded'
125
) );
126
-
127
// hook on the acivation event
128
- register_activation_hook ( $rootPluginFilenameAndPath, array (
129
$this,
130
- 'on_activation'
131
) );
132
-
133
// hook on the deactivation event
134
- register_deactivation_hook ( $rootPluginFilenameAndPath, array (
135
$this,
136
- 'on_deactivation'
137
) );
138
}
139
-
140
/**
141
* Functions to execute on the plugins_loaded event
142
*
@@ -145,15 +143,15 @@ class Postman {
145
*/
146
public function on_plugins_loaded() {
147
// load the text domain
148
- $this->loadTextDomain ();
149
-
150
// register the setup_admin function on plugins_loaded because we need to call
151
// current_user_can to verify the capability of the current user
152
- if (PostmanUtils::isAdmin () && is_admin ()) {
153
- $this->setup_admin ();
154
}
155
}
156
-
157
/**
158
* Functions to execute on the wp_loaded event
159
*
@@ -163,45 +161,45 @@ class Postman {
163
public function on_wp_loaded() {
164
// register the check for configuration errors on the wp_loaded hook,
165
// because we want it to run after the OAuth Grant Code check on the init hook
166
- $this->check_for_configuration_errors ();
167
}
168
-
169
/**
170
* Functions to execute on the register_activation_hook
171
* ref: https://codex.wordpress.org/Function_Reference/register_activation_hook
172
*/
173
public function on_activation() {
174
- if ($this->logger->isInfo ()) {
175
- $this->logger->info ( 'Activating plugin' );
176
}
177
require_once 'PostmanInstaller.php';
178
- $upgrader = new PostmanInstaller ();
179
- $upgrader->activatePostman ();
180
}
181
-
182
/**
183
* Functions to execute on the register_deactivation_hook
184
* ref: https://codex.wordpress.org/Function_Reference/register_deactivation_hook
185
*/
186
public function on_deactivation() {
187
- if ($this->logger->isInfo ()) {
188
- $this->logger->info ( 'Deactivating plugin' );
189
}
190
require_once 'PostmanInstaller.php';
191
- $upgrader = new PostmanInstaller ();
192
- $upgrader->deactivatePostman ();
193
}
194
-
195
/**
196
* If the user is on the WordPress Admin page, creates the Admin screens
197
*/
198
public function setup_admin() {
199
- $this->logger->debug ( 'Admin start-up sequence' );
200
-
201
- $options = PostmanOptions::getInstance ();
202
- $authToken = PostmanOAuthToken::getInstance ();
203
$rootPluginFilenameAndPath = $this->rootPluginFilenameAndPath;
204
-
205
// load the dependencies
206
require_once 'PostmanMessageHandler.php';
207
require_once 'PostmanAdminController.php';
@@ -212,85 +210,83 @@ class Postman {
212
require_once 'Postman-Configuration/PostmanConfigurationController.php';
213
require_once 'Postman-Send-Test-Email/PostmanSendTestEmailController.php';
214
require_once 'Postman-Diagnostic-Test/PostmanDiagnosticTestController.php';
215
-
216
// create and store an instance of the MessageHandler
217
- $this->messageHandler = new PostmanMessageHandler ();
218
-
219
// create the Admin Controllers
220
- new PostmanDashboardWidgetController ( $rootPluginFilenameAndPath, $options, $authToken, $this->wpMailBinder );
221
- new PostmanAdminController ( $rootPluginFilenameAndPath, $options, $authToken, $this->messageHandler, $this->wpMailBinder );
222
- new PostmanEmailLogController ( $rootPluginFilenameAndPath );
223
- new PostmanConnectivityTestController ( $rootPluginFilenameAndPath );
224
- new PostmanConfigurationController ( $rootPluginFilenameAndPath );
225
- new PostmanSendTestEmailController ( $rootPluginFilenameAndPath );
226
- new PostmanDiagnosticTestController ( $rootPluginFilenameAndPath );
227
-
228
// register the Postman signature (only if we're on a postman admin screen) on the in_admin_footer event
229
- if (PostmanUtils::isCurrentPagePostmanAdmin ()) {
230
- add_action ( 'in_admin_footer', array (
231
$this,
232
- 'print_signature'
233
) );
234
}
235
}
236
-
237
/**
238
* Check for configuration errors and displays messages to the user
239
*/
240
public function check_for_configuration_errors() {
241
- $options = PostmanOptions::getInstance ();
242
- $authToken = PostmanOAuthToken::getInstance ();
243
-
244
// did Postman fail binding to wp_mail()?
245
- if ($this->wpMailBinder->isUnboundDueToException ()) {
246
// this message gets printed on ANY WordPress admin page, as it's a fatal error that
247
// may occur just by activating a new plugin
248
-
249
// log the fatal message
250
- $this->logger->fatal ( 'Postman: wp_mail has been declared by another plugin or theme, so you won\'t be able to use Postman until the conflict is resolved.' );
251
-
252
- if (PostmanUtils::isAdmin () && is_admin ()) {
253
// on any admin pages, show this error message
254
-
255
// I noticed the wpMandrill and SendGrid plugins have the exact same error message here
256
// I've adopted their error message as well, for shits and giggles .... :D
257
- $message = __ ( 'Postman: wp_mail has been declared by another plugin or theme, so you won\'t be able to use Postman until the conflict is resolved.', Postman::TEXT_DOMAIN );
258
- $this->messageHandler->addError ( $message );
259
}
260
} else {
261
- $transport = PostmanTransportRegistry::getInstance ()->getCurrentTransport ();
262
- $scribe = $transport->getScribe ();
263
-
264
- $virgin = $options->isNew ();
265
- if (! $transport->isConfiguredAndReady ()) {
266
// if the configuration is broken, and the user has started to configure the plugin
267
// show this error message
268
- $messages = $transport->getConfigurationMessages ();
269
foreach ( $messages as $message ) {
270
- if ($message) {
271
// log the warning message
272
- $this->logger->warn ( sprintf ( '%s Transport has a configuration problem: %s', $transport->getName (), $message ) );
273
-
274
- if (PostmanUtils::isAdmin () && PostmanUtils::isCurrentPagePostmanAdmin ()) {
275
// on pages that are Postman admin pages only, show this error message
276
- $this->messageHandler->addError ( $message );
277
}
278
}
279
}
280
}
281
-
282
// on pages that are NOT Postman admin pages only, show this error message
283
- if (PostmanUtils::isAdmin () && ! PostmanUtils::isCurrentPagePostmanAdmin () && ! $transport->isConfiguredAndReady ()) {
284
// on pages that are *NOT* Postman admin pages only....
285
// if the configuration is broken show this error message
286
- add_action ( 'admin_notices', Array (
287
$this,
288
- 'display_configuration_required_warning'
289
) );
290
}
291
}
292
}
293
-
294
/**
295
* Returns the plugin version number and name
296
* Part of the Postman API
@@ -301,74 +297,74 @@ class Postman {
301
// get plugin metadata
302
return $this->pluginData;
303
}
304
-
305
/**
306
* This is the general message that Postman requires configuration, to warn users who think
307
* the plugin is ready-to-go as soon as it is activated.
308
* This message only goes away once the plugin is configured.
309
*/
310
public function display_configuration_required_warning() {
311
- if (PostmanUtils::isAdmin ()) {
312
- if ($this->logger->isDebug ()) {
313
- $this->logger->debug ( 'Displaying configuration required warning' );
314
}
315
- $message = sprintf ( PostmanTransportRegistry::getInstance ()->getReadyMessage () );
316
- $goToSettings = sprintf ( '<a href="%s">%s</a>', PostmanUtils::getSettingsPageUrl (), __ ( 'Settings', Postman::TEXT_DOMAIN ) );
317
- $goToEmailLog = sprintf ( '%s', _x ( 'Email Log', 'The log of Emails that have been delivered', Postman::TEXT_DOMAIN ) );
318
- if (PostmanOptions::getInstance ()->isMailLoggingEnabled ()) {
319
- $goToEmailLog = sprintf ( '<a href="%s">%s</a>', PostmanUtils::getEmailLogPageUrl (), $goToEmailLog );
320
}
321
- $message .= (sprintf ( ' %s | %s', $goToEmailLog, $goToSettings ));
322
;
323
- $this->messageHandler->printMessage ( $message, PostmanMessageHandler::WARNING_CLASS );
324
}
325
}
326
-
327
/**
328
* Register the email transports.
329
*
330
* The Gmail API used to be a separate plugin which was registered when that plugin
331
* was loaded. But now both the SMTP, Gmail API and other transports are registered here.
332
*
333
- * @param unknown $pluginData
334
*/
335
- private function registerTransports($rootPluginFilenameAndPath) {
336
- PostmanTransportRegistry::getInstance ()->registerTransport ( new PostmanDefaultModuleTransport ( $rootPluginFilenameAndPath ) );
337
- PostmanTransportRegistry::getInstance ()->registerTransport ( new PostmanSmtpModuleTransport ( $rootPluginFilenameAndPath ) );
338
- PostmanTransportRegistry::getInstance ()->registerTransport ( new PostmanGmailApiModuleTransport ( $rootPluginFilenameAndPath ) );
339
- PostmanTransportRegistry::getInstance ()->registerTransport ( new PostmanMandrillTransport ( $rootPluginFilenameAndPath ) );
340
- PostmanTransportRegistry::getInstance ()->registerTransport ( new PostmanSendGridTransport ( $rootPluginFilenameAndPath ) );
341
}
342
-
343
/**
344
* Print the Postman signature on the bottom of the page
345
*
346
* http://striderweb.com/nerdaphernalia/2008/06/give-your-wordpress-plugin-credit/
347
*/
348
function print_signature() {
349
- printf ( '<a href="https://wordpress.org/plugins/postman-smtp/">%s</a> %s<br/>', $this->pluginData ['name'], $this->pluginData ['version'] );
350
}
351
-
352
/**
353
* Loads the appropriate language file
354
*/
355
private function loadTextDomain() {
356
// had to hardcode the third parameter, Relative path to WP_PLUGIN_DIR,
357
// because __FILE__ returns the wrong path if the plugin is installed as a symlink
358
- $shortLocale = substr ( get_locale (), 0, 2 );
359
- if ($shortLocale != 'en') {
360
$langDir = 'postman-smtp/Postman/languages';
361
- $success = load_plugin_textdomain ( Postman::TEXT_DOMAIN, false, $langDir );
362
- if ($this->logger->isDebug ()) {
363
- if ($success) {
364
- $this->logger->debug ( sprintf ( 'local translation file loaded for locale=%s', get_locale () ) );
365
} else {
366
- $this->logger->debug ( sprintf ( 'failed to load local translation file: locale=%s file=%s/%s-%s.mo', get_locale (), $langDir, Postman::TEXT_DOMAIN, get_locale () ) );
367
}
368
}
369
}
370
}
371
-
372
/**
373
* Shortcode to return the current plugin version.
374
*
@@ -381,19 +377,19 @@ class Postman {
381
}
382
}
383
384
- if (! function_exists ( 'str_getcsv' )) {
385
/**
386
* PHP version less than 5.3 don't have str_getcsv natively.
387
*
388
- * @param unknown $string
389
* @return multitype:
390
*/
391
- function str_getcsv($string) {
392
- $logger = new PostmanLogger ( 'postman-common-functions' );
393
- if ($logger->isDebug ()) {
394
- $logger->debug ( 'Using custom str_getcsv' );
395
}
396
- return PostmanUtils::postman_strgetcsv_impl ( $string );
397
}
398
}
399
15
* @copyright Jan 16, 2015
16
*/
17
class Postman {
18
+
19
+ const ADMINISTRATOR_ROLE_NAME = 'administrator';
20
const MANAGE_POSTMAN_CAPABILITY_NAME = 'manage_postman_smtp';
21
+ const TEXT_DOMAIN = 'post-smtp';
22
+
23
private $logger;
24
private $messageHandler;
25
private $wpMailBinder;
26
private $pluginData;
27
private $rootPluginFilenameAndPath;
28
+
29
/**
30
* The constructor
31
*
32
* @param unknown $rootPluginFilenameAndPath
33
* - the __FILE__ of the caller
34
*/
35
+ public function __construct( $rootPluginFilenameAndPath, $version ) {
36
+ assert( ! empty( $rootPluginFilenameAndPath ) );
37
+ assert( ! empty( $version ) );
38
$this->rootPluginFilenameAndPath = $rootPluginFilenameAndPath;
39
+
40
// load the dependencies
41
require_once 'PostmanOptions.php';
42
require_once 'PostmanState.php';
53
require_once 'PostmanConfigTextHelper.php';
54
require_once 'Postman-Email-Log/PostmanEmailLogPostType.php';
55
require_once 'Postman-Mail/PostmanMyMailConnector.php';
56
+
57
// get plugin metadata - alternative to get_plugin_data
58
+ $this->pluginData = array(
59
+ 'name' => __( 'Postman SMTP', Postman::TEXT_DOMAIN ),
60
+ 'version' => $version,
61
);
62
+
63
// register the plugin metadata filter (part of the Postman API)
64
+ add_filter( 'postman_get_plugin_metadata', array(
65
$this,
66
+ 'getPluginMetaData',
67
) );
68
+
69
// create an instance of the logger
70
+ $this->logger = new PostmanLogger( get_class( $this ) );
71
+ if ( $this->logger->isDebug() ) {
72
+ $this->logger->debug( sprintf( '%1$s v%2$s starting', $this->pluginData ['name'], $this->pluginData ['version'] ) );
73
}
74
+
75
+ if ( isset( $_REQUEST ['page'] ) && $this->logger->isTrace() ) {
76
+ $this->logger->trace( 'Current page: ' . $_REQUEST ['page'] );
77
}
78
+
79
// register the email transports
80
+ $this->registerTransports( $rootPluginFilenameAndPath );
81
+
82
// store an instance of the WpMailBinder
83
+ $this->wpMailBinder = PostmanWpMailBinder::getInstance();
84
+
85
// bind to wp_mail - this has to happen before the "init" action
86
// this design allows other plugins to register a Postman transport and call bind()
87
// bind may be called more than once
88
+ $this->wpMailBinder->bind();
89
+
90
// registers the custom post type for all callers
91
+ PostmanEmailLogPostType::automaticallyCreatePostType();
92
+
93
// run the DatastoreUpgrader any time there is a version mismatch
94
+ if ( PostmanState::getInstance()->getVersion() != $this->pluginData ['version'] ) {
95
// manually trigger the activation hook
96
+ if ( $this->logger->isInfo() ) {
97
+ $this->logger->info( sprintf( 'Upgrading datastore from version %s to %s', PostmanState::getInstance()->getVersion(), $this->pluginData ['version'] ) );
98
}
99
require_once 'PostmanInstaller.php';
100
+ $upgrader = new PostmanInstaller();
101
+ $upgrader->activatePostman();
102
}
103
+
104
// MyMail integration
105
+ new PostmanMyMailConnector( $rootPluginFilenameAndPath );
106
+
107
// register the shortcode handler on the add_shortcode event
108
+ add_shortcode( 'postman-version', array(
109
$this,
110
+ 'version_shortcode',
111
) );
112
+
113
// hook on the plugins_loaded event
114
+ add_action( 'plugins_loaded', array(
115
$this,
116
+ 'on_plugins_loaded',
117
) );
118
+
119
// hook on the wp_loaded event
120
+ add_action( 'wp_loaded', array(
121
$this,
122
+ 'on_wp_loaded',
123
) );
124
+
125
// hook on the acivation event
126
+ register_activation_hook( $rootPluginFilenameAndPath, array(
127
$this,
128
+ 'on_activation',
129
) );
130
+
131
// hook on the deactivation event
132
+ register_deactivation_hook( $rootPluginFilenameAndPath, array(
133
$this,
134
+ 'on_deactivation',
135
) );
136
}
137
+
138
/**
139
* Functions to execute on the plugins_loaded event
140
*
143
*/
144
public function on_plugins_loaded() {
145
// load the text domain
146
+ $this->loadTextDomain();
147
+
148
// register the setup_admin function on plugins_loaded because we need to call
149
// current_user_can to verify the capability of the current user
150
+ if ( PostmanUtils::isAdmin() && is_admin() ) {
151
+ $this->setup_admin();
152
}
153
}
154
+
155
/**
156
* Functions to execute on the wp_loaded event
157
*
161
public function on_wp_loaded() {
162
// register the check for configuration errors on the wp_loaded hook,
163
// because we want it to run after the OAuth Grant Code check on the init hook
164
+ $this->check_for_configuration_errors();
165
}
166
+
167
/**
168
* Functions to execute on the register_activation_hook
169
* ref: https://codex.wordpress.org/Function_Reference/register_activation_hook
170
*/
171
public function on_activation() {
172
+ if ( $this->logger->isInfo() ) {
173
+ $this->logger->info( 'Activating plugin' );
174
}
175
require_once 'PostmanInstaller.php';
176
+ $upgrader = new PostmanInstaller();
177
+ $upgrader->activatePostman();
178
}
179
+
180
/**
181
* Functions to execute on the register_deactivation_hook
182
* ref: https://codex.wordpress.org/Function_Reference/register_deactivation_hook
183
*/
184
public function on_deactivation() {
185
+ if ( $this->logger->isInfo() ) {
186
+ $this->logger->info( 'Deactivating plugin' );
187
}
188
require_once 'PostmanInstaller.php';
189
+ $upgrader = new PostmanInstaller();
190
+ $upgrader->deactivatePostman();
191
}
192
+
193
/**
194
* If the user is on the WordPress Admin page, creates the Admin screens
195
*/
196
public function setup_admin() {
197
+ $this->logger->debug( 'Admin start-up sequence' );
198
+
199
+ $options = PostmanOptions::getInstance();
200
+ $authToken = PostmanOAuthToken::getInstance();
201
$rootPluginFilenameAndPath = $this->rootPluginFilenameAndPath;
202
+
203
// load the dependencies
204
require_once 'PostmanMessageHandler.php';
205
require_once 'PostmanAdminController.php';
210
require_once 'Postman-Configuration/PostmanConfigurationController.php';
211
require_once 'Postman-Send-Test-Email/PostmanSendTestEmailController.php';
212
require_once 'Postman-Diagnostic-Test/PostmanDiagnosticTestController.php';
213
+
214
// create and store an instance of the MessageHandler
215
+ $this->messageHandler = new PostmanMessageHandler();
216
+
217
// create the Admin Controllers
218
+ new PostmanDashboardWidgetController( $rootPluginFilenameAndPath, $options, $authToken, $this->wpMailBinder );
219
+ new PostmanAdminController( $rootPluginFilenameAndPath, $options, $authToken, $this->messageHandler, $this->wpMailBinder );
220
+ new PostmanEmailLogController( $rootPluginFilenameAndPath );
221
+ new PostmanConnectivityTestController( $rootPluginFilenameAndPath );
222
+ new PostmanConfigurationController( $rootPluginFilenameAndPath );
223
+ new PostmanSendTestEmailController( $rootPluginFilenameAndPath );
224
+ new PostmanDiagnosticTestController( $rootPluginFilenameAndPath );
225
+
226
// register the Postman signature (only if we're on a postman admin screen) on the in_admin_footer event
227
+ if ( PostmanUtils::isCurrentPagePostmanAdmin() ) {
228
+ add_action( 'in_admin_footer', array(
229
$this,
230
+ 'print_signature',
231
) );
232
}
233
}
234
+
235
/**
236
* Check for configuration errors and displays messages to the user
237
*/
238
public function check_for_configuration_errors() {
239
+ $options = PostmanOptions::getInstance();
240
+ $authToken = PostmanOAuthToken::getInstance();
241
+
242
// did Postman fail binding to wp_mail()?
243
+ if ( $this->wpMailBinder->isUnboundDueToException() ) {
244
// this message gets printed on ANY WordPress admin page, as it's a fatal error that
245
// may occur just by activating a new plugin
246
// log the fatal message
247
+ $this->logger->fatal( 'Postman: wp_mail has been declared by another plugin or theme, so you won\'t be able to use Postman until the conflict is resolved.' );
248
+
249
+ if ( PostmanUtils::isAdmin() && is_admin() ) {
250
// on any admin pages, show this error message
251
// I noticed the wpMandrill and SendGrid plugins have the exact same error message here
252
// I've adopted their error message as well, for shits and giggles .... :D
253
+ $message = __( 'Postman: wp_mail has been declared by another plugin or theme, so you won\'t be able to use Postman until the conflict is resolved.', Postman::TEXT_DOMAIN );
254
+ $this->messageHandler->addError( $message );
255
}
256
} else {
257
+ $transport = PostmanTransportRegistry::getInstance()->getCurrentTransport();
258
+ $scribe = $transport->getScribe();
259
+
260
+ $virgin = $options->isNew();
261
+ if ( ! $transport->isConfiguredAndReady() ) {
262
// if the configuration is broken, and the user has started to configure the plugin
263
// show this error message
264
+ $messages = $transport->getConfigurationMessages();
265
foreach ( $messages as $message ) {
266
+ if ( $message ) {
267
// log the warning message
268
+ $this->logger->warn( sprintf( '%s Transport has a configuration problem: %s', $transport->getName(), $message ) );
269
+
270
+ if ( PostmanUtils::isAdmin() && PostmanUtils::isCurrentPagePostmanAdmin() ) {
271
// on pages that are Postman admin pages only, show this error message
272
+ $this->messageHandler->addError( $message );
273
}
274
}
275
}
276
}
277
+
278
// on pages that are NOT Postman admin pages only, show this error message
279
+ if ( PostmanUtils::isAdmin() && ! PostmanUtils::isCurrentPagePostmanAdmin() && ! $transport->isConfiguredAndReady() ) {
280
// on pages that are *NOT* Postman admin pages only....
281
// if the configuration is broken show this error message
282
+ add_action( 'admin_notices', array(
283
$this,
284
+ 'display_configuration_required_warning',
285
) );
286
}
287
}
288
}
289
+
290
/**
291
* Returns the plugin version number and name
292
* Part of the Postman API
297
// get plugin metadata
298
return $this->pluginData;
299
}
300
+
301
/**
302
* This is the general message that Postman requires configuration, to warn users who think
303
* the plugin is ready-to-go as soon as it is activated.
304
* This message only goes away once the plugin is configured.
305
*/
306
public function display_configuration_required_warning() {
307
+ if ( PostmanUtils::isAdmin() ) {
308
+ if ( $this->logger->isDebug() ) {
309
+ $this->logger->debug( 'Displaying configuration required warning' );
310
}
311
+ $message = sprintf( PostmanTransportRegistry::getInstance()->getReadyMessage() );
312
+ $goToSettings = sprintf( '<a href="%s">%s</a>', PostmanUtils::getSettingsPageUrl(), __( 'Settings', Postman::TEXT_DOMAIN ) );
313
+ $goToEmailLog = sprintf( '%s', _x( 'Email Log', 'The log of Emails that have been delivered', Postman::TEXT_DOMAIN ) );
314
+ if ( PostmanOptions::getInstance()->isMailLoggingEnabled() ) {
315
+ $goToEmailLog = sprintf( '<a href="%s">%s</a>', PostmanUtils::getEmailLogPageUrl(), $goToEmailLog );
316
}
317
+ $message .= (sprintf( ' %s | %s', $goToEmailLog, $goToSettings ));
318
;
319
+ $this->messageHandler->printMessage( $message, PostmanMessageHandler::WARNING_CLASS );
320
}
321
}
322
+
323
/**
324
* Register the email transports.
325
*
326
* The Gmail API used to be a separate plugin which was registered when that plugin
327
* was loaded. But now both the SMTP, Gmail API and other transports are registered here.
328
*
329
+ * @param unknown $pluginData
330
*/
331
+ private function registerTransports( $rootPluginFilenameAndPath ) {
332
+ PostmanTransportRegistry::getInstance()->registerTransport( new PostmanDefaultModuleTransport( $rootPluginFilenameAndPath ) );
333
+ PostmanTransportRegistry::getInstance()->registerTransport( new PostmanSmtpModuleTransport( $rootPluginFilenameAndPath ) );
334
+ PostmanTransportRegistry::getInstance()->registerTransport( new PostmanGmailApiModuleTransport( $rootPluginFilenameAndPath ) );
335
+ PostmanTransportRegistry::getInstance()->registerTransport( new PostmanMandrillTransport( $rootPluginFilenameAndPath ) );
336
+ PostmanTransportRegistry::getInstance()->registerTransport( new PostmanSendGridTransport( $rootPluginFilenameAndPath ) );
337
}
338
+
339
/**
340
* Print the Postman signature on the bottom of the page
341
*
342
* http://striderweb.com/nerdaphernalia/2008/06/give-your-wordpress-plugin-credit/
343
*/
344
function print_signature() {
345
+ printf( '<a href="https://wordpress.org/plugins/postman-smtp/">%s</a> %s<br/>', $this->pluginData ['name'], $this->pluginData ['version'] );
346
}
347
+
348
/**
349
* Loads the appropriate language file
350
*/
351
private function loadTextDomain() {
352
// had to hardcode the third parameter, Relative path to WP_PLUGIN_DIR,
353
// because __FILE__ returns the wrong path if the plugin is installed as a symlink
354
+ $shortLocale = substr( get_locale(), 0, 2 );
355
+ if ( $shortLocale != 'en' ) {
356
$langDir = 'postman-smtp/Postman/languages';
357
+ $success = load_plugin_textdomain( Postman::TEXT_DOMAIN, false, $langDir );
358
+ if ( $this->logger->isDebug() ) {
359
+ if ( $success ) {
360
+ $this->logger->debug( sprintf( 'local translation file loaded for locale=%s', get_locale() ) );
361
} else {
362
+ $this->logger->debug( sprintf( 'failed to load local translation file: locale=%s file=%s/%s-%s.mo', get_locale(), $langDir, Postman::TEXT_DOMAIN, get_locale() ) );
363
}
364
}
365
}
366
}
367
+
368
/**
369
* Shortcode to return the current plugin version.
370
*
377
}
378
}
379
380
+ if ( ! function_exists( 'str_getcsv' ) ) {
381
/**
382
* PHP version less than 5.3 don't have str_getcsv natively.
383
*
384
+ * @param unknown $string
385
* @return multitype:
386
*/
387
+ function str_getcsv( $string ) {
388
+ $logger = new PostmanLogger( 'postman-common-functions' );
389
+ if ( $logger->isDebug() ) {
390
+ $logger->debug( 'Using custom str_getcsv' );
391
}
392
+ return PostmanUtils::postman_strgetcsv_impl( $string );
393
}
394
}
395
Postman/PostmanAdminController.php CHANGED
@@ -1,6 +1,6 @@
1
<?php
2
- if (! class_exists ( "PostmanAdminController" )) {
3
-
4
require_once 'PostmanOptions.php';
5
require_once 'PostmanState.php';
6
require_once 'PostmanState.php';
@@ -14,20 +14,19 @@ if (! class_exists ( "PostmanAdminController" )) {
14
require_once 'PostmanViewController.php';
15
require_once 'PostmanPreRequisitesCheck.php';
16
require_once 'Postman-Auth/PostmanAuthenticationManagerFactory.php';
17
-
18
- //
19
class PostmanAdminController {
20
-
21
// this is the slug used in the URL
22
const MANAGE_OPTIONS_PAGE_SLUG = 'postman/manage-options';
23
-
24
// NONCE NAMES
25
const PURGE_DATA_SLUG = 'postman_purge_data';
26
const IMPORT_SETTINGS_SLUG = 'postman_import_settings';
27
-
28
// The Postman Group is used for saving data, make sure it is globally unique
29
const SETTINGS_GROUP_NAME = 'postman_group';
30
-
31
// a database entry specifically for the form that sends test e-mail
32
const TEST_OPTIONS = 'postman_test_options';
33
const SMTP_OPTIONS = 'postman_smtp_options';
@@ -54,92 +53,92 @@ if (! class_exists ( "PostmanAdminController" )) {
54
const ADVANCED_SECTION = 'postman_advanced_section';
55
const EMAIL_VALIDATION_SECTION = 'postman_email_validation_section';
56
const EMAIL_VALIDATION_OPTIONS = 'postman_email_validation_options';
57
-
58
// slugs
59
const POSTMAN_TEST_SLUG = 'postman-test';
60
-
61
// logging
62
private $logger;
63
-
64
// Holds the values to be used in the fields callbacks
65
private $rootPluginFilenameAndPath;
66
private $options;
67
private $authorizationToken;
68
private $importableConfiguration;
69
-
70
// helpers
71
private $messageHandler;
72
private $oauthScribe;
73
private $wpMailBinder;
74
-
75
/**
76
* Constructor
77
*
78
- * @param unknown $rootPluginFilenameAndPath
79
- * @param PostmanOptions $options
80
- * @param PostmanOAuthToken $authorizationToken
81
- * @param PostmanMessageHandler $messageHandler
82
- * @param PostmanWpMailBinder $binder
83
*/
84
- public function __construct($rootPluginFilenameAndPath, PostmanOptions $options, PostmanOAuthToken $authorizationToken, PostmanMessageHandler $messageHandler, PostmanWpMailBinder $binder) {
85
- assert ( ! empty ( $rootPluginFilenameAndPath ) );
86
- assert ( ! empty ( $options ) );
87
- assert ( ! empty ( $authorizationToken ) );
88
- assert ( ! empty ( $messageHandler ) );
89
- assert ( ! empty ( $binder ) );
90
- assert ( PostmanUtils::isAdmin () );
91
- assert ( is_admin () );
92
-
93
- $this->logger = new PostmanLogger ( get_class ( $this ) );
94
$this->options = $options;
95
$this->authorizationToken = $authorizationToken;
96
$this->messageHandler = $messageHandler;
97
$this->rootPluginFilenameAndPath = $rootPluginFilenameAndPath;
98
$this->wpMailBinder = $binder;
99
-
100
// check if the user saved data, and if validation was successful
101
- $session = PostmanSession::getInstance ();
102
- if ($session->isSetAction ()) {
103
- $this->logger->debug ( sprintf ( 'session action: %s', $session->getAction () ) );
104
}
105
- if ($session->getAction () == PostmanInputSanitizer::VALIDATION_SUCCESS) {
106
// unset the action
107
- $session->unsetAction ();
108
// do a redirect on the init hook
109
- $this->registerInitFunction ( 'handleSuccessfulSave' );
110
// add a saved message to be shown after the redirect
111
- $this->messageHandler->addMessage ( _x ( 'Settings saved.', 'The plugin successfully saved new settings.', Postman::TEXT_DOMAIN ) );
112
return;
113
} else {
114
// unset the action in the failed case as well
115
- $session->unsetAction ();
116
}
117
-
118
// test to see if an OAuth authentication is in progress
119
- if ($session->isSetOauthInProgress ()) {
120
// there is only a three minute window that Postman will expect a Grant Code, once Grant is clicked by the user
121
- $this->logger->debug ( 'Looking for grant code' );
122
- if (isset ( $_GET ['code'] )) {
123
- $this->logger->debug ( 'Found authorization grant code' );
124
// queue the function that processes the incoming grant code
125
- $this->registerInitFunction ( 'handleAuthorizationGrant' );
126
return;
127
}
128
}
129
-
130
// continue to initialize the AdminController
131
- add_action ( 'init', array (
132
$this,
133
- 'on_init'
134
) );
135
-
136
// Adds "Settings" link to the plugin action page
137
- add_filter ( 'plugin_action_links_' . plugin_basename ( $this->rootPluginFilenameAndPath ), array (
138
$this,
139
- 'postmanModifyLinksOnPluginsListPage'
140
) );
141
}
142
-
143
/**
144
* Functions to execute on the init event
145
*
@@ -148,86 +147,86 @@ if (! class_exists ( "PostmanAdminController" )) {
148
*/
149
public function on_init() {
150
// only administrators should be able to trigger this
151
- if (PostmanUtils::isAdmin ()) {
152
- //
153
- $transport = PostmanTransportRegistry::getInstance ()->getCurrentTransport ();
154
- $this->oauthScribe = $transport->getScribe ();
155
-
156
// register content handlers
157
- $viewController = new PostmanViewController ( $this->rootPluginFilenameAndPath, $this->options, $this->authorizationToken, $this->oauthScribe, $this );
158
-
159
// register action handlers
160
- $this->registerAdminPostAction ( self::PURGE_DATA_SLUG, 'handlePurgeDataAction' );
161
- $this->registerAdminPostAction ( self::IMPORT_SETTINGS_SLUG, 'importSettingsAction' );
162
- $this->registerAdminPostAction ( PostmanUtils::REQUEST_OAUTH2_GRANT_SLUG, 'handleOAuthPermissionRequestAction' );
163
-
164
- if (PostmanUtils::isCurrentPagePostmanAdmin ()) {
165
- $this->checkPreRequisites ();
166
}
167
}
168
}
169
-
170
/**
171
- *
172
*/
173
private function checkPreRequisites() {
174
- $states = PostmanPreRequisitesCheck::getState ();
175
foreach ( $states as $state ) {
176
- if (! $state ['ready']) {
177
/* Translators: where %1$s is the name of the library */
178
- $message = sprintf ( __ ( 'This PHP installation requires the <b>%1$s</b> library.', Postman::TEXT_DOMAIN ), $state ['name'] );
179
- if ($state ['required']) {
180
- $this->messageHandler->addError ( $message );
181
} else {
182
// $this->messageHandler->addWarning ( $message );
183
}
184
}
185
}
186
}
187
-
188
/**
189
*
190
- * @param unknown $actionName
191
- * @param unknown $callbackName
192
*/
193
- private function registerInitFunction($callbackName) {
194
- $this->logger->debug ( 'Registering init function ' . $callbackName );
195
- add_action ( 'init', array (
196
$this,
197
- $callbackName
198
) );
199
}
200
-
201
/**
202
* Registers actions posted by am HTML FORM with the WordPress 'action' parameter
203
*
204
- * @param unknown $actionName
205
- * @param unknown $callbankName
206
*/
207
- private function registerAdminPostAction($actionName, $callbankName) {
208
// $this->logger->debug ( 'Registering ' . $actionName . ' Action Post handler' );
209
- add_action ( 'admin_post_' . $actionName, array (
210
$this,
211
- $callbankName
212
) );
213
}
214
-
215
/**
216
* Add "Settings" link to the plugin action page
217
*
218
- * @param unknown $links
219
* @return multitype:
220
*/
221
- public function postmanModifyLinksOnPluginsListPage($links) {
222
// only administrators should be able to trigger this
223
- if (PostmanUtils::isAdmin ()) {
224
- $mylinks = array (
225
- sprintf ( '<a href="%s" class="postman_settings">%s</a>', PostmanUtils::getSettingsPageUrl (), __ ( 'Settings', Postman::TEXT_DOMAIN ) )
226
);
227
- return array_merge ( $mylinks, $links );
228
}
229
}
230
-
231
/**
232
* This function runs after a successful, error-free save
233
*/
@@ -235,43 +234,43 @@ if (! class_exists ( "PostmanAdminController" )) {
235
// WordPress likes to keep GET parameters around for a long time
236
// (something in the call to settings_fields() does this)
237
// here we redirect after a successful save to clear those parameters
238
- PostmanUtils::redirect ( PostmanUtils::POSTMAN_HOME_PAGE_RELATIVE_URL );
239
}
240
-
241
/**
242
* This function handle the request to import plugin data
243
*/
244
public function importSettingsAction() {
245
- $this->logger->debug ( 'is wpnonce import-settings?' );
246
$success = true;
247
- if (wp_verify_nonce ( $_REQUEST ['_wpnonce'], PostmanAdminController::IMPORT_SETTINGS_SLUG )) {
248
- $success = PostmanOptions::getInstance ()->import ( $_POST ['settings'] );
249
} else {
250
$success = false;
251
}
252
- if (! $success) {
253
- $this->messageHandler->addError ( __ ( 'There was an error importing the data.', Postman::TEXT_DOMAIN ) );
254
- $this->logger->error ( 'There was an error importing the data' );
255
}
256
- PostmanUtils::redirect ( PostmanUtils::POSTMAN_HOME_PAGE_RELATIVE_URL );
257
}
258
/**
259
* This function handle the request to purge plugin data
260
*/
261
public function handlePurgeDataAction() {
262
- $this->logger->debug ( 'is wpnonce purge-data?' );
263
- if (wp_verify_nonce ( $_REQUEST ['_wpnonce'], PostmanAdminController::PURGE_DATA_SLUG )) {
264
- $this->logger->debug ( 'Purging stored data' );
265
- delete_option ( PostmanOptions::POSTMAN_OPTIONS );
266
- delete_option ( PostmanOAuthToken::OPTIONS_NAME );
267
- delete_option ( PostmanAdminController::TEST_OPTIONS );
268
- $logPurger = new PostmanEmailLogPurger ();
269
- $logPurger->removeAll ();
270
- $this->messageHandler->addMessage ( __ ( 'Plugin data was removed.', Postman::TEXT_DOMAIN ) );
271
- PostmanUtils::redirect ( PostmanUtils::POSTMAN_HOME_PAGE_RELATIVE_URL );
272
}
273
}
274
-
275
/**
276
* Handles the authorization grant
277
*/
@@ -279,49 +278,49 @@ if (! class_exists ( "PostmanAdminController" )) {
279
$logger = $this->logger;
280
$options = $this->options;
281
$authorizationToken = $this->authorizationToken;
282
- $logger->debug ( 'Authorization in progress' );
283
- $transactionId = PostmanSession::getInstance ()->getOauthInProgress ();
284
-
285
// begin transaction
286
- PostmanUtils::lock ();
287
-
288
- $authenticationManager = PostmanAuthenticationManagerFactory::getInstance ()->createAuthenticationManager ();
289
try {
290
- if ($authenticationManager->processAuthorizationGrantCode ( $transactionId )) {
291
- $logger->debug ( 'Authorization successful' );
292
// save to database
293
- $authorizationToken->save ();
294
- $this->messageHandler->addMessage ( __ ( 'The OAuth 2.0 authorization was successful. Ready to send e-mail.', Postman::TEXT_DOMAIN ) );
295
} else {
296
- $this->messageHandler->addError ( __ ( 'Your email provider did not grant Postman permission. Try again.', Postman::TEXT_DOMAIN ) );
297
}
298
} catch ( PostmanStateIdMissingException $e ) {
299
- $this->messageHandler->addError ( __ ( 'The grant code from Google had no accompanying state and may be a forgery', Postman::TEXT_DOMAIN ) );
300
} catch ( Exception $e ) {
301
- $logger->error ( 'Error: ' . get_class ( $e ) . ' code=' . $e->getCode () . ' message=' . $e->getMessage () );
302
/* translators: %s is the error message */
303
- $this->messageHandler->addError ( sprintf ( __ ( 'Error authenticating with this Client ID. [%s]', Postman::TEXT_DOMAIN ), '<em>' . $e->getMessage () . '</em>' ) );
304
}
305
-
306
// clean-up
307
- PostmanUtils::unlock ();
308
- PostmanSession::getInstance ()->unsetOauthInProgress ();
309
-
310
// redirect home
311
- PostmanUtils::redirect ( PostmanUtils::POSTMAN_HOME_PAGE_RELATIVE_URL );
312
}
313
-
314
/**
315
* This method is called when a user clicks on a "Request Permission from Google" link.
316
* This link will create a remote API call for Google and redirect the user from WordPress to Google.
317
* Google will redirect back to WordPress after the user responds.
318
*/
319
public function handleOAuthPermissionRequestAction() {
320
- $this->logger->debug ( 'handling OAuth Permission request' );
321
- $authenticationManager = PostmanAuthenticationManagerFactory::getInstance ()->createAuthenticationManager ();
322
- $transactionId = $authenticationManager->generateRequestTransactionId ();
323
- PostmanSession::getInstance ()->setOauthInProgress ( $transactionId );
324
- $authenticationManager->requestVerificationCode ( $transactionId );
325
}
326
}
327
- }
1
<?php
2
+ if ( ! class_exists( 'PostmanAdminController' ) ) {
3
+
4
require_once 'PostmanOptions.php';
5
require_once 'PostmanState.php';
6
require_once 'PostmanState.php';
14
require_once 'PostmanViewController.php';
15
require_once 'PostmanPreRequisitesCheck.php';
16
require_once 'Postman-Auth/PostmanAuthenticationManagerFactory.php';
17
+
18
class PostmanAdminController {
19
+
20
// this is the slug used in the URL
21
const MANAGE_OPTIONS_PAGE_SLUG = 'postman/manage-options';
22
+
23
// NONCE NAMES
24
const PURGE_DATA_SLUG = 'postman_purge_data';
25
const IMPORT_SETTINGS_SLUG = 'postman_import_settings';
26
+
27
// The Postman Group is used for saving data, make sure it is globally unique
28
const SETTINGS_GROUP_NAME = 'postman_group';
29
+
30
// a database entry specifically for the form that sends test e-mail
31
const TEST_OPTIONS = 'postman_test_options';
32
const SMTP_OPTIONS = 'postman_smtp_options';
53
const ADVANCED_SECTION = 'postman_advanced_section';
54
const EMAIL_VALIDATION_SECTION = 'postman_email_validation_section';
55
const EMAIL_VALIDATION_OPTIONS = 'postman_email_validation_options';
56
+
57
// slugs
58
const POSTMAN_TEST_SLUG = 'postman-test';
59
+
60
// logging
61
private $logger;
62
+
63
// Holds the values to be used in the fields callbacks
64
private $rootPluginFilenameAndPath;
65
private $options;
66
private $authorizationToken;
67
private $importableConfiguration;
68
+
69
// helpers
70
private $messageHandler;
71
private $oauthScribe;
72
private $wpMailBinder;
73
+
74
/**
75
* Constructor
76
*
77
+ * @param unknown $rootPluginFilenameAndPath
78
+ * @param PostmanOptions $options
79
+ * @param PostmanOAuthToken $authorizationToken
80
+ * @param PostmanMessageHandler $messageHandler
81
+ * @param PostmanWpMailBinder $binder
82
*/
83
+ public function __construct( $rootPluginFilenameAndPath, PostmanOptions $options, PostmanOAuthToken $authorizationToken, PostmanMessageHandler $messageHandler, PostmanWpMailBinder $binder ) {
84
+ assert( ! empty( $rootPluginFilenameAndPath ) );
85
+ assert( ! empty( $options ) );
86
+ assert( ! empty( $authorizationToken ) );
87
+ assert( ! empty( $messageHandler ) );
88
+ assert( ! empty( $binder ) );
89
+ assert( PostmanUtils::isAdmin() );
90
+ assert( is_admin() );
91
+
92
+ $this->logger = new PostmanLogger( get_class( $this ) );
93
$this->options = $options;
94
$this->authorizationToken = $authorizationToken;
95
$this->messageHandler = $messageHandler;
96
$this->rootPluginFilenameAndPath = $rootPluginFilenameAndPath;
97
$this->wpMailBinder = $binder;
98
+
99
// check if the user saved data, and if validation was successful
100
+ $session = PostmanSession::getInstance();
101
+ if ( $session->isSetAction() ) {
102
+ $this->logger->debug( sprintf( 'session action: %s', $session->getAction() ) );
103
}
104
+ if ( $session->getAction() == PostmanInputSanitizer::VALIDATION_SUCCESS ) {
105
// unset the action
106
+ $session->unsetAction();
107
// do a redirect on the init hook
108
+ $this->registerInitFunction( 'handleSuccessfulSave' );
109
// add a saved message to be shown after the redirect
110
+ $this->messageHandler->addMessage( _x( 'Settings saved.', 'The plugin successfully saved new settings.', Postman::TEXT_DOMAIN ) );
111
return;
112
} else {
113
// unset the action in the failed case as well
114
+ $session->unsetAction();
115
}
116
+
117
// test to see if an OAuth authentication is in progress
118
+ if ( $session->isSetOauthInProgress() ) {
119
// there is only a three minute window that Postman will expect a Grant Code, once Grant is clicked by the user
120
+ $this->logger->debug( 'Looking for grant code' );
121
+ if ( isset( $_GET ['code'] ) ) {
122
+ $this->logger->debug( 'Found authorization grant code' );
123
// queue the function that processes the incoming grant code
124
+ $this->registerInitFunction( 'handleAuthorizationGrant' );
125
return;
126
}
127
}
128
+
129
// continue to initialize the AdminController
130
+ add_action( 'init', array(
131
$this,
132
+ 'on_init',
133
) );
134
+
135
// Adds "Settings" link to the plugin action page
136
+ add_filter( 'plugin_action_links_' . plugin_basename( $this->rootPluginFilenameAndPath ), array(
137
$this,
138
+ 'postmanModifyLinksOnPluginsListPage',
139
) );
140
}
141
+
142
/**
143
* Functions to execute on the init event
144
*
147
*/
148
public function on_init() {
149
// only administrators should be able to trigger this
150
+ if ( PostmanUtils::isAdmin() ) {
151
+ $transport = PostmanTransportRegistry::getInstance()->getCurrentTransport();
152
+ $this->oauthScribe = $transport->getScribe();
153
+
154
// register content handlers
155
+ $viewController = new PostmanViewController( $this->rootPluginFilenameAndPath, $this->options, $this->authorizationToken, $this->oauthScribe, $this );
156
+
157
// register action handlers
158
+ $this->registerAdminPostAction( self::PURGE_DATA_SLUG, 'handlePurgeDataAction' );
159
+ $this->registerAdminPostAction( self::IMPORT_SETTINGS_SLUG, 'importSettingsAction' );
160
+ $this->registerAdminPostAction( PostmanUtils::REQUEST_OAUTH2_GRANT_SLUG, 'handleOAuthPermissionRequestAction' );
161
+
162
+ if ( PostmanUtils::isCurrentPagePostmanAdmin() ) {
163
+ $this->checkPreRequisites();
164
}
165
}
166
}
167
+
168
/**
169
+ *
170
*/
171
private function checkPreRequisites() {
172
+ $states = PostmanPreRequisitesCheck::getState();
173
foreach ( $states as $state ) {
174
+ if ( ! $state ['ready'] ) {
175
/* Translators: where %1$s is the name of the library */
176
+ $message = sprintf( __( 'This PHP installation requires the <b>%1$s</b> library.', Postman::TEXT_DOMAIN ), $state ['name'] );
177
+ if ( $state ['required'] ) {
178
+ $this->messageHandler->addError( $message );
179
} else {
180
// $this->messageHandler->addWarning ( $message );
181
}
182
}
183
}
184
}
185
+
186
/**
187
*
188
+ * @param unknown $actionName
189
+ * @param unknown $callbackName
190
*/
191
+ private function registerInitFunction( $callbackName ) {
192
+ $this->logger->debug( 'Registering init function ' . $callbackName );
193
+ add_action( 'init', array(
194
$this,
195
+ $callbackName,
196
) );
197
}
198
+
199
/**
200
* Registers actions posted by am HTML FORM with the WordPress 'action' parameter
201
*
202
+ * @param unknown $actionName
203
+ * @param unknown $callbankName
204
*/
205
+ private function registerAdminPostAction( $actionName, $callbankName ) {
206
// $this->logger->debug ( 'Registering ' . $actionName . ' Action Post handler' );
207
+ add_action( 'admin_post_' . $actionName, array(
208
$this,
209
+ $callbankName,
210
) );
211
}
212
+
213
/**
214
* Add "Settings" link to the plugin action page
215
*
216
+ * @param unknown $links
217
* @return multitype:
218
*/
219
+ public function postmanModifyLinksOnPluginsListPage( $links ) {
220
// only administrators should be able to trigger this
221
+ if ( PostmanUtils::isAdmin() ) {
222
+ $mylinks = array(
223
+ sprintf( '<a href="%s" class="postman_settings">%s</a>', PostmanUtils::getSettingsPageUrl(), __( 'Settings', Postman::TEXT_DOMAIN ) ),
224
+ sprintf( '<a href="%s" class="postman_settings">%s</a>', 'https://postmansmtp.com', __( 'Visit us', Postman::TEXT_DOMAIN ) ),
225
);
226
+ return array_merge( $mylinks, $links );
227
}
228
}
229
+
230
/**
231
* This function runs after a successful, error-free save
232
*/
234
// WordPress likes to keep GET parameters around for a long time
235
// (something in the call to settings_fields() does this)
236
// here we redirect after a successful save to clear those parameters
237
+ PostmanUtils::redirect( PostmanUtils::POSTMAN_HOME_PAGE_RELATIVE_URL );
238
}
239
+
240
/**
241
* This function handle the request to import plugin data
242
*/
243
public function importSettingsAction() {
244
+ $this->logger->debug( 'is wpnonce import-settings?' );
245
$success = true;
246
+ if ( wp_verify_nonce( $_REQUEST ['_wpnonce'], PostmanAdminController::IMPORT_SETTINGS_SLUG ) ) {
247
+ $success = PostmanOptions::getInstance()->import( $_POST ['settings'] );
248
} else {
249
$success = false;
250
}
251
+ if ( ! $success ) {
252
+ $this->messageHandler->addError( __( 'There was an error importing the data.', Postman::TEXT_DOMAIN ) );
253
+ $this->logger->error( 'There was an error importing the data' );
254
}
255
+ PostmanUtils::redirect( PostmanUtils::POSTMAN_HOME_PAGE_RELATIVE_URL );
256
}
257
/**
258
* This function handle the request to purge plugin data
259
*/
260
public function handlePurgeDataAction() {
261
+ $this->logger->debug( 'is wpnonce purge-data?' );
262
+ if ( wp_verify_nonce( $_REQUEST ['_wpnonce'], PostmanAdminController::PURGE_DATA_SLUG ) ) {
263
+ $this->logger->debug( 'Purging stored data' );
264
+ delete_option( PostmanOptions::POSTMAN_OPTIONS );
265
+ delete_option( PostmanOAuthToken::OPTIONS_NAME );
266
+ delete_option( PostmanAdminController::TEST_OPTIONS );
267
+ $logPurger = new PostmanEmailLogPurger();
268
+ $logPurger->removeAll();
269
+ $this->messageHandler->addMessage( __( 'Plugin data was removed.', Postman::TEXT_DOMAIN ) );
270
+ PostmanUtils::redirect( PostmanUtils::POSTMAN_HOME_PAGE_RELATIVE_URL );
271
}
272
}
273
+
274
/**
275
* Handles the authorization grant
276
*/
278
$logger = $this->logger;
279
$options = $this->options;
280
$authorizationToken = $this->authorizationToken;
281
+ $logger->debug( 'Authorization in progress' );
282
+ $transactionId = PostmanSession::getInstance()->getOauthInProgress();
283
+
284
// begin transaction
285
+ PostmanUtils::lock();
286
+
287
+ $authenticationManager = PostmanAuthenticationManagerFactory::getInstance()->createAuthenticationManager();
288
try {
289
+ if ( $authenticationManager->processAuthorizationGrantCode( $transactionId ) ) {
290
+ $logger->debug( 'Authorization successful' );
291
// save to database
292
+ $authorizationToken->save();
293
+ $this->messageHandler->addMessage( __( 'The OAuth 2.0 authorization was successful. Ready to send e-mail.', Postman::TEXT_DOMAIN ) );
294
} else {
295
+ $this->messageHandler->addError( __( 'Your email provider did not grant Postman permission. Try again.', Postman::TEXT_DOMAIN ) );
296
}
297
} catch ( PostmanStateIdMissingException $e ) {
298
+ $this->messageHandler->addError( __( 'The grant code from Google had no accompanying state and may be a forgery', Postman::TEXT_DOMAIN ) );
299
} catch ( Exception $e ) {
300
+ $logger->error( 'Error: ' . get_class( $e ) . ' code=' . $e->getCode() . ' message=' . $e->getMessage() );
301
/* translators: %s is the error message */
302
+ $this->messageHandler->addError( sprintf( __( 'Error authenticating with this Client ID. [%s]', Postman::TEXT_DOMAIN ), '<em>' . $e->getMessage() . '</em>' ) );
303
}
304
+
305
// clean-up
306
+ PostmanUtils::unlock();
307
+ PostmanSession::getInstance()->unsetOauthInProgress();
308
+
309
// redirect home
310
+ PostmanUtils::redirect( PostmanUtils::POSTMAN_HOME_PAGE_RELATIVE_URL );
311
}
312
+
313
/**
314
* This method is called when a user clicks on a "Request Permission from Google" link.
315
* This link will create a remote API call for Google and redirect the user from WordPress to Google.
316
* Google will redirect back to WordPress after the user responds.
317
*/
318
public function handleOAuthPermissionRequestAction() {
319
+ $this->logger->debug( 'handling OAuth Permission request' );
320
+ $authenticationManager = PostmanAuthenticationManagerFactory::getInstance()->createAuthenticationManager();
321
+ $transactionId = $authenticationManager->generateRequestTransactionId();
322
+ PostmanSession::getInstance()->setOauthInProgress( $transactionId );
323
+ $authenticationManager->requestVerificationCode( $transactionId );
324
}
325
}
326
+ }
postman-smtp.php CHANGED
@@ -4,10 +4,10 @@
4
* Plugin Name: Post SMTP
5
* Plugin URI: https://wordpress.org/plugins/post-smtp/
6
* Description: Email not reliable? Post SMTP is the first and only WordPress SMTP plugin to implement OAuth 2.0 for Gmail, Hotmail and Yahoo Mail. Setup is a breeze with the Configuration Wizard and integrated Port Tester. Enjoy worry-free delivery even if your password changes!
7
- * Version: 1.7.5
8
* Author: Jason Hendriks, Yehuda Hassine
9
- * Text Domain: postman-smtp
10
- * Author URI: https://github.com/yehudah/Postman-SMTP
11
* License: GPLv2 or later
12
* License URI: http://www.gnu.org/licenses/gpl-2.0.html
13
*/
@@ -70,5 +70,5 @@ function post_start( $startingMemory ) {
70
*/
71
function post_setupPostman() {
72
require_once 'Postman/Postman.php';
73
- $kevinCostner = new Postman( __FILE__, '1.7.3' );
74
}
4
* Plugin Name: Post SMTP
5
* Plugin URI: https://wordpress.org/plugins/post-smtp/
6
* Description: Email not reliable? Post SMTP is the first and only WordPress SMTP plugin to implement OAuth 2.0 for Gmail, Hotmail and Yahoo Mail. Setup is a breeze with the Configuration Wizard and integrated Port Tester. Enjoy worry-free delivery even if your password changes!
7
+ * Version: 1.7.6
8
* Author: Jason Hendriks, Yehuda Hassine
9
+ * Text Domain: post-smtp
10
+ * Author URI: https://postmansmtp.com
11
* License: GPLv2 or later
12
* License URI: http://www.gnu.org/licenses/gpl-2.0.html
13
*/
70
*/
71
function post_setupPostman() {
72
require_once 'Postman/Postman.php';
73
+ $kevinCostner = new Postman( __FILE__, '1.7.6' );
74
}
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: yehudah, jasonhendriks
3
Tags: postman smtp, postman, smtp, email, mail, mailer, email log, oauth2, gmail, google apps, hotmail, yahoo, mandrill api, sendgrid api, sparkpost api
4
Requires at least: 3.9
5
Tested up to: 4.8
6
- Stable tag: 1.7.5
7
License: GPLv2 or later
8
License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
@@ -271,7 +271,11 @@ To avoid being flagged as spam, you need to prove your email isn't forged. On a
271
272
== Changelog ==
273
274
- = 1.7.3 - 2017-10-07 =
275
* Fixed: security issue (XSS)
276
* Fixed: Small bug with Google API
277
3
Tags: postman smtp, postman, smtp, email, mail, mailer, email log, oauth2, gmail, google apps, hotmail, yahoo, mandrill api, sendgrid api, sparkpost api
4
Requires at least: 3.9
5
Tested up to: 4.8
6
+ Stable tag: 1.7.6
7
License: GPLv2 or later
8
License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
271
272
== Changelog ==
273
274
+ = 1.7.6 - 2017-10-17
275
+ * Missing sendgrid files
276
+ * Fixed: Localization slug
277
+
278
+ = 1.7.5 - 2017-10-07 =
279
* Fixed: security issue (XSS)
280
* Fixed: Small bug with Google API
281