Mailgun for WordPress - Version 1.5.8.1

Version Description

(2017-02-06): = - Fix "Undefined property: MailgunAdmin::$hook_suffix" (#48) - Fix "Undefined variable: from_name on every email process" (API and SMTP) (#49) - Admin code now loads only on admin user access

Download this release

Release Info

Developer Mailgun
Plugin Icon 128x128 Mailgun for WordPress
Version 1.5.8.1
Comparing to
See all releases

Code changes from version 1.5.7 to 1.5.8.1

CHANGELOG.md CHANGED
@@ -1,6 +1,20 @@
1
  Changelog
2
  =========
3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  1.5.7 (2017-01-04):
5
  * Add better support for using recipient variables for batch mailing.
6
  * Clarify wording on `From Address` note
1
  Changelog
2
  =========
3
 
4
+ 1.5.8.1 (2017-02-06):
5
+ - Fix "Undefined property: MailgunAdmin::$hook_suffix" (#48)
6
+ - Fix "Undefined variable: from_name on every email process" (API and SMTP) (#49)
7
+ - Admin code now loads only on admin user access
8
+
9
+ 1.5.8 (2017-01-23):
10
+ * Rewrite a large chunk of old SMTP code
11
+ * Fix a bug with SMTP + "override from" that was introduced in 1.5.7
12
+ * SMTP debug logging is now controlled by `MG_DEBUG_SMTP` constant
13
+
14
+ 1.5.7.1 (2017-01-18):
15
+ * Fix an odd `Undefined property: MailgunAdmin::$defaults` when saving config
16
+ * Fix strict mode notice for using `$mailgun['override-from']` without checking `isset`
17
+
18
  1.5.7 (2017-01-04):
19
  * Add better support for using recipient variables for batch mailing.
20
  * Clarify wording on `From Address` note
includes/admin.php CHANGED
@@ -22,7 +22,7 @@
22
  class MailgunAdmin extends Mailgun
23
  {
24
  /**
25
- * @var array $defaults Array of "safe" option defaults.
26
  */
27
  private $defaults;
28
 
@@ -306,27 +306,31 @@ class MailgunAdmin extends Mailgun
306
  public function admin_notices()
307
  {
308
  $screen = get_current_screen();
309
- if ($screen->id == $this->hook_suffix) {
 
310
  return;
311
  }
312
 
313
  if ((!$this->get_option('apiKey') && $this->get_option('useAPI') === '1')
314
  || (!$this->get_option('password') && $this->get_option('useAPI') === '0')
315
- ) { ?>
316
- <div id='mailgun-warning' class='updated fade'><p><strong><?php _e('Mailgun is almost ready. ', 'mailgun'); ?></strong><?php printf(__('You must <a href="%1$s">configure Mailgun</a> for it to work.', 'mailgun'), menu_page_url('mailgun', false)); ?></p></div>
 
317
  <?php
 
318
  }
319
 
320
  if ($this->get_option('override-from') === '1'
321
  && (!$this->get_option('from-name')
322
  || !$this->get_option('from-address'))
323
- ) { ?>
324
- <div id='mailgun-warning' class='updated fade'><p><strong><?php _e('Mailgun is almost ready. ', 'mailgun'); ?></strong><?php printf(__('"Override From" option requires that "From Name" and "From Address" be set to work properly! <a href="%1$s">Configure Mailgun now</a>.', 'mailgun'), menu_page_url('mailgun', false)); ?></p></div>
 
325
  <?php
 
326
  }
327
  }
328
 
329
-
330
  /**
331
  * Add a settings link to the plugin actions.
332
  *
@@ -362,6 +366,7 @@ class MailgunAdmin extends Mailgun
362
  array(
363
  'message' => __('Unauthorized', 'mailgun'),
364
  'method' => null,
 
365
  )
366
  )
367
  );
22
  class MailgunAdmin extends Mailgun
23
  {
24
  /**
25
+ * @var array Array of "safe" option defaults.
26
  */
27
  private $defaults;
28
 
306
  public function admin_notices()
307
  {
308
  $screen = get_current_screen();
309
+ if (!current_user_can('manage_options') || $screen->id == $this->hook_suffix
310
+ ) {
311
  return;
312
  }
313
 
314
  if ((!$this->get_option('apiKey') && $this->get_option('useAPI') === '1')
315
  || (!$this->get_option('password') && $this->get_option('useAPI') === '0')
316
+ ) {
317
+ ?>
318
+ <div id='mailgun-warning' class='notice notice-warning fade'><p><strong><?php _e('Mailgun is almost ready. ', 'mailgun'); ?></strong><?php printf(__('You must <a href="%1$s">configure Mailgun</a> for it to work.', 'mailgun'), menu_page_url('mailgun', false)); ?></p></div>
319
  <?php
320
+
321
  }
322
 
323
  if ($this->get_option('override-from') === '1'
324
  && (!$this->get_option('from-name')
325
  || !$this->get_option('from-address'))
326
+ ) {
327
+ ?>
328
+ <div id='mailgun-warning' class='notice notice-warning fade'><p><strong><?php _e('Mailgun is almost ready. ', 'mailgun'); ?></strong><?php printf(__('"Override From" option requires that "From Name" and "From Address" be set to work properly! <a href="%1$s">Configure Mailgun now</a>.', 'mailgun'), menu_page_url('mailgun', false)); ?></p></div>
329
  <?php
330
+
331
  }
332
  }
333
 
 
334
  /**
335
  * Add a settings link to the plugin actions.
336
  *
366
  array(
367
  'message' => __('Unauthorized', 'mailgun'),
368
  'method' => null,
369
+ 'error' => __('Unauthorized', 'mailgun'),
370
  )
371
  )
372
  );
includes/mg-filter.php ADDED
@@ -0,0 +1,277 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * mailgun-wordpress-plugin - Sending mail from Wordpress using Mailgun
5
+ * Copyright (C) 2016 Mailgun, et al.
6
+ *
7
+ * This program is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ * GNU General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License along
18
+ * with this program; if not, write to the Free Software Foundation, Inc.,
19
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
+ */
21
+
22
+ /**
23
+ * Tries several methods to get the MIME Content-Type of a file.
24
+ *
25
+ * @param string $filepath
26
+ * @param string $default_type If all methods fail, fallback to $default_type
27
+ *
28
+ * @return string Content-Type
29
+ *
30
+ * @since 1.5.4
31
+ */
32
+ function get_mime_content_type($filepath, $default_type = 'text/plain')
33
+ {
34
+ if (function_exists('mime_content_type')) {
35
+ return mime_content_type($filepath);
36
+ } elseif (function_exists('finfo_file')) {
37
+ $fi = finfo_open(FILEINFO_MIME_TYPE);
38
+ $ret = finfo_file($fi, $filepath);
39
+ finfo_close($fi);
40
+
41
+ return $ret;
42
+ } else {
43
+ return $default_type;
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Find the sending "From Name" with a similar process used in `wp_mail`.
49
+ * This operates as a filter for the from name. If the override is set,
50
+ * a given name will clobbered except in ONE case.
51
+ * If the override is not enabled this is the from name resolution order:
52
+ * 1. From name given by headers - {@param $from_name_header}
53
+ * 2. From name set in Mailgun settings
54
+ * 3. From `MAILGUN_FROM_NAME` constant
55
+ * 4. From name constructed as `<your_site_title>` or "WordPress"
56
+ *
57
+ * If the `wp_mail_from` filter is available, it is applied to the resulting
58
+ * `$from_addr` before being returned. The filtered result is null-tested
59
+ * before being returned.
60
+ *
61
+ * @return string
62
+ *
63
+ * @since 1.5.8
64
+ */
65
+ function mg_detect_from_name($from_name_header = null)
66
+ {
67
+ // Get options to avoid strict mode problems
68
+ $mg_opts = get_option('mailgun');
69
+ $mg_override_from = (isset($mg_opts['override-from'])) ? $mg_opts['override-from'] : null;
70
+ $mg_from_name = (isset($mg_opts['from-name'])) ? $mg_opts['from-name'] : null;
71
+
72
+ $from_name = null;
73
+
74
+ if ($mg_override_from && !is_null($mg_from_name)) {
75
+ $from_name = $mg_from_name;
76
+ } elseif (!is_null($from_name_header)) {
77
+ $from_name = $from_name_header;
78
+ } elseif (defined('MAILGUN_FROM_NAME') && MAILGUN_FROM_NAME) {
79
+ $from_name = MAILGUN_FROM_NAME;
80
+ } else {
81
+ if (is_null($mg_from_name) || empty($mg_from_name)) {
82
+ if (function_exists('get_current_site')) {
83
+ $from_name = get_current_site()->site_name;
84
+ } else {
85
+ $from_name = 'WordPress';
86
+ }
87
+ } else {
88
+ $from_name = $mg_from_name;
89
+ }
90
+ }
91
+
92
+ $filter_from_name = null;
93
+ if (has_filter('wp_mail_from_name')) {
94
+ $filter_from_name = apply_filters(
95
+ 'wp_mail_from_name',
96
+ $from_name
97
+ );
98
+ if (!is_null($filter_from_name) && !empty($filter_from_name)) {
99
+ $from_name = $filter_from_name;
100
+ }
101
+ }
102
+
103
+ return $from_name;
104
+ }
105
+
106
+ /**
107
+ * Find the sending "From Address" with a similar process used in `wp_mail`.
108
+ * This operates as a filter for the from address. If the override is set,
109
+ * a given address will except in ONE case.
110
+ * If the override is not enabled this is the from address resolution order:
111
+ * 1. From address given by headers - {@param $from_addr_header}
112
+ * 2. From address set in Mailgun settings
113
+ * 3. From `MAILGUN_FROM_ADDRESS` constant
114
+ * 4. From address constructed as `wordpress@<your_site_domain>`
115
+ *
116
+ * If the `wp_mail_from` filter is available, it is applied to the resulting
117
+ * `$from_addr` before being returned. The filtered result is null-tested
118
+ * before being returned.
119
+ *
120
+ * If we don't have `From` input headers, use wordpress@$sitedomain
121
+ * Some hosts will block outgoing mail from this address if it doesn't
122
+ * exist but there's no easy alternative. Defaulting to admin_email
123
+ * might appear to be another option but some hosts may refuse to
124
+ * relay mail from an unknown domain.
125
+ *
126
+ * @link http://trac.wordpress.org/ticket/5007.
127
+ *
128
+ * @param string $from_addr_header From address given by a header.
129
+ *
130
+ * @return string
131
+ *
132
+ * @since 1.5.8
133
+ */
134
+ function mg_detect_from_address($from_addr_header = null)
135
+ {
136
+ // Get options to avoid strict mode problems
137
+ $mg_opts = get_option('mailgun');
138
+ $mg_override_from = (isset($mg_opts['override-from'])) ? $mg_opts['override-from'] : null;
139
+ $mg_from_addr = (isset($mg_opts['from-address'])) ? $mg_opts['from-address'] : null;
140
+
141
+ $from_addr = null;
142
+
143
+ if ($mg_override_from && !is_null($mg_from_addr)) {
144
+ $from_addr = $mg_from_addr;
145
+ } elseif (!is_null($from_addr_header)) {
146
+ $from_addr = $from_addr_header;
147
+ } elseif (defined('MAILGUN_FROM_ADDRESS') && MAILGUN_FROM_ADDRESS) {
148
+ $from_addr = MAILGUN_FROM_ADDRESS;
149
+ } else {
150
+ if (is_null($mg_from_addr) || empty($mg_from_addr)) {
151
+ if (function_exists('get_current_site')) {
152
+ $sitedomain = get_current_site()->domain;
153
+ } else {
154
+ $sitedomain = strtolower($_SERVER['SERVER_NAME']);
155
+ if (substr($sitedomain, 0, 4) === 'www.') {
156
+ $sitedomain = substr($sitedomain, 4);
157
+ }
158
+ }
159
+
160
+ $from_addr = 'wordpress@'.$sitedomain;
161
+ } else {
162
+ $from_addr = $mg_from_addr;
163
+ }
164
+ }
165
+
166
+ $filter_from_addr = null;
167
+ if (has_filter('wp_mail_from')) {
168
+ $filter_from_addr = apply_filters(
169
+ 'wp_mail_from',
170
+ $from_addr
171
+ );
172
+ if (!is_null($filter_from_addr) || !empty($filter_from_addr)) {
173
+ $from_addr = $filter_from_addr;
174
+ }
175
+ }
176
+
177
+ return $from_addr;
178
+ }
179
+
180
+ /**
181
+ * Parses mail headers into an array of arrays so they can be easily modified.
182
+ * We have to deal with headers that may have boundaries or parts, so a single
183
+ * header like:
184
+ *
185
+ * From: Excited User <user@samples.mailgun.com>
186
+ *
187
+ * Will look like this in array format:
188
+ *
189
+ * array(
190
+ * 'from' => array(
191
+ * 'value' => 'Excited User <user@samples.mailgun.com>',
192
+ * 'boundary' => null,
193
+ * 'parts' => null,
194
+ * )
195
+ * )
196
+ *
197
+ * @param string|array $headers
198
+ *
199
+ * @return array
200
+ *
201
+ * @since 1.5.8
202
+ */
203
+ function mg_parse_headers($headers = array())
204
+ {
205
+ if (empty($headers)) {
206
+ return array();
207
+ }
208
+
209
+ $tmp = array();
210
+ if (!is_array($headers)) {
211
+ $tmp = explode("\n", str_replace("\r\n", "\n", $headers));
212
+ } else {
213
+ $tmp = $headers;
214
+ }
215
+
216
+ $new_headers = array();
217
+ if (!empty($tmp)) {
218
+ $name = null;
219
+ $value = null;
220
+ $boundary = null;
221
+ $parts = null;
222
+
223
+ foreach ((array) $tmp as $header) {
224
+ // If this header does not contain a ':', is it a fold?
225
+ if (false === strpos($header, ':')) {
226
+ // Does this header have a boundary?
227
+ if (false !== stripos($header, 'boundary=')) {
228
+ $parts = preg_split('/boundary=/i', trim($header));
229
+ $boundary = trim(str_replace(array('"', '\''), '', $parts[1]));
230
+ }
231
+ $value .= $header;
232
+
233
+ continue;
234
+ }
235
+
236
+ // Explode the header
237
+ list($name, $value) = explode(':', trim($header), 2);
238
+
239
+ // Clean up the values
240
+ $name = trim($name);
241
+ $value = trim($value);
242
+
243
+ $new_headers[$name] = array(
244
+ 'value' => $value,
245
+ 'boundary' => $boundary,
246
+ 'parts' => $parts,
247
+ );
248
+ }
249
+ }
250
+
251
+ return $new_headers;
252
+ }
253
+
254
+ /**
255
+ * Takes a header array in the format produced by mg_parse_headers and
256
+ * dumps them down in to a submittable header format.
257
+ *
258
+ * @param array $headers Headers to dump
259
+ *
260
+ * @return string String of \r\n separated headers
261
+ *
262
+ * @since 1.5.8
263
+ */
264
+ function mg_dump_headers($headers = null)
265
+ {
266
+ if (is_null($headers) || !is_array($headers)) {
267
+ return '';
268
+ }
269
+
270
+ $header_string = '';
271
+ foreach ($headers as $name => $content) {
272
+ // XXX - Is it actually okay to discard `parts` and `boundary`?
273
+ $header_string .= sprintf("%s: %s\r\n", $name, $content['value']);
274
+ }
275
+
276
+ return $header_string;
277
+ }
includes/{wp-mail.php → wp-mail-api.php} RENAMED
@@ -19,6 +19,11 @@
19
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
  */
21
 
 
 
 
 
 
22
  /**
23
  * mg_api_last_error is a compound getter/setter for the last error that was
24
  * encountered during a Mailgun API call.
@@ -43,32 +48,7 @@ function mg_api_last_error($error = null)
43
  }
44
  }
45
 
46
- /**
47
- * Tries several methods to get the MIME Content-Type of a file.
48
- *
49
- * @param string $filepath
50
- * @param string $default_type If all methods fail, fallback to $default_type
51
- *
52
- * @return string Content-Type
53
- *
54
- * @since 1.5.4
55
- */
56
- function get_mime_content_type($filepath, $default_type = 'text/plain')
57
- {
58
- if (function_exists('mime_content_type')) {
59
- return mime_content_type($filepath);
60
- } elseif (function_exists('finfo_file')) {
61
- $fi = finfo_open(FILEINFO_MIME_TYPE);
62
- $ret = finfo_file($fi, $filepath);
63
- finfo_close($fi);
64
-
65
- return $ret;
66
- } else {
67
- return $default_type;
68
- }
69
- }
70
-
71
- /**
72
  * Wordpress filter to mutate a `To` header to use recipient variables.
73
  * Uses the `mg_use_recipient_vars_syntax` filter to apply the actual
74
  * change. Otherwise, just a list of `To` addresses will be returned.
@@ -93,7 +73,7 @@ function mg_mutate_to_rcpt_vars_cb($to_addrs)
93
 
94
  $idx = 0;
95
  foreach ($to_addrs as $addr) {
96
- $rcpt_vars[$addr] = array("batch_msg_id" => $idx);
97
  $idx++;
98
  }
99
 
@@ -223,65 +203,17 @@ function wp_mail($to, $subject, $message, $headers = '', $attachments = array())
223
  }
224
  }
225
 
226
- if ($mailgun['override-from'] && !empty($mailgun['from-name'])
227
- && !empty($mailgun['from-address'])
228
- ) {
229
- $from_name = $mailgun['from-name'];
230
- $from_email = $mailgun['from-address'];
231
- } else {
232
- // From email and name
233
- // If we don't have a name from the input headers
234
- if (empty($from_name) && !empty($mailgun['from-name'])) {
235
- $from_name = $mailgun['from-name'];
236
- } elseif (empty($from_email) && empty($mailgun['from-name'])) {
237
- if (function_exists('get_current_site')) {
238
- $from_name = get_current_site()->site_name;
239
- } else {
240
- $from_name = 'WordPress';
241
- }
242
- }
243
-
244
- /* If we don't have `From` input headers, use wordpress@$sitedomain
245
- * Some hosts will block outgoing mail from this address if it doesn't
246
- * exist but there's no easy alternative. Defaulting to admin_email
247
- * might appear to be another option but some hosts may refuse to
248
- * relay mail from an unknown domain.
249
- *
250
- * @link http://trac.wordpress.org/ticket/5007.
251
- */
252
-
253
- if (empty($from_email) && !empty($mailgun['from-address'])) {
254
- $from_email = $mailgun['from-address'];
255
- } elseif (empty($from_email) && empty($mailgun['from-address'])) {
256
- if (function_exists('get_current_site')) {
257
- $sitedomain = get_current_site()->domain;
258
- } else {
259
- // Get the site domain and get rid of www.
260
- $sitedomain = strtolower($_SERVER['SERVER_NAME']);
261
- if (substr($sitedomain, 0, 4) == 'www.') {
262
- $sitedomain = substr($sitedomain, 4);
263
- }
264
- }
265
-
266
- $from_email = 'wordpress@'.$sitedomain;
267
- }
268
-
269
- // Attempt to apply external filters to these values before using our own.
270
- if (has_filter('wp_mail_from')) {
271
- $from_email = apply_filters(
272
- 'wp_mail_from',
273
- $from_email
274
- );
275
- }
276
 
277
- if (has_filter('wp_mail_from_name')) {
278
- $from_name = apply_filters(
279
- 'wp_mail_from_name',
280
- $from_name
281
- );
282
- }
283
  }
284
 
 
 
 
285
  $body = array(
286
  'from' => "{$from_name} <{$from_email}>",
287
  'to' => $to,
19
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
  */
21
 
22
+ // Include MG filter functions
23
+ if (!include dirname(__FILE__).'/mg-filter.php') {
24
+ Mailgun::deactivate_and_die(dirname(__FILE__).'/mg-filter.php');
25
+ }
26
+
27
  /**
28
  * mg_api_last_error is a compound getter/setter for the last error that was
29
  * encountered during a Mailgun API call.
48
  }
49
  }
50
 
51
+ /*
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  * Wordpress filter to mutate a `To` header to use recipient variables.
53
  * Uses the `mg_use_recipient_vars_syntax` filter to apply the actual
54
  * change. Otherwise, just a list of `To` addresses will be returned.
73
 
74
  $idx = 0;
75
  foreach ($to_addrs as $addr) {
76
+ $rcpt_vars[$addr] = array('batch_msg_id' => $idx);
77
  $idx++;
78
  }
79
 
203
  }
204
  }
205
 
206
+ if (!isset($from_name)) {
207
+ $from_name = null;
208
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
 
210
+ if (!isset($from_email)) {
211
+ $from_email = null;
 
 
 
 
212
  }
213
 
214
+ $from_name = mg_detect_from_name($from_name);
215
+ $from_email = mg_detect_from_address($from_email);
216
+
217
  $body = array(
218
  'from' => "{$from_name} <{$from_email}>",
219
  'to' => $to,
includes/wp-mail-smtp.php ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * mailgun-wordpress-plugin - Sending mail from Wordpress using Mailgun
5
+ * Copyright (C) 2016 Mailgun, et al.
6
+ *
7
+ * This program is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ * GNU General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License along
18
+ * with this program; if not, write to the Free Software Foundation, Inc.,
19
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
+ */
21
+
22
+ // Include MG filter functions
23
+ if (!include dirname(__FILE__).'/mg-filter.php') {
24
+ Mailgun::deactivate_and_die(dirname(__FILE__).'/mg-filter.php');
25
+ }
26
+
27
+ /**
28
+ * mg_smtp_last_error is a compound getter/setter for the last error that was
29
+ * encountered during a Mailgun SMTP conversation.
30
+ *
31
+ * @param string $error OPTIONAL
32
+ *
33
+ * @return string Last error that occurred.
34
+ *
35
+ * @since 1.5.0
36
+ */
37
+ function mg_smtp_last_error($error = null)
38
+ {
39
+ static $last_error;
40
+
41
+ if (null === $error) {
42
+ return $last_error;
43
+ } else {
44
+ $tmp = $last_error;
45
+ $last_error = $error;
46
+
47
+ return $tmp;
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Debugging output function for PHPMailer.
53
+ *
54
+ * @param string $str Log message
55
+ * @param string $level Logging level
56
+ *
57
+ * @return none
58
+ *
59
+ * @since 1.5.7
60
+ */
61
+ function mg_smtp_debug_output($str, $level)
62
+ {
63
+ if (defined('MG_DEBUG_SMTP') && MG_DEBUG_SMTP) {
64
+ error_log("PHPMailer [$level] $str");
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Capture and store the failure message from PHPmailer so the user will
70
+ * actually know what is wrong.
71
+ *
72
+ * @param WP_Error $error Error raised by Wordpress/PHPmailer
73
+ *
74
+ * @return none
75
+ *
76
+ * @since 1.5.7
77
+ */
78
+ function wp_mail_failed($error)
79
+ {
80
+ if (is_wp_error($error)) {
81
+ mg_smtp_last_error($error->get_error_message());
82
+ } else {
83
+ mg_smtp_last_error($error->__toString());
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Provides a `wp_mail` compatible filter for SMTP sends through the
89
+ * Wordpress PHPmailer transport.
90
+ *
91
+ * @param array $args Compacted array of arguments.
92
+ *
93
+ * @return array Compacted array of arguments.
94
+ *
95
+ * @since 1.5.8
96
+ */
97
+ function mg_smtp_mail_filter(array $args)
98
+ {
99
+ // Extract the arguments from array to ($to, $subject, $message, $headers, $attachments)
100
+ extract($args);
101
+
102
+ // $headers and $attachments are optional - make sure they exist
103
+ $headers = (!isset($headers)) ? '' : $headers;
104
+ $attachments = (!isset($attachments)) ? array() : $attachments;
105
+
106
+ $mg_opts = get_option('mailgun');
107
+ $mg_headers = mg_parse_headers($headers);
108
+
109
+ // Filter the `From:` header
110
+ $from_header = (isset($mg_headers['From'])) ? $mg_headers['From'] : null;
111
+
112
+ list($from_name, $from_addr) = array(null, null);
113
+ if (!is_null($from_header)) {
114
+ $content = $from_header['value'];
115
+ $boundary = $from_header['boundary'];
116
+ $parts = $from_header['parts'];
117
+
118
+ if (strpos($content, '<') !== false) {
119
+ $from_name = substr($content, 0, strpos($content, '<') - 1);
120
+ $from_name = str_replace('"', '', $from_name);
121
+ $from_name = trim($from_name);
122
+
123
+ $from_addr = substr($content, strpos($content, '<') + 1);
124
+ $from_addr = str_replace('>', '', $from_addr);
125
+ $from_addr = trim($from_addr);
126
+ } else {
127
+ $from_addr = trim($content);
128
+ }
129
+ }
130
+
131
+ if (!isset($from_name)) {
132
+ $from_name = null;
133
+ }
134
+
135
+ if (!isset($from_addr)) {
136
+ $from_addr = null;
137
+ }
138
+
139
+ $from_name = mg_detect_from_name($from_name);
140
+ $from_addr = mg_detect_from_address($from_addr);
141
+
142
+ $from_header['value'] = sprintf('%s <%s>', $from_name, $from_addr);
143
+ $mg_headers['From'] = $from_header;
144
+
145
+ // Header compaction
146
+ $headers = mg_dump_headers($mg_headers);
147
+
148
+ return compact('to', 'subject', 'message', 'headers', 'attachments');
149
+ }
mailgun.php CHANGED
@@ -4,7 +4,7 @@
4
  * Plugin Name: Mailgun
5
  * Plugin URI: http://wordpress.org/extend/plugins/mailgun/
6
  * Description: Mailgun integration for WordPress
7
- * Version: 1.5.7
8
  * Author: Mailgun
9
  * Author URI: http://www.mailgun.com/
10
  * License: GPLv2 or later
@@ -31,45 +31,6 @@
31
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32
  */
33
 
34
- /**
35
- * mg_smtp_last_error is a compound getter/setter for the last error that was
36
- * encountered during a Mailgun SMTP conversation.
37
- *
38
- * @param string $error OPTIONAL
39
- *
40
- * @return string Last error that occurred.
41
- *
42
- * @since 1.5.0
43
- */
44
- function mg_smtp_last_error($error = null)
45
- {
46
- static $last_error;
47
-
48
- if (null === $error) {
49
- return $last_error;
50
- } else {
51
- $tmp = $last_error;
52
- $last_error = $error;
53
-
54
- return $tmp;
55
- }
56
- }
57
-
58
- /**
59
- * Debugging output function for PHPMailer.
60
- *
61
- * @param string $str Log message
62
- * @param string $level Logging level
63
- *
64
- * @return none
65
- *
66
- * @since 1.5.7
67
- */
68
- function phpmailer_debug_output($str, $level)
69
- {
70
- error_log("PHPMailer [$level] $str");
71
- }
72
-
73
  /**
74
  * Entrypoint for the Mailgun plugin. Sets up the mailing "strategy" -
75
  * either API or SMTP.
@@ -95,15 +56,24 @@ class Mailgun
95
 
96
  // Either override the wp_mail function or configure PHPMailer to use the
97
  // Mailgun SMTP servers
 
 
98
  if ($this->get_option('useAPI') || (defined('MAILGUN_USEAPI') && MAILGUN_USEAPI)) {
99
  if (!function_exists('wp_mail')) {
100
- if (!@include dirname(__FILE__).'/includes/wp-mail.php') {
101
- self::deactivate_and_die(dirname(__FILE__).'/includes/wp-mail.php');
102
  }
103
  }
104
  } else {
 
 
 
 
 
 
 
105
  add_action('phpmailer_init', array(&$this, 'phpmailer_init'));
106
- add_action('wp_mail_failed', array(&$this, 'wp_mail_failed'));
107
  }
108
  }
109
 
@@ -146,9 +116,6 @@ class Mailgun
146
  $secure = (defined('MAILGUN_SECURE') && MAILGUN_SECURE) ? MAILGUN_SECURE : $this->get_option('secure');
147
  $password = (defined('MAILGUN_PASSWORD') && MAILGUN_PASSWORD) ? MAILGUN_PASSWORD : $this->get_option('password');
148
 
149
- $from_name = (defined('MAILGUN_FROM_NAME') && MAILGUN_FROM_NAME) ? MAILGUN_FROM_NAME : $this->detect_from_name();
150
- $from_address = (defined('MAILGUN_FROM_ADDRESS') && MAILGUN_FROM_ADDRESS) ? MAILGUN_FROM_ADDRESS : $this->detect_from_address();
151
-
152
  $phpmailer->Mailer = 'smtp';
153
  $phpmailer->Host = 'smtp.mailgun.org';
154
  $phpmailer->Port = (bool) $secure ? 465 : 587;
@@ -158,29 +125,8 @@ class Mailgun
158
 
159
  $phpmailer->SMTPSecure = (bool) $secure ? 'ssl' : 'none';
160
  // Without this line... wp_mail for SMTP-only will always return false. But why? :(
161
- $phpmailer->Debugoutput = 'phpmailer_debug_output';
162
  $phpmailer->SMTPDebug = 2;
163
- $phpmailer->From = $from_address;
164
- $phpmailer->FromName = $from_name;
165
- }
166
-
167
- /**
168
- * Capture and store the failure message from PHPmailer so the user will
169
- * actually know what is wrong.
170
- *
171
- * @param WP_Error $error Error raised by Wordpress/PHPmailer
172
- *
173
- * @return none
174
- *
175
- * @since 1.5.7
176
- */
177
- public function wp_mail_failed($error)
178
- {
179
- if (is_wp_error($error)) {
180
- mg_smtp_last_error($error->get_error_message());
181
- } else {
182
- mg_smtp_last_error($error->__toString());
183
- }
184
  }
185
 
186
  /**
@@ -221,7 +167,7 @@ class Mailgun
221
  $time = time();
222
  $url = $this->api_endpoint.$uri;
223
  $headers = array(
224
- 'Authorization' => 'Basic '.base64_encode("api:{$apiKey}")
225
  );
226
 
227
  switch ($method) {
@@ -491,81 +437,6 @@ class Mailgun
491
  register_widget('list_widget');
492
  add_shortcode('mailgun', array(&$this, 'build_list_form'));
493
  }
494
-
495
- /**
496
- * Find the sending "From Name" with a similar process used in `wp_mail`.
497
- *
498
- * @return string
499
- *
500
- * @since 1.5.7
501
- */
502
- private function detect_from_name()
503
- {
504
- $from_name = null;
505
-
506
- if ($this->get_option('override-from') && !is_null($this->get_option('from-name'))) {
507
- $from_name = $this->get_option('from-name');
508
- } else {
509
- if (is_null($this->get_option('from-name'))) {
510
- if (function_exists('get_current_site')) {
511
- $from_name = get_current_site()->site_name;
512
- } else {
513
- $from_name = 'WordPress';
514
- }
515
- } else {
516
- $from_name = $this->get_option('from-name');
517
- }
518
- }
519
-
520
- if (has_filter('wp_mail_from_name')) {
521
- $from_name = apply_filters(
522
- 'wp_mail_from_name',
523
- $from_name
524
- );
525
- }
526
-
527
- return $from_name;
528
- }
529
-
530
- /**
531
- * Find the sending "From Address" with a similar process used in `wp_mail`.
532
- *
533
- * @return string
534
- *
535
- * @since 1.5.7
536
- */
537
- private function detect_from_address()
538
- {
539
- $from_addr = null;
540
-
541
- if ($this->get_option('override-from') && !is_null($this->get_option('from-address'))) {
542
- $from_addr = $this->get_option('from-address');
543
- } else {
544
- if (is_null($this->get_option('from-address'))) {
545
- if (function_exists('get_current_site')) {
546
- $from_addr = get_current_site()->domain;
547
- } else {
548
- $sitedomain = strtolower($_SERVER['SERVER_NAME']);
549
- if (substr($sitedomain, 0, 4) === 'www.') {
550
- $sitedomain = substr($sitedomain, 4);
551
- }
552
- }
553
-
554
- $from_addr = $sitedomain;
555
- } else {
556
- $from_addr = $this->get_option('from-address');
557
- }
558
- }
559
-
560
- if (has_filter('wp_mail_from')) {
561
- $from_addr = apply_filters(
562
- 'wp_mail_from',
563
- $from_addr
564
- );
565
- }
566
-
567
- return $from_addr;
568
- }
569
  }
570
 
571
  $mailgun = new Mailgun();
4
  * Plugin Name: Mailgun
5
  * Plugin URI: http://wordpress.org/extend/plugins/mailgun/
6
  * Description: Mailgun integration for WordPress
7
+ * Version: 1.5.8.1
8
  * Author: Mailgun
9
  * Author URI: http://www.mailgun.com/
10
  * License: GPLv2 or later
31
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32
  */
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  /**
35
  * Entrypoint for the Mailgun plugin. Sets up the mailing "strategy" -
36
  * either API or SMTP.
56
 
57
  // Either override the wp_mail function or configure PHPMailer to use the
58
  // Mailgun SMTP servers
59
+ // When using SMTP, we also need to inject a `wp_mail` filter to make "from" settings
60
+ // work properly. Fixes issues with 1.5.7+
61
  if ($this->get_option('useAPI') || (defined('MAILGUN_USEAPI') && MAILGUN_USEAPI)) {
62
  if (!function_exists('wp_mail')) {
63
+ if (!include dirname(__FILE__).'/includes/wp-mail-api.php') {
64
+ self::deactivate_and_die(dirname(__FILE__).'/includes/wp-mail-api.php');
65
  }
66
  }
67
  } else {
68
+ // Using SMTP, include the SMTP filter
69
+ if (!function_exists('mg_smtp_mail_filter')) {
70
+ if (!include dirname(__FILE__).'/includes/wp-mail-smtp.php') {
71
+ self::deactivate_and_die(dirname(__FILE__).'/includes/wp-mail-smtp.php');
72
+ }
73
+ }
74
+ add_filter('wp_mail', 'mg_smtp_mail_filter');
75
  add_action('phpmailer_init', array(&$this, 'phpmailer_init'));
76
+ add_action('wp_mail_failed', 'wp_mail_failed');
77
  }
78
  }
79
 
116
  $secure = (defined('MAILGUN_SECURE') && MAILGUN_SECURE) ? MAILGUN_SECURE : $this->get_option('secure');
117
  $password = (defined('MAILGUN_PASSWORD') && MAILGUN_PASSWORD) ? MAILGUN_PASSWORD : $this->get_option('password');
118
 
 
 
 
119
  $phpmailer->Mailer = 'smtp';
120
  $phpmailer->Host = 'smtp.mailgun.org';
121
  $phpmailer->Port = (bool) $secure ? 465 : 587;
125
 
126
  $phpmailer->SMTPSecure = (bool) $secure ? 'ssl' : 'none';
127
  // Without this line... wp_mail for SMTP-only will always return false. But why? :(
128
+ $phpmailer->Debugoutput = 'mg_smtp_debug_output';
129
  $phpmailer->SMTPDebug = 2;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  }
131
 
132
  /**
167
  $time = time();
168
  $url = $this->api_endpoint.$uri;
169
  $headers = array(
170
+ 'Authorization' => 'Basic '.base64_encode("api:{$apiKey}"),
171
  );
172
 
173
  switch ($method) {
437
  register_widget('list_widget');
438
  add_shortcode('mailgun', array(&$this, 'build_list_form'));
439
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
440
  }
441
 
442
  $mailgun = new Mailgun();
readme.txt CHANGED
@@ -5,7 +5,7 @@ Contributors: Mailgun, sivel, lookahead.io, m35dev
5
  Tags: mailgun, smtp, http, api, mail, email
6
  Requires at least: 3.3
7
  Tested up to: 4.7.1
8
- Stable tag: 1.5.7
9
  License: GPLv2 or later
10
 
11
 
@@ -42,6 +42,12 @@ Your web server may not allow outbound HTTP connections. Set `Use HTTP API` to "
42
 
43
  Your web server may not allow outbound SMTP connections on port 465 for secure connections or 587 for unsecured connections. Try changing `Use Secure SMTP` to "No" or "Yes" depending on your current configuration and testing again. If both fail, try setting `Use HTTP API` to "Yes" and testing again.
44
 
 
 
 
 
 
 
45
  - Can this be configured globally for WordPress Multisite?
46
 
47
  Yes, using the following constants that can be placed in wp-config.php:
@@ -70,6 +76,20 @@ MAILGUN_FROM_ADDRESS Type: string
70
 
71
  == Changelog ==
72
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  = 1.5.7 (2017-01-04): =
74
  * Add better support for using recipient variables for batch mailing.
75
  * Clarify wording on `From Address` note
5
  Tags: mailgun, smtp, http, api, mail, email
6
  Requires at least: 3.3
7
  Tested up to: 4.7.1
8
+ Stable tag: 1.5.8.1
9
  License: GPLv2 or later
10
 
11
 
42
 
43
  Your web server may not allow outbound SMTP connections on port 465 for secure connections or 587 for unsecured connections. Try changing `Use Secure SMTP` to "No" or "Yes" depending on your current configuration and testing again. If both fail, try setting `Use HTTP API` to "Yes" and testing again.
44
 
45
+ If you *have* to use SMTP and something is still going horribly wrong, enable debug mode in WordPress and also add the `MG_DEBUG_SMTP` constant to your `wp-config.php`, like so:
46
+
47
+ `
48
+ define( 'MG_DEBUG_SMTP', true );
49
+ `
50
+
51
  - Can this be configured globally for WordPress Multisite?
52
 
53
  Yes, using the following constants that can be placed in wp-config.php:
76
 
77
  == Changelog ==
78
 
79
+ = 1.5.8.1 (2017-02-06): =
80
+ - Fix "Undefined property: MailgunAdmin::$hook_suffix" (#48)
81
+ - Fix "Undefined variable: from_name on every email process" (API and SMTP) (#49)
82
+ - Admin code now loads only on admin user access
83
+
84
+ = 1.5.8 (2017-01-23): =
85
+ * Rewrite a large chunk of old SMTP code
86
+ * Fix a bug with SMTP + "override from" that was introduced in 1.5.7
87
+ * SMTP debug logging is now controlled by `MG_DEBUG_SMTP` constant
88
+
89
+ = 1.5.7.1 (2017-01-18): =
90
+ * Fix an odd `Undefined property: MailgunAdmin::$defaults` when saving config
91
+ * Fix strict mode notice for using `$mailgun['override-from']` without checking `isset`
92
+
93
  = 1.5.7 (2017-01-04): =
94
  * Add better support for using recipient variables for batch mailing.
95
  * Clarify wording on `From Address` note