Mailgun for WordPress - Version 1.8.1

Version Description

(2022-08-19): = - backward compatibility with php7.0

Download this release

Release Info

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

Code changes from version 1.8.2 to 1.8.1

Files changed (6) hide show
  1. .gitignore +1 -2
  2. includes/admin.php +56 -60
  3. includes/wp-mail-api.php +319 -303
  4. mailgun.php +1 -1
  5. readme.md +1 -4
  6. readme.txt +1 -4
.gitignore CHANGED
@@ -1,4 +1,3 @@
1
  svn/
2
  .idea/
3
- docker-compose.yaml
4
- .git
1
  svn/
2
  .idea/
3
+ docker-compose.yaml
 
includes/admin.php CHANGED
@@ -26,13 +26,6 @@ class MailgunAdmin extends Mailgun
26
  */
27
  private $defaults;
28
 
29
- /**
30
- * @var array
31
- */
32
- protected $options = [];
33
-
34
- protected $hook_suffix;
35
-
36
  /**
37
  * Setup backend functionality in WordPress.
38
  *
@@ -70,9 +63,9 @@ class MailgunAdmin extends Mailgun
70
  public function init()
71
  {
72
  $sitename = strtolower($_SERVER['SERVER_NAME']);
73
- if (substr($sitename, 0, 4) === 'www.') {
74
  $sitename = substr($sitename, 4);
75
- }
76
 
77
  $region = (defined('MAILGUN_REGION') && MAILGUN_REGION) ? MAILGUN_REGION : $this->get_option('region');
78
  $regionDefault = $region ?: 'us';
@@ -92,10 +85,10 @@ class MailgunAdmin extends Mailgun
92
  'override-from' => '0',
93
  'tag' => $sitename,
94
  );
95
- if (!$this->options) {
96
  $this->options = $this->defaults;
97
  add_option('mailgun', $this->options);
98
- }
99
  }
100
 
101
  /**
@@ -107,7 +100,7 @@ class MailgunAdmin extends Mailgun
107
  */
108
  public function admin_menu()
109
  {
110
- if (current_user_can('manage_options')) {
111
  $this->hook_suffix = add_options_page(__('Mailgun', 'mailgun'), __('Mailgun', 'mailgun'),
112
  'manage_options', 'mailgun', array(&$this, 'options_page'));
113
  add_options_page(__('Mailgun Lists', 'mailgun'), __('Mailgun Lists', 'mailgun'), 'manage_options',
@@ -115,7 +108,7 @@ class MailgunAdmin extends Mailgun
115
  add_action("admin_print_scripts-{$this->hook_suffix}", array(&$this, 'admin_js'));
116
  add_filter("plugin_action_links_{$this->plugin_basename}", array(&$this, 'filter_plugin_actions'));
117
  add_action("admin_footer-{$this->hook_suffix}", array(&$this, 'admin_footer_js'));
118
- }
119
  }
120
 
121
  /**
@@ -205,10 +198,10 @@ class MailgunAdmin extends Mailgun
205
  */
206
  public function options_page()
207
  {
208
- if (!@include 'options-page.php') {
209
  printf(__('<div id="message" class="updated fade"><p>The options page for the <strong>Mailgun</strong> plugin cannot be displayed. The file <strong>%s</strong> is missing. Please reinstall the plugin.</p></div>',
210
- 'mailgun'), __DIR__ . '/options-page.php');
211
- }
212
  }
213
 
214
  /**
@@ -220,10 +213,10 @@ class MailgunAdmin extends Mailgun
220
  */
221
  public function lists_page()
222
  {
223
- if (!@include 'lists-page.php') {
224
  printf(__('<div id="message" class="updated fade"><p>The lists page for the <strong>Mailgun</strong> plugin cannot be displayed. The file <strong>%s</strong> is missing. Please reinstall the plugin.</p></div>',
225
- 'mailgun'), __DIR__ . '/lists-page.php');
226
- }
227
  }
228
 
229
  /**
@@ -267,7 +260,7 @@ class MailgunAdmin extends Mailgun
267
  *
268
  * @since 0.1
269
  */
270
- public function validation(array $options)
271
  {
272
  $apiKey = trim($options['apiKey']);
273
  $username = trim($options['username']);
@@ -391,7 +384,6 @@ class MailgunAdmin extends Mailgun
391
  *
392
  * @return string
393
  *
394
- * @throws JsonException
395
  * @since 0.1
396
  */
397
  public function ajax_send_test()
@@ -414,25 +406,26 @@ class MailgunAdmin extends Mailgun
414
  $secure = (defined('MAILGUN_SECURE') && MAILGUN_SECURE) ? MAILGUN_SECURE : $this->get_option('secure');
415
  $sectype = (defined('MAILGUN_SECTYPE') && MAILGUN_SECTYPE) ? MAILGUN_SECTYPE : $this->get_option('sectype');
416
 
417
- if (!$getRegion) {
418
  mg_api_last_error(__("Region has not been selected", "mailgun"));
419
- } else {
420
- if ($getRegion === 'us') {
421
  $region = __("U.S./North America", "mailgun");
422
- }
423
- if ($getRegion === "eu") {
 
424
  $region = __("Europe", "mailgun");
425
- }
426
- }
427
 
428
- if ($useAPI) {
429
  $method = __('HTTP API', 'mailgun');
430
- } else {
431
- $method = ($secure) ? __('Secure SMTP', 'mailgun') : __('Insecure SMTP', 'mailgun');
432
- if ($secure) {
433
- $method .= sprintf(__(' via %s', 'mailgun'), $sectype);
434
- }
435
- }
436
 
437
  $admin_email = get_option('admin_email');
438
  $result = wp_mail(
@@ -440,51 +433,54 @@ class MailgunAdmin extends Mailgun
440
  __('Mailgun WordPress Plugin Test', 'mailgun'),
441
  sprintf(__("This is a test email generated by the Mailgun WordPress plugin.\n\nIf you have received this message, the requested test has succeeded.\n\nThe sending region is set to %s.\n\nThe method used to send this email was: %s.",
442
  'mailgun'), $region, $method),
443
- ['Content-Type: text/plain']
444
  );
445
 
446
- if ($useAPI) {
447
- if (!function_exists('mg_api_last_error')) {
448
- if (!include __DIR__ . '/wp-mail-api.php') {
449
  $this->deactivate_and_die(__DIR__ . '/wp-mail-api.php');
450
- }
451
- }
 
452
  $error_msg = mg_api_last_error();
453
- } else {
454
- if (!function_exists('mg_smtp_last_error')) {
455
- if (!include __DIR__ . '/wp-mail-smtp.php') {
456
  $this->deactivate_and_die(__DIR__ . '/wp-mail-smtp.php');
457
- }
458
- }
 
459
  $error_msg = mg_smtp_last_error();
460
- }
461
 
462
  // Admin Email is used as 'to' parameter, but in case of 'Test Configuration' this message is not clear for the user, so replaced with more appropriate one
463
- if (false !== strpos($error_msg, "'to'") && false !== strpos($error_msg, 'is not a valid')) {
464
  $error_msg = sprintf(
465
  "Administration Email Address (%s) is not valid and can't be used for test, you can change it at General Setting page",
466
  $admin_email
467
  );
468
- }
469
 
470
- if ($result) {
471
  die(
472
- json_encode(array(
473
- 'message' => __('Success', 'mailgun'),
474
- 'method' => $method,
475
- 'error' => __('Success', 'mailgun'),
476
- ), JSON_THROW_ON_ERROR)
477
  );
478
- }
 
 
479
 
480
- // Error message will always be returned in case of failure, if not - connection wasn't successful
481
- $error_msg = $error_msg ? $error_msg : "Can't connect to Mailgun";
482
- die(
483
  json_encode(array(
484
  'message' => __('Failure', 'mailgun'),
485
  'method' => $method,
486
  'error' => $error_msg,
487
  ), JSON_THROW_ON_ERROR)
488
- );
 
489
  }
490
  }
26
  */
27
  private $defaults;
28
 
 
 
 
 
 
 
 
29
  /**
30
  * Setup backend functionality in WordPress.
31
  *
63
  public function init()
64
  {
65
  $sitename = strtolower($_SERVER['SERVER_NAME']);
66
+ if (substr($sitename, 0, 4) == 'www.'):
67
  $sitename = substr($sitename, 4);
68
+ endif;
69
 
70
  $region = (defined('MAILGUN_REGION') && MAILGUN_REGION) ? MAILGUN_REGION : $this->get_option('region');
71
  $regionDefault = $region ?: 'us';
85
  'override-from' => '0',
86
  'tag' => $sitename,
87
  );
88
+ if (!$this->options):
89
  $this->options = $this->defaults;
90
  add_option('mailgun', $this->options);
91
+ endif;
92
  }
93
 
94
  /**
100
  */
101
  public function admin_menu()
102
  {
103
+ if (current_user_can('manage_options')):
104
  $this->hook_suffix = add_options_page(__('Mailgun', 'mailgun'), __('Mailgun', 'mailgun'),
105
  'manage_options', 'mailgun', array(&$this, 'options_page'));
106
  add_options_page(__('Mailgun Lists', 'mailgun'), __('Mailgun Lists', 'mailgun'), 'manage_options',
108
  add_action("admin_print_scripts-{$this->hook_suffix}", array(&$this, 'admin_js'));
109
  add_filter("plugin_action_links_{$this->plugin_basename}", array(&$this, 'filter_plugin_actions'));
110
  add_action("admin_footer-{$this->hook_suffix}", array(&$this, 'admin_footer_js'));
111
+ endif;
112
  }
113
 
114
  /**
198
  */
199
  public function options_page()
200
  {
201
+ if (!@include 'options-page.php'):
202
  printf(__('<div id="message" class="updated fade"><p>The options page for the <strong>Mailgun</strong> plugin cannot be displayed. The file <strong>%s</strong> is missing. Please reinstall the plugin.</p></div>',
203
+ 'mailgun'), dirname(__FILE__) . '/options-page.php');
204
+ endif;
205
  }
206
 
207
  /**
213
  */
214
  public function lists_page()
215
  {
216
+ if (!@include 'lists-page.php'):
217
  printf(__('<div id="message" class="updated fade"><p>The lists page for the <strong>Mailgun</strong> plugin cannot be displayed. The file <strong>%s</strong> is missing. Please reinstall the plugin.</p></div>',
218
+ 'mailgun'), dirname(__FILE__) . '/lists-page.php');
219
+ endif;
220
  }
221
 
222
  /**
260
  *
261
  * @since 0.1
262
  */
263
+ public function validation($options)
264
  {
265
  $apiKey = trim($options['apiKey']);
266
  $username = trim($options['username']);
384
  *
385
  * @return string
386
  *
 
387
  * @since 0.1
388
  */
389
  public function ajax_send_test()
406
  $secure = (defined('MAILGUN_SECURE') && MAILGUN_SECURE) ? MAILGUN_SECURE : $this->get_option('secure');
407
  $sectype = (defined('MAILGUN_SECTYPE') && MAILGUN_SECTYPE) ? MAILGUN_SECTYPE : $this->get_option('sectype');
408
 
409
+ if ((bool)!$getRegion):
410
  mg_api_last_error(__("Region has not been selected", "mailgun"));
411
+ else:
412
+ if ($getRegion === 'us'):
413
  $region = __("U.S./North America", "mailgun");
414
+ endif;
415
+
416
+ if ($getRegion === "eu"):
417
  $region = __("Europe", "mailgun");
418
+ endif;
419
+ endif;
420
 
421
+ if ((bool)$useAPI):
422
  $method = __('HTTP API', 'mailgun');
423
+ else:
424
+ $method = ((bool)$secure) ? __('Secure SMTP', 'mailgun') : __('Insecure SMTP', 'mailgun');
425
+ if ((bool)$secure):
426
+ $method = $method . sprintf(__(' via %s', 'mailgun'), $sectype);
427
+ endif;
428
+ endif;
429
 
430
  $admin_email = get_option('admin_email');
431
  $result = wp_mail(
433
  __('Mailgun WordPress Plugin Test', 'mailgun'),
434
  sprintf(__("This is a test email generated by the Mailgun WordPress plugin.\n\nIf you have received this message, the requested test has succeeded.\n\nThe sending region is set to %s.\n\nThe method used to send this email was: %s.",
435
  'mailgun'), $region, $method),
436
+ array('Content-Type: text/plain')
437
  );
438
 
439
+ if ((bool)$useAPI):
440
+ if (!function_exists('mg_api_last_error')):
441
+ if (!include __DIR__ . '/wp-mail-api.php'):
442
  $this->deactivate_and_die(__DIR__ . '/wp-mail-api.php');
443
+ endif;
444
+ endif;
445
+
446
  $error_msg = mg_api_last_error();
447
+ else:
448
+ if (!function_exists('mg_smtp_last_error')):
449
+ if (!include __DIR__ . '/wp-mail-smtp.php'):
450
  $this->deactivate_and_die(__DIR__ . '/wp-mail-smtp.php');
451
+ endif;
452
+ endif;
453
+
454
  $error_msg = mg_smtp_last_error();
455
+ endif;
456
 
457
  // Admin Email is used as 'to' parameter, but in case of 'Test Configuration' this message is not clear for the user, so replaced with more appropriate one
458
+ if (false !== strpos($error_msg, "'to'") && false !== strpos($error_msg, 'is not a valid')):
459
  $error_msg = sprintf(
460
  "Administration Email Address (%s) is not valid and can't be used for test, you can change it at General Setting page",
461
  $admin_email
462
  );
463
+ endif;
464
 
465
+ if ($result):
466
  die(
467
+ json_encode(array(
468
+ 'message' => __('Success', 'mailgun'),
469
+ 'method' => $method,
470
+ 'error' => __('Success', 'mailgun'),
471
+ ), JSON_THROW_ON_ERROR)
472
  );
473
+ else:
474
+ // Error message will always be returned in case of failure, if not - connection wasn't successful
475
+ $error_msg = $error_msg ? $error_msg : "Can't connect to Mailgun";
476
 
477
+ die(
 
 
478
  json_encode(array(
479
  'message' => __('Failure', 'mailgun'),
480
  'method' => $method,
481
  'error' => $error_msg,
482
  ), JSON_THROW_ON_ERROR)
483
+ );
484
+ endif;
485
  }
486
  }
includes/wp-mail-api.php CHANGED
@@ -20,19 +20,19 @@
20
  */
21
 
22
  // Include MG filter functions
23
- if (!include __DIR__ . '/mg-filter.php') {
24
- (new Mailgun)->deactivate_and_die(__DIR__ . '/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.
30
  *
31
- * @param string $error OPTIONAL
32
  *
33
- * @return string Last error that occurred.
34
  *
35
- * @since 1.5.0
36
  */
37
  function mg_api_last_error($error = null)
38
  {
@@ -40,12 +40,12 @@ function mg_api_last_error($error = null)
40
 
41
  if (null === $error) {
42
  return $last_error;
43
- }
44
-
45
- $tmp = $last_error;
46
- $last_error = $error;
47
 
48
- return $tmp;
 
49
  }
50
 
51
  /*
@@ -79,14 +79,14 @@ function mg_mutate_to_rcpt_vars_cb($to_addrs)
79
 
80
  // TODO: Also add folding to prevent hitting the 998 char limit on headers.
81
  return array(
82
- 'to' => '%recipient%',
83
  'rcpt_vars' => json_encode($rcpt_vars),
84
  );
85
  }
86
  }
87
 
88
  return array(
89
- 'to' => $to_addrs,
90
  'rcpt_vars' => null,
91
  );
92
  }
@@ -98,351 +98,365 @@ function mg_mutate_to_rcpt_vars_cb($to_addrs)
98
  * Based off of the core wp_mail function, but with modifications required to
99
  * send email using the Mailgun HTTP API
100
  *
101
- * @param string|array $to Array or comma-separated list of email addresses to send message.
102
- * @param string $subject Email subject
103
- * @param string $message Message contents
104
- * @param string|array $headers Optional. Additional headers.
105
- * @param string|array $attachments Optional. Files to attach.
106
  *
107
- * @return bool Whether the email contents were sent successfully.
108
  *
109
  * @global PHPMailer\PHPMailer\PHPMailer $phpmailer
110
  *
111
- * @since 0.1
112
  */
113
  if (!function_exists('wp_mail')) {
114
- function wp_mail($to, $subject, $message, $headers = '', $attachments = array())
115
- {
116
- // Compact the input, apply the filters, and extract them back out
117
- extract(apply_filters('wp_mail', compact('to', 'subject', 'message', 'headers', 'attachments')));
118
-
119
- $mailgun = get_option('mailgun');
120
- $region = (defined('MAILGUN_REGION') && MAILGUN_REGION) ? MAILGUN_REGION : $mailgun['region'];
121
- $apiKey = (defined('MAILGUN_APIKEY') && MAILGUN_APIKEY) ? MAILGUN_APIKEY : $mailgun['apiKey'];
122
- $domain = (defined('MAILGUN_DOMAIN') && MAILGUN_DOMAIN) ? MAILGUN_DOMAIN : $mailgun['domain'];
123
-
124
- if (empty($apiKey) || empty($domain)) {
125
- return false;
126
- }
127
 
128
- // If a region is not set via defines or through the options page, default to US region.
129
- if (!((bool)$region)) {
130
- error_log('[Mailgun] No region configuration was found! Defaulting to US region.');
131
- $region = 'us';
132
- }
133
 
134
- if (!is_array($attachments)) {
135
- $attachments = explode("\n", str_replace("\r\n", "\n", $attachments));
136
- }
 
 
 
 
 
 
137
 
138
- // Headers
139
- if (empty($headers)) {
140
- $headers = [];
 
 
 
 
 
 
 
 
 
141
  } else {
142
- if (!is_array($headers)) {
143
- // Explode the headers out, so this function can take both
144
- // string headers and an array of headers.
145
- $tempheaders = explode("\n", str_replace("\r\n", "\n", $headers));
146
- } else {
147
- $tempheaders = $headers;
148
- }
149
- $headers = [];
150
- $cc = [];
151
- $bcc = [];
152
-
153
- // If it's actually got contents
154
- if (!empty($tempheaders)) {
155
- // Iterate through the raw headers
156
- foreach ((array)$tempheaders as $header) {
157
- if (strpos($header, ':') === false) {
158
- if (false !== stripos($header, 'boundary=')) {
159
- $parts = preg_split('/boundary=/i', trim($header));
160
- $boundary = trim(str_replace(["'", '"'], '', $parts[1]));
161
- }
162
- continue;
163
  }
164
- // Explode them out
165
- list($name, $content) = explode(':', trim($header), 2);
166
-
167
- // Cleanup crew
168
- $name = trim($name);
169
- $content = trim($content);
170
-
171
- switch (strtolower($name)) {
172
- // Mainly for legacy -- process a From: header if it's there
173
- case 'from':
174
- if (strpos($content, '<') !== false) {
175
- // So... making my life hard again?
176
- $from_name = substr($content, 0, strpos($content, '<') - 1);
177
- $from_name = str_replace('"', '', $from_name);
178
- $from_name = trim($from_name);
179
-
180
- $from_email = substr($content, strpos($content, '<') + 1);
181
- $from_email = str_replace('>', '', $from_email);
182
- $from_email = trim($from_email);
183
- } else {
184
- $from_email = trim($content);
185
- }
186
- break;
187
- case 'content-type':
188
- if (strpos($content, ';') !== false) {
189
- list($type, $charset) = explode(';', $content);
190
- $content_type = trim($type);
191
- if (false !== stripos($charset, 'charset=')) {
192
- $charset = trim(str_replace(array('charset=', '"'), '', $charset));
193
- } elseif (false !== stripos($charset, 'boundary=')) {
194
- $boundary = trim(str_replace(array('BOUNDARY=', 'boundary=', '"'), '', $charset));
195
- $charset = '';
196
- }
197
- } else {
198
- $content_type = trim($content);
199
- }
200
- break;
201
- case 'cc':
202
- $cc = array_merge((array)$cc, explode(',', $content));
203
- break;
204
- case 'bcc':
205
- $bcc = array_merge((array)$bcc, explode(',', $content));
206
- break;
207
- default:
208
- // Add it to our grand headers array
209
- $headers[trim($name)] = trim($content);
210
- break;
211
  }
 
 
 
 
 
 
 
 
 
 
 
212
  }
213
  }
214
  }
 
215
 
216
- if (!isset($from_name)) {
217
- $from_name = null;
218
- }
219
 
220
- if (!isset($from_email)) {
221
- $from_email = null;
222
- }
223
 
224
- $from_name = mg_detect_from_name($from_name);
225
- $from_email = mg_detect_from_address($from_email);
226
 
227
- $body = array(
228
- 'from' => "{$from_name} <{$from_email}>",
229
- 'to' => $to,
230
- 'subject' => $subject,
231
- );
232
 
233
- $rcpt_data = apply_filters('mg_mutate_to_rcpt_vars', $to);
234
- if (!is_null($rcpt_data['rcpt_vars'])) {
235
- $body['recipient-variables'] = $rcpt_data['rcpt_vars'];
236
- }
 
 
 
 
237
 
238
- $body['o:tag'] = array();
239
- $body['o:tracking-clicks'] = !empty($mailgun['track-clicks']) ? $mailgun['track-clicks'] : 'no';
240
- $body['o:tracking-opens'] = empty($mailgun['track-opens']) ? 'no' : 'yes';
 
 
241
 
242
- // this is the wordpress site tag
243
- if (isset($mailgun['tag'])) {
244
- $tags = explode(',', str_replace(' ', '', $mailgun['tag']));
 
245
  $body['o:tag'] = $tags;
 
 
 
 
246
  }
 
247
 
248
- // campaign-id now refers to a list of tags which will be appended to the site tag
249
- if (!empty($mailgun['campaign-id'])) {
250
- $tags = explode(',', str_replace(' ', '', $mailgun['campaign-id']));
251
- if (empty($body['o:tag'])) {
252
- $body['o:tag'] = $tags;
253
- } elseif (is_array($body['o:tag'])) {
254
- $body['o:tag'] = array_merge($body['o:tag'], $tags);
255
- } else {
256
- $body['o:tag'] .= ',' . $tags;
257
- }
258
- }
 
 
 
 
 
 
 
 
259
 
260
- /**
261
- * Filter tags.
262
- *
263
- * @param array $tags Mailgun tags.
264
- * @param string $to To address.
265
- * @param string $subject Subject line.
266
- * @param string $message Message content.
267
- * @param array $headers Headers array.
268
- * @param array $attachments Attachments array.
269
- * @param string $region Mailgun region.
270
- * @param string $domain Mailgun domain.
271
- *
272
- * @return array Mailgun tags.
273
- */
274
- $body['o:tag'] = apply_filters('mailgun_tags', $body['o:tag'], $to, $subject, $message, $headers, $attachments, $region, $domain);
275
 
276
- if (!empty($cc) && is_array($cc)) {
277
- $body['cc'] = implode(', ', $cc);
278
- }
 
 
 
279
 
280
- if (!empty($bcc) && is_array($bcc)) {
281
- $body['bcc'] = implode(', ', $bcc);
282
- }
283
 
284
- // If we are not given a Content-Type in the supplied headers,
285
- // write the message body to a file and try to determine the mimetype
286
- // using get_mime_content_type.
287
- if (!isset($content_type)) {
288
- $tmppath = tempnam(get_temp_dir(), 'mg');
289
- $tmp = fopen($tmppath, 'w+');
290
 
291
- fwrite($tmp, $message);
292
- fclose($tmp);
293
-
294
- $content_type = get_mime_content_type($tmppath, 'text/plain');
295
 
296
- unlink($tmppath);
297
- }
 
 
 
 
 
298
 
299
- // Allow external content type filter to function normally
300
- if (has_filter('wp_mail_content_type')) {
301
- $content_type = apply_filters(
302
- 'wp_mail_content_type',
303
- $content_type
304
- );
305
- }
 
 
 
306
 
307
- if ('text/plain' === $content_type) {
308
- $body['text'] = $message;
309
- } else if ('text/html' === $content_type) {
310
- $body['html'] = $message;
311
- } else {
312
- // Unknown Content-Type??
313
- error_log('[mailgun] Got unknown Content-Type: ' . $content_type);
314
- $body['text'] = $message;
315
- $body['html'] = $message;
 
 
 
 
 
 
 
 
316
  }
317
 
318
- // Some plugins, such as WooCommerce (@see WC_Email::handle_multipart()), to handle multipart/alternative with html
319
- // and plaintext messages hooks into phpmailer_init action to override AltBody property directly in $phpmailer,
320
- // so we should allow them to do this, and then get overridden plain text body from $phpmailer.
321
- // Partly, this logic is taken from original wp_mail function.
322
- if (false !== stripos($content_type, 'multipart')) {
323
- global $phpmailer;
324
-
325
- // (Re)create it, if it's gone missing.
326
- if (!($phpmailer instanceof PHPMailer\PHPMailer\PHPMailer)) {
327
- require_once ABSPATH . WPINC . '/PHPMailer/PHPMailer.php';
328
- require_once ABSPATH . WPINC . '/PHPMailer/SMTP.php';
329
- require_once ABSPATH . WPINC . '/PHPMailer/Exception.php';
330
- $phpmailer = new PHPMailer\PHPMailer\PHPMailer(true);
331
-
332
- $phpmailer::$validator = static function ($email) {
333
- return (bool)is_email($email);
334
- };
335
- }
336
-
337
- /**
338
- * Fires after PHPMailer is initialized.
339
- *
340
- * @param PHPMailer $phpmailer The PHPMailer instance (passed by reference).
341
- */
342
- do_action_ref_array('phpmailer_init', array(&$phpmailer));
343
 
344
- $plainTextMessage = $phpmailer->AltBody;
345
 
346
- if ($plainTextMessage) {
347
- $body['text'] = $plainTextMessage;
348
- }
349
  }
 
350
 
351
- // If we don't have a charset from the input headers
352
- if (!isset($charset)) {
353
- $charset = get_bloginfo('charset');
354
- }
355
 
356
- // Set the content-type and charset
357
- $charset = apply_filters('wp_mail_charset', $charset);
358
- if (isset($headers['Content-Type'])) {
359
- if (!strstr($headers['Content-Type'], 'charset')) {
360
- $headers['Content-Type'] = rtrim($headers['Content-Type'], '; ') . "; charset={$charset}";
361
- }
362
  }
 
363
 
364
- // Set custom headers
365
- if (!empty($headers)) {
366
- foreach ((array)$headers as $name => $content) {
367
- $body["h:{$name}"] = $content;
368
- }
369
  }
370
 
371
- /*
372
- * Deconstruct post array and create POST payload.
373
- * This entire routine is because wp_remote_post does
374
- * not support files directly.
375
- */
376
 
377
- $payload = '';
 
 
 
 
378
 
379
- // First, generate a boundary for the multipart message.
380
- $boundary = sha1(uniqid('', true));
381
 
382
- // Allow other plugins to apply body changes before creating the payload.
383
- $body = apply_filters('mg_mutate_message_body', $body);
384
- if (($body_payload = mg_build_payload_from_body($body, $boundary)) != null) {
385
- $payload .= $body_payload;
386
- }
387
 
388
- // Allow other plugins to apply attachment changes before writing to the payload.
389
- $attachments = apply_filters('mg_mutate_attachments', $attachments);
390
- if (($attachment_payload = mg_build_attachments_payload($attachments, $boundary)) != null) {
391
- $payload .= $attachment_payload;
392
- }
393
 
394
- $payload .= '--' . $boundary . '--';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
395
 
396
- $data = array(
397
- 'body' => $payload,
398
- 'headers' => array(
399
- 'Authorization' => 'Basic ' . base64_encode("api:{$apiKey}"),
400
- 'Content-Type' => 'multipart/form-data; boundary=' . $boundary,
401
- ),
402
- );
403
 
404
- $endpoint = mg_api_get_region($region);
405
- $endpoint = ($endpoint) ? $endpoint : 'https://api.mailgun.net/v3/';
406
- $url = $endpoint . "{$domain}/messages";
 
 
 
 
407
 
408
- // TODO: Mailgun only supports 1000 recipients per request, since we are
409
- // overriding this function, let's add looping here to handle that
410
- $response = wp_remote_post($url, $data);
411
- if (is_wp_error($response)) {
412
- // Store WP error in last error.
413
- mg_api_last_error($response->get_error_message());
414
 
415
- return false;
416
- }
 
 
 
 
417
 
418
- $response_code = wp_remote_retrieve_response_code($response);
419
- $response_body = json_decode(wp_remote_retrieve_body($response));
420
 
421
- // Mailgun API should *always* return a `message` field, even when
422
- // $response_code != 200, so a lack of `message` indicates something
423
- // is broken.
424
- if ((int)$response_code != 200 || !isset($response_body->message)) {
425
- // Store response code and HTTP response message in last error.
426
- $response_message = wp_remote_retrieve_response_message($response);
427
- $errmsg = "$response_code - $response_message";
428
- mg_api_last_error($errmsg);
429
 
430
- return false;
431
- }
 
 
 
 
 
 
432
 
433
- // Not sure there is any additional checking that needs to be done here, but why not?
434
- if ($response_body->message != 'Queued. Thank you.') {
435
- mg_api_last_error($response_body->message);
436
 
437
- return false;
438
- }
 
439
 
440
- return true;
441
  }
 
 
 
442
  }
443
 
444
- function mg_build_payload_from_body($body, $boundary)
445
- {
446
  $payload = '';
447
 
448
  // Iterate through pre-built params and build payload:
@@ -450,16 +464,16 @@ function mg_build_payload_from_body($body, $boundary)
450
  if (is_array($value)) {
451
  $parent_key = $key;
452
  foreach ($value as $key => $value) {
453
- $payload .= '--' . $boundary;
454
  $payload .= "\r\n";
455
- $payload .= 'Content-Disposition: form-data; name="' . $parent_key . "\"\r\n\r\n";
456
  $payload .= $value;
457
  $payload .= "\r\n";
458
  }
459
  } else {
460
- $payload .= '--' . $boundary;
461
  $payload .= "\r\n";
462
- $payload .= 'Content-Disposition: form-data; name="' . $key . '"' . "\r\n\r\n";
463
  $payload .= $value;
464
  $payload .= "\r\n";
465
  }
@@ -468,8 +482,10 @@ function mg_build_payload_from_body($body, $boundary)
468
  return $payload;
469
  }
470
 
471
- function mg_build_attachments_payload($attachments, $boundary)
472
- {
 
 
473
  $payload = '';
474
 
475
  // If we have attachments, add them to the payload.
@@ -477,9 +493,9 @@ function mg_build_attachments_payload($attachments, $boundary)
477
  $i = 0;
478
  foreach ($attachments as $attachment) {
479
  if (!empty($attachment)) {
480
- $payload .= '--' . $boundary;
481
  $payload .= "\r\n";
482
- $payload .= 'Content-Disposition: form-data; name="attachment[' . $i . ']"; filename="' . basename($attachment) . '"' . "\r\n\r\n";
483
  $payload .= file_get_contents($attachment);
484
  $payload .= "\r\n";
485
  $i++;
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.
30
  *
31
+ * @param string $error OPTIONAL
32
  *
33
+ * @return string Last error that occurred.
34
  *
35
+ * @since 1.5.0
36
  */
37
  function mg_api_last_error($error = null)
38
  {
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
  /*
79
 
80
  // TODO: Also add folding to prevent hitting the 998 char limit on headers.
81
  return array(
82
+ 'to' => '%recipient%',
83
  'rcpt_vars' => json_encode($rcpt_vars),
84
  );
85
  }
86
  }
87
 
88
  return array(
89
+ 'to' => $to_addrs,
90
  'rcpt_vars' => null,
91
  );
92
  }
98
  * Based off of the core wp_mail function, but with modifications required to
99
  * send email using the Mailgun HTTP API
100
  *
101
+ * @param string|array $to Array or comma-separated list of email addresses to send message.
102
+ * @param string $subject Email subject
103
+ * @param string $message Message contents
104
+ * @param string|array $headers Optional. Additional headers.
105
+ * @param string|array $attachments Optional. Files to attach.
106
  *
107
+ * @return bool Whether the email contents were sent successfully.
108
  *
109
  * @global PHPMailer\PHPMailer\PHPMailer $phpmailer
110
  *
111
+ * @since 0.1
112
  */
113
  if (!function_exists('wp_mail')) {
114
+ function wp_mail($to, $subject, $message, $headers = '', $attachments = array())
115
+ {
116
+ // Compact the input, apply the filters, and extract them back out
117
+ extract(apply_filters('wp_mail', compact('to', 'subject', 'message', 'headers', 'attachments')));
 
 
 
 
 
 
 
 
 
118
 
119
+ $mailgun = get_option('mailgun');
120
+ $region = (defined('MAILGUN_REGION') && MAILGUN_REGION) ? MAILGUN_REGION : $mailgun['region'];
121
+ $apiKey = (defined('MAILGUN_APIKEY') && MAILGUN_APIKEY) ? MAILGUN_APIKEY : $mailgun['apiKey'];
122
+ $domain = (defined('MAILGUN_DOMAIN') && MAILGUN_DOMAIN) ? MAILGUN_DOMAIN : $mailgun['domain'];
 
123
 
124
+ if (empty($apiKey) || empty($domain)) {
125
+ return false;
126
+ }
127
+
128
+ // If a region is not set via defines or through the options page, default to US region.
129
+ if (!((bool) $region)) {
130
+ error_log('[Mailgun] No region configuration was found! Defaulting to US region.');
131
+ $region = 'us';
132
+ }
133
 
134
+ if (!is_array($attachments)) {
135
+ $attachments = explode("\n", str_replace("\r\n", "\n", $attachments));
136
+ }
137
+
138
+ // Headers
139
+ if (empty($headers)) {
140
+ $headers = array();
141
+ } else {
142
+ if (!is_array($headers)) {
143
+ // Explode the headers out, so this function can take both
144
+ // string headers and an array of headers.
145
+ $tempheaders = explode("\n", str_replace("\r\n", "\n", $headers));
146
  } else {
147
+ $tempheaders = $headers;
148
+ }
149
+ $headers = array();
150
+ $cc = array();
151
+ $bcc = array();
152
+
153
+ // If it's actually got contents
154
+ if (!empty($tempheaders)) {
155
+ // Iterate through the raw headers
156
+ foreach ((array) $tempheaders as $header) {
157
+ if (strpos($header, ':') === false) {
158
+ if (false !== stripos($header, 'boundary=')) {
159
+ $parts = preg_split('/boundary=/i', trim($header));
160
+ $boundary = trim(str_replace(array("'", '"'), '', $parts[1]));
 
 
 
 
 
 
 
161
  }
162
+ continue;
163
+ }
164
+ // Explode them out
165
+ list($name, $content) = explode(':', trim($header), 2);
166
+
167
+ // Cleanup crew
168
+ $name = trim($name);
169
+ $content = trim($content);
170
+
171
+ switch (strtolower($name)) {
172
+ // Mainly for legacy -- process a From: header if it's there
173
+ case 'from':
174
+ if (strpos($content, '<') !== false) {
175
+ // So... making my life hard again?
176
+ $from_name = substr($content, 0, strpos($content, '<') - 1);
177
+ $from_name = str_replace('"', '', $from_name);
178
+ $from_name = trim($from_name);
179
+
180
+ $from_email = substr($content, strpos($content, '<') + 1);
181
+ $from_email = str_replace('>', '', $from_email);
182
+ $from_email = trim($from_email);
183
+ } else {
184
+ $from_email = trim($content);
185
+ }
186
+ break;
187
+ case 'content-type':
188
+ if (strpos($content, ';') !== false) {
189
+ list($type, $charset) = explode(';', $content);
190
+ $content_type = trim($type);
191
+ if (false !== stripos($charset, 'charset=')) {
192
+ $charset = trim(str_replace(array('charset=', '"'), '', $charset));
193
+ } elseif (false !== stripos($charset, 'boundary=')) {
194
+ $boundary = trim(str_replace(array('BOUNDARY=', 'boundary=', '"'), '', $charset));
195
+ $charset = '';
196
+ }
197
+ } else {
198
+ $content_type = trim($content);
 
 
 
 
 
 
 
 
 
 
199
  }
200
+ break;
201
+ case 'cc':
202
+ $cc = array_merge((array) $cc, explode(',', $content));
203
+ break;
204
+ case 'bcc':
205
+ $bcc = array_merge((array) $bcc, explode(',', $content));
206
+ break;
207
+ default:
208
+ // Add it to our grand headers array
209
+ $headers[trim($name)] = trim($content);
210
+ break;
211
  }
212
  }
213
  }
214
+ }
215
 
216
+ if (!isset($from_name)) {
217
+ $from_name = null;
218
+ }
219
 
220
+ if (!isset($from_email)) {
221
+ $from_email = null;
222
+ }
223
 
224
+ $from_name = mg_detect_from_name($from_name);
225
+ $from_email = mg_detect_from_address($from_email);
226
 
227
+ $body = array(
228
+ 'from' => "{$from_name} <{$from_email}>",
229
+ 'to' => $to,
230
+ 'subject' => $subject,
231
+ );
232
 
233
+ $rcpt_data = apply_filters('mg_mutate_to_rcpt_vars', $to);
234
+ if (!is_null($rcpt_data['rcpt_vars'])) {
235
+ $body['recipient-variables'] = $rcpt_data['rcpt_vars'];
236
+ }
237
+
238
+ $body['o:tag'] = array();
239
+ $body['o:tracking-clicks'] = !empty($mailgun['track-clicks']) ? $mailgun['track-clicks'] : 'no';
240
+ $body['o:tracking-opens'] = empty($mailgun['track-opens']) ? 'no' : 'yes';
241
 
242
+ // this is the wordpress site tag
243
+ if (isset($mailgun['tag'])) {
244
+ $tags = explode(',', str_replace(' ', '', $mailgun['tag']));
245
+ $body['o:tag'] = $tags;
246
+ }
247
 
248
+ // campaign-id now refers to a list of tags which will be appended to the site tag
249
+ if (!empty($mailgun['campaign-id'])) {
250
+ $tags = explode(',', str_replace(' ', '', $mailgun['campaign-id']));
251
+ if (empty($body['o:tag'])) {
252
  $body['o:tag'] = $tags;
253
+ } elseif (is_array($body['o:tag'])) {
254
+ $body['o:tag'] = array_merge($body['o:tag'], $tags);
255
+ } else {
256
+ $body['o:tag'] .= ','.$tags;
257
  }
258
+ }
259
 
260
+ /**
261
+ * Filter tags.
262
+ *
263
+ * @param array $tags Mailgun tags.
264
+ * @param string $to To address.
265
+ * @param string $subject Subject line.
266
+ * @param string $message Message content.
267
+ * @param array $headers Headers array.
268
+ * @param array $attachments Attachments array.
269
+ * @param string $region Mailgun region.
270
+ * @param string $domain Mailgun domain.
271
+ *
272
+ * @return array Mailgun tags.
273
+ */
274
+ $body['o:tag'] = apply_filters( 'mailgun_tags', $body['o:tag'], $to, $subject, $message, $headers, $attachments, $region, $domain );
275
+
276
+ if (!empty($cc) && is_array($cc)) {
277
+ $body['cc'] = implode(', ', $cc);
278
+ }
279
 
280
+ if (!empty($bcc) && is_array($bcc)) {
281
+ $body['bcc'] = implode(', ', $bcc);
282
+ }
 
 
 
 
 
 
 
 
 
 
 
 
283
 
284
+ // If we are not given a Content-Type in the supplied headers,
285
+ // write the message body to a file and try to determine the mimetype
286
+ // using get_mime_content_type.
287
+ if (!isset($content_type)) {
288
+ $tmppath = tempnam(get_temp_dir(), 'mg');
289
+ $tmp = fopen($tmppath, 'w+');
290
 
291
+ fwrite($tmp, $message);
292
+ fclose($tmp);
 
293
 
294
+ $content_type = get_mime_content_type($tmppath, 'text/plain');
 
 
 
 
 
295
 
296
+ unlink($tmppath);
297
+ }
 
 
298
 
299
+ // Allow external content type filter to function normally
300
+ if (has_filter('wp_mail_content_type')) {
301
+ $content_type = apply_filters(
302
+ 'wp_mail_content_type',
303
+ $content_type
304
+ );
305
+ }
306
 
307
+ if ('text/plain' === $content_type) {
308
+ $body['text'] = $message;
309
+ } else if ('text/html' === $content_type) {
310
+ $body['html'] = $message;
311
+ } else {
312
+ // Unknown Content-Type??
313
+ error_log('[mailgun] Got unknown Content-Type: ' . $content_type);
314
+ $body['text'] = $message;
315
+ $body['html'] = $message;
316
+ }
317
 
318
+ // Some plugins, such as WooCommerce (@see WC_Email::handle_multipart()), to handle multipart/alternative with html
319
+ // and plaintext messages hooks into phpmailer_init action to override AltBody property directly in $phpmailer,
320
+ // so we should allow them to do this, and then get overridden plain text body from $phpmailer.
321
+ // Partly, this logic is taken from original wp_mail function.
322
+ if (false !== stripos($content_type, 'multipart')) {
323
+ global $phpmailer;
324
+
325
+ // (Re)create it, if it's gone missing.
326
+ if (!($phpmailer instanceof PHPMailer\PHPMailer\PHPMailer)) {
327
+ require_once ABSPATH . WPINC . '/PHPMailer/PHPMailer.php';
328
+ require_once ABSPATH . WPINC . '/PHPMailer/SMTP.php';
329
+ require_once ABSPATH . WPINC . '/PHPMailer/Exception.php';
330
+ $phpmailer = new PHPMailer\PHPMailer\PHPMailer(true);
331
+
332
+ $phpmailer::$validator = static function ($email) {
333
+ return (bool)is_email($email);
334
+ };
335
  }
336
 
337
+ /**
338
+ * Fires after PHPMailer is initialized.
339
+ *
340
+ * @param PHPMailer $phpmailer The PHPMailer instance (passed by reference).
341
+ */
342
+ do_action_ref_array('phpmailer_init', array(&$phpmailer));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
343
 
344
+ $plainTextMessage = $phpmailer->AltBody;
345
 
346
+ if ($plainTextMessage) {
347
+ $body['text'] = $plainTextMessage;
 
348
  }
349
+ }
350
 
351
+ // If we don't have a charset from the input headers
352
+ if (!isset($charset)) {
353
+ $charset = get_bloginfo('charset');
354
+ }
355
 
356
+ // Set the content-type and charset
357
+ $charset = apply_filters('wp_mail_charset', $charset);
358
+ if (isset($headers['Content-Type'])) {
359
+ if (!strstr($headers['Content-Type'], 'charset')) {
360
+ $headers['Content-Type'] = rtrim($headers['Content-Type'], '; ')."; charset={$charset}";
 
361
  }
362
+ }
363
 
364
+ // Set custom headers
365
+ if (!empty($headers)) {
366
+ foreach ((array) $headers as $name => $content) {
367
+ $body["h:{$name}"] = $content;
 
368
  }
369
 
370
+ // TODO: Can we handle this?
371
+ //if ( false !== stripos( $content_type, 'multipart' ) && ! empty($boundary) )
372
+ // $phpmailer->AddCustomHeader( sprintf( "Content-Type: %s;\n\t boundary=\"%s\"", $content_type, $boundary ) );
373
+ }
 
374
 
375
+ /*
376
+ * Deconstruct post array and create POST payload.
377
+ * This entire routine is because wp_remote_post does
378
+ * not support files directly.
379
+ */
380
 
381
+ $payload = '';
 
382
 
383
+ // First, generate a boundary for the multipart message.
384
+ $boundary = sha1(uniqid('', true));
 
 
 
385
 
386
+ // Allow other plugins to apply body changes before creating the payload.
387
+ $body = apply_filters('mg_mutate_message_body', $body);
388
+ if ( ($body_payload = mg_build_payload_from_body($body, $boundary)) != null ) {
389
+ $payload .= $body_payload;
390
+ }
391
 
392
+ // TODO: Special handling for multipart/alternative mail
393
+ // if ('multipart/alternative' === $content_type) {
394
+ // // Build payload from mime
395
+ // // error_log(sprintf('building message payload from multipart/alternative'));
396
+ // // error_log($body['message']);
397
+ // // error_log('Attachments:');
398
+ // // foreach ($attachments as $attachment) {
399
+ // // error_log($attachment);
400
+ // // }
401
+ // }
402
+
403
+ // Allow other plugins to apply attachment changes before writing to the payload.
404
+ $attachments = apply_filters('mg_mutate_attachments', $attachments);
405
+ if ( ($attachment_payload = mg_build_attachments_payload($attachments, $boundary)) != null ) {
406
+ $payload .= $attachment_payload;
407
+ }
408
 
409
+ $payload .= '--'.$boundary.'--';
 
 
 
 
 
 
410
 
411
+ $data = array(
412
+ 'body' => $payload,
413
+ 'headers' => array(
414
+ 'Authorization' => 'Basic '.base64_encode("api:{$apiKey}"),
415
+ 'Content-Type' => 'multipart/form-data; boundary='.$boundary,
416
+ ),
417
+ );
418
 
419
+ $endpoint = mg_api_get_region($region);
420
+ $endpoint = ($endpoint) ? $endpoint : 'https://api.mailgun.net/v3/';
421
+ $url = $endpoint."{$domain}/messages";
 
 
 
422
 
423
+ // TODO: Mailgun only supports 1000 recipients per request, since we are
424
+ // overriding this function, let's add looping here to handle that
425
+ $response = wp_remote_post($url, $data);
426
+ if (is_wp_error($response)) {
427
+ // Store WP error in last error.
428
+ mg_api_last_error($response->get_error_message());
429
 
430
+ return false;
431
+ }
432
 
433
+ $response_code = wp_remote_retrieve_response_code($response);
434
+ $response_body = json_decode(wp_remote_retrieve_body($response));
 
 
 
 
 
 
435
 
436
+ // Mailgun API should *always* return a `message` field, even when
437
+ // $response_code != 200, so a lack of `message` indicates something
438
+ // is broken.
439
+ if ((int) $response_code != 200 || !isset($response_body->message)) {
440
+ // Store response code and HTTP response message in last error.
441
+ $response_message = wp_remote_retrieve_response_message($response);
442
+ $errmsg = "$response_code - $response_message";
443
+ mg_api_last_error($errmsg);
444
 
445
+ return false;
446
+ }
 
447
 
448
+ // Not sure there is any additional checking that needs to be done here, but why not?
449
+ if ($response_body->message != 'Queued. Thank you.') {
450
+ mg_api_last_error($response_body->message);
451
 
452
+ return false;
453
  }
454
+
455
+ return true;
456
+ }
457
  }
458
 
459
+ function mg_build_payload_from_body($body, $boundary) {
 
460
  $payload = '';
461
 
462
  // Iterate through pre-built params and build payload:
464
  if (is_array($value)) {
465
  $parent_key = $key;
466
  foreach ($value as $key => $value) {
467
+ $payload .= '--'.$boundary;
468
  $payload .= "\r\n";
469
+ $payload .= 'Content-Disposition: form-data; name="'.$parent_key."\"\r\n\r\n";
470
  $payload .= $value;
471
  $payload .= "\r\n";
472
  }
473
  } else {
474
+ $payload .= '--'.$boundary;
475
  $payload .= "\r\n";
476
+ $payload .= 'Content-Disposition: form-data; name="'.$key.'"'."\r\n\r\n";
477
  $payload .= $value;
478
  $payload .= "\r\n";
479
  }
482
  return $payload;
483
  }
484
 
485
+ function mg_build_payload_from_mime($body, $boundary) {
486
+ }
487
+
488
+ function mg_build_attachments_payload($attachments, $boundary) {
489
  $payload = '';
490
 
491
  // If we have attachments, add them to the payload.
493
  $i = 0;
494
  foreach ($attachments as $attachment) {
495
  if (!empty($attachment)) {
496
+ $payload .= '--'.$boundary;
497
  $payload .= "\r\n";
498
+ $payload .= 'Content-Disposition: form-data; name="attachment['.$i.']"; filename="'.basename($attachment).'"'."\r\n\r\n";
499
  $payload .= file_get_contents($attachment);
500
  $payload .= "\r\n";
501
  $i++;
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.8.2
8
  * Author: Mailgun
9
  * Author URI: http://www.mailgun.com/
10
  * License: GPLv2 or later
4
  * Plugin Name: Mailgun
5
  * Plugin URI: http://wordpress.org/extend/plugins/mailgun/
6
  * Description: Mailgun integration for WordPress
7
+ * Version: 1.8.1
8
  * Author: Mailgun
9
  * Author URI: http://www.mailgun.com/
10
  * License: GPLv2 or later
readme.md 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: 6.0.1
8
- Stable tag: 1.8.2
9
  License: GPLv2 or later
10
 
11
 
@@ -131,9 +131,6 @@ MAILGUN_FROM_ADDRESS Type: string
131
 
132
 
133
  == Changelog ==
134
- = 1.8.2 (2022-08-24): =
135
- - Plugin refactoring. Small fixes
136
-
137
  = 1.8.1 (2022-08-19): =
138
  - backward compatibility with php7.0
139
 
5
  Tags: mailgun, smtp, http, api, mail, email
6
  Requires at least: 3.3
7
  Tested up to: 6.0.1
8
+ Stable tag: 1.8.1
9
  License: GPLv2 or later
10
 
11
 
131
 
132
 
133
  == Changelog ==
 
 
 
134
  = 1.8.1 (2022-08-19): =
135
  - backward compatibility with php7.0
136
 
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: 6.0.1
8
- Stable tag: 1.8.2
9
  License: GPLv2 or later
10
 
11
 
@@ -128,9 +128,6 @@ MAILGUN_FROM_ADDRESS Type: string
128
 
129
 
130
  == Changelog ==
131
- = 1.8.2 (2022-08-24): =
132
- - Plugin refactoring. Small fixes
133
-
134
  = 1.8.1 (2022-08-19): =
135
  - backward compatibility with php7.0
136
 
5
  Tags: mailgun, smtp, http, api, mail, email
6
  Requires at least: 3.3
7
  Tested up to: 6.0.1
8
+ Stable tag: 1.8.1
9
  License: GPLv2 or later
10
 
11
 
128
 
129
 
130
  == Changelog ==
 
 
 
131
  = 1.8.1 (2022-08-19): =
132
  - backward compatibility with php7.0
133