Skip to content

Commit

Permalink
Merge pull request #154 from JWardee/v2.0.2
Browse files Browse the repository at this point in the history
V2.0.2
  • Loading branch information
JWardee authored Jun 20, 2022
2 parents 0d542c6 + 6072fd3 commit 7cce28d
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 50 deletions.
2 changes: 1 addition & 1 deletion WpMailCatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
Domain Path: /languages
Description: Logging your mail will stop you from ever losing your emails again! This fast, lightweight plugin (under 140kb in size!) is also useful for debugging or backing up your messages.
Author: James Ward
Version: 2.0.1
Version: 2.0.2
Author URI: https://jamesward.io
Donate link: https://paypal.me/jamesmward
*/
Expand Down
2 changes: 1 addition & 1 deletion build/grunt/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "WpMailCatcher",
"version": "2.0.1",
"version": "2.0.2",
"lang_po_directory": "../../languages",
"build_directory": "./..",
"dist_directory": "../../assets",
Expand Down
8 changes: 7 additions & 1 deletion readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Tags: mail logging, email log, email logger, logging, email logging, mail, crm
Requires at least: 4.7
Tested up to: 6.0
Requires PHP: 7.2
Stable tag: 2.0.1
Stable tag: 2.0.2
License: GNU General Public License v3.0
License URI: https://raw.githubusercontent.com/JWardee/wp-mail-catcher/master/LICENSE
Donate link: https://paypal.me/jamesmward
Expand Down Expand Up @@ -94,6 +94,12 @@ Great! Please leave a note in our (GitHub tracker)

== Changelog ==

= 2.0.2 =

- Improvement: Reduced memory usage when deleting expired logs
- Fix: Emails sent with the to address formatted with angled brackets are now escaped
- Possible fix: Aligned wp_mail handling to be much closer to older version as some people reported issues

= 2.0.1 =

- Fix: Bulk actions (delete, export, resend) now works
Expand Down
11 changes: 1 addition & 10 deletions src/ExpiredLogManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,6 @@ public static function deletionIntervals()

public static function removeExpiredLogs($timeInterval = null)
{
$idsToRemove = [];
$interval = $timeInterval == null ? Settings::get('timescale') : $timeInterval;

foreach (Logs::get(['ignore_cache' => true]) as $log) {
if ((time() - $log['timestamp']) >= $interval) {
$idsToRemove[] = $log['id'];
}
}

Logs::delete($idsToRemove);
Logs::deleteOlderThan($timeInterval);
}
}
9 changes: 6 additions & 3 deletions src/Loggers/LogHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ public function saveError($error)
global $wpdb;

$wpdb->update(
$wpdb->prefix . GeneralHelper::$tableName, [
$wpdb->prefix . GeneralHelper::$tableName,
[
'status' => 0,
'error' => $error,
],
Expand All @@ -68,13 +69,15 @@ public function saveError($error)
public function saveIsHtml($contentType)
{
if ($this->id === null) {
return;
// Because this is triggered from add_filter we need to return the unmodified content type
return $contentType;
}

global $wpdb;

$wpdb->update(
$wpdb->prefix . GeneralHelper::$tableName, [
$wpdb->prefix . GeneralHelper::$tableName,
[
'is_html' => $contentType === 'text/html',
],
['id' => $this->id]
Expand Down
7 changes: 2 additions & 5 deletions src/Loggers/WpMail.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,14 @@ class WpMail
public function __construct()
{
$priority = 999999;
add_filter('wp_mail', [$this, 'recordMail'], $priority);
add_action('wp_mail', [$this, 'recordMail'], $priority);
add_action('wp_mail_failed', [$this, 'recordError'], $priority);
add_filter('wp_mail_content_type', [$this, 'saveIsHtml'], $priority);
}

public function recordMail($args)
{
$this->saveMail($args, [$this, 'getTransformedMailArgs']);

// Because this is triggered from add_filter we need to return the unmodified args
return $args;
return $this->saveMail($args, [$this, 'getTransformedMailArgs']);
}

public function recordError($error)
Expand Down
19 changes: 19 additions & 0 deletions src/Models/Logs.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,14 @@ static private function dbResultTransform($results, $args = [])
foreach ($results as &$result) {
$result['attachment_file_paths'] = [];

if (isset($result['email_to'])) {
$result['email_to'] = htmlspecialchars($result['email_to']);
}

if (isset($result['subject'])) {
$result['subject'] = htmlspecialchars($result['subject']);
}

if (isset($result['status'])) {
$result['status'] = (bool)$result['status'];
}
Expand Down Expand Up @@ -249,4 +257,15 @@ static private function getEmailFrom($logEntry)
*/
return str_replace(['custom:', 'From:', ' '], '', $fullHeader);
}

static public function deleteOlderThan($timeInterval)
{
global $wpdb;

$timestamp = time() - $timeInterval;

$sql = $wpdb->prepare("DELETE FROM " . $wpdb->prefix . GeneralHelper::$tableName . " WHERE time <= %d", $timestamp);

$wpdb->query($sql);
}
}
134 changes: 105 additions & 29 deletions testing/tests/TestEmails.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ public function testMail()
get_attached_file($pdfAttachmentId)
]);

$emailLogs = Logs::get();
$emailLogs = Logs::get();

$this->assertCount(1, $emailLogs);
$this->assertCount(1, $emailLogs);
$this->assertEquals($to, $emailLogs[0]['email_to']);
$this->assertEquals($subject, $emailLogs[0]['subject']);
$this->assertEquals($message, $emailLogs[0]['message']);
$this->assertEquals(true, $emailLogs[0]['is_html']);
$this->assertTrue($emailLogs[0]['is_html']);

$this->assertEquals($additionalHeaders[0], $emailLogs[0]['additional_headers'][0]);
$this->assertEquals($additionalHeaders[1], $emailLogs[0]['additional_headers'][1]);
Expand All @@ -46,52 +46,128 @@ public function testMail()
wp_delete_attachment($pdfAttachmentId);
}

public function testEscapingToAndSubject()
{
$to = 'hello <[email protected]>';
$subject = 'my subject <blah> " \'';

wp_mail($to, $subject, 'message');

$log = Logs::getFirst();

$this->assertEquals($log['email_to'], htmlspecialchars($to));
$this->assertEquals($log['subject'], htmlspecialchars($subject));
}

public function testCorrectTos()
{
wp_mail('[email protected]', 'subject', 'message');
$this->assertTrue(Logs::get()[0]['status']);
$this->assertTrue(Logs::getFirst()['status']);
}

public function testIncorrectTos()
{
wp_mail('testtest.com', 'subject', 'message');
$this->assertFalse(Logs::get()[0]['status']);
$this->assertFalse(Logs::getFirst()['status']);
}

public function testHtmlEmailSetViaFilter()
{
public function testHtmlEmailSetViaFilter()
{
$contentTypeFilterPriority = 999;
$updateContentType = function() {
$updateContentType = function () {
return 'text/html';
};

add_filter('wp_mail_content_type', $updateContentType, $contentTypeFilterPriority);

// Send an email without explicitly setting the html header
wp_mail('[email protected]', 'subject', 'message');
wp_mail('[email protected]', 'subject', 'message');

remove_filter('wp_mail_content_type', $updateContentType, $contentTypeFilterPriority);

$this->assertTrue(Logs::get()[0]['is_html']);
}
$this->assertTrue(Logs::get()[0]['is_html']);
}

public function testHtmlEmail()
{
public function testHtmlEmail()
{
// Test various formats
wp_mail('[email protected]', 'subject', 'message', [GeneralHelper::$htmlEmailHeader]);
wp_mail('[email protected]', 'subject', 'message', ['content-type:text/html']);
wp_mail('[email protected]', 'subject', 'message', ['Content-Type: text/html']);
wp_mail('[email protected]', 'subject', 'message', ['Content-Type: text/html;']);

$this->assertTrue(Logs::get()[0]['is_html']);
$this->assertTrue(Logs::get()[1]['is_html']);
$this->assertTrue(Logs::get()[2]['is_html']);
$this->assertTrue(Logs::get()[3]['is_html']);
}

public function testNonHtmlEmail()
{
wp_mail('[email protected]', 'subject', 'message');
$this->assertFalse(Logs::get()[0]['is_html']);
}
wp_mail('[email protected]', 'subject', 'message', [GeneralHelper::$htmlEmailHeader]);
wp_mail('[email protected]', 'subject', 'message', ['content-type:text/html']);
wp_mail('[email protected]', 'subject', 'message', ['Content-Type: text/html']);
wp_mail('[email protected]', 'subject', 'message', ['Content-Type: text/html;']);

$this->assertTrue(Logs::get()[0]['is_html']);
$this->assertTrue(Logs::get()[1]['is_html']);
$this->assertTrue(Logs::get()[2]['is_html']);
$this->assertTrue(Logs::get()[3]['is_html']);
}

public function testNonHtmlEmail()
{
wp_mail('[email protected]', 'subject', 'message');
$this->assertFalse(Logs::get()[0]['is_html']);
}

public function testWpFiltersWithMailCatcherAreUnchanged()
{
$originalTo = '[email protected]';
$originalSubject = 'subject';
$originalMessage = 'message';
$originalContentType = 'multipart/alternative';
$originalAdditionalHeaders = ['content-type: ' . $originalContentType, 'cc: [email protected]'];

$isWpMailFilterCalled = false;
$isWpMailContentFilterCalled = false;

$wpMailFilter = function ($args) use (&$isWpMailFilterCalled, $originalTo, $originalSubject, $originalMessage, $originalAdditionalHeaders) {
$isWpMailFilterCalled = true;

$this->assertEquals($args['to'], $originalTo);
$this->assertEquals($args['subject'], $originalSubject);
$this->assertEquals($args['message'], $originalMessage);

for ($i = 0; $i < count($args['headers']); $i++) {
$this->assertEquals($args['headers'][$i], $originalAdditionalHeaders[$i]);
}

return $args;
};

$wpMailContentFilter = function ($contentType) use (&$isWpMailContentFilterCalled, $originalContentType) {
$isWpMailContentFilterCalled = true;
$this->assertEquals($contentType, $originalContentType);
return $originalContentType;
};

// Add filters
add_filter('wp_mail', $wpMailFilter);
add_filter('wp_mail', $wpMailFilter, 9999991);
add_filter('wp_mail_content_type', $wpMailContentFilter);
add_filter('wp_mail_content_type', $wpMailContentFilter, 9999991);

// Send message
wp_mail($originalTo, $originalSubject, $originalMessage, $originalAdditionalHeaders);

// Assert filters were called
$this->assertTrue($isWpMailFilterCalled);
$this->assertTrue($isWpMailContentFilterCalled);

$emailLogs = Logs::get();

// Assert email was logged correctly
$this->assertCount(1, $emailLogs);
$this->assertEquals($originalTo, $emailLogs[0]['email_to']);
$this->assertEquals($originalSubject, $emailLogs[0]['subject']);
$this->assertEquals($originalMessage, $emailLogs[0]['message']);
$this->assertFalse($emailLogs[0]['is_html']);

$this->assertEquals($originalAdditionalHeaders[0], $emailLogs[0]['additional_headers'][0]);
$this->assertEquals($originalAdditionalHeaders[1], $emailLogs[0]['additional_headers'][1]);

// Tidy up
remove_filter('wp_mail', $wpMailFilter);
remove_filter('wp_mail', $wpMailFilter, 9999991);
remove_filter('wp_mail_content_type', $wpMailContentFilter);
remove_filter('wp_mail_content_type', $wpMailContentFilter, 9999991);
}
}

0 comments on commit 7cce28d

Please sign in to comment.