Plugin Directory

Changeset 3193246


Ignore:
Timestamp:
11/20/2024 02:26:33 PM (17 months ago)
Author:
webimpian
Message:

2.1.0

Location:
mailniaga-smtp
Files:
309 added
7 edited

Legend:

Unmodified
Added
Removed
  • mailniaga-smtp/trunk/includes/src/MailniagaConnector.php

    r3170128 r3193246  
    1313    private MailniagaEmailLogCleaner $email_log_cleaner;
    1414    private MailniagaCheckBalance $check_balance;
     15    private MailniagaActionSchedulerCleaner $action_scheduler_cleaner;
    1516
    1617
     
    2526        $this->email_log_cleaner = new MailniagaEmailLogCleaner();
    2627        $this->check_balance = new MailniagaCheckBalance($this->settings);
     28        $this->action_scheduler_cleaner = new MailniagaActionSchedulerCleaner();
    2729    }
    2830
     
    4446        $this->email_log_cleaner->register();
    4547        $this->check_balance->register();
     48        $this->action_scheduler_cleaner->register();
    4649
    4750        add_action('admin_post_mailniaga_send_test_email', [$this, 'handle_test_email']);
  • mailniaga-smtp/trunk/includes/src/MailniagaEmailLog.php

    r3170128 r3193246  
    143143                        <th><?php _e('Subject', 'mailniaga-smtp'); ?></th>
    144144                        <th><?php _e('Status', 'mailniaga-smtp'); ?></th>
    145                         <th><?php _e('Created At', 'mailniaga-smtp'); ?></th>
     145                        <th><?php _e('Created', 'mailniaga-smtp'); ?></th>
     146                        <th><?php _e('Updated', 'mailniaga-smtp'); ?></th>
    146147                        <th><?php _e('Actions', 'mailniaga-smtp'); ?></th>
    147148                    </tr>
     
    168169                            <td><?php echo esc_html($email->status); ?></td>
    169170                            <td><?php echo esc_html($email->created_at); ?></td>
     171                            <td><?php echo esc_html($email->updated_at); ?></td>
    170172                            <td>
    171173                                <a href="#" class="view-details" data-id="<?php echo esc_attr($email->id); ?>"><?php _e('View Details', 'mailniaga-smtp'); ?></a>
  • mailniaga-smtp/trunk/includes/src/MailniagaEmailSender.php

    r3170128 r3193246  
    11<?php
    2 
    32namespace Webimpian\MailniagaWPConnector;
    43
    54use GuzzleHttp\Client;
    6 use GuzzleHttp\Exception\GuzzleException;
     5use GuzzleHttp\Pool;
     6use GuzzleHttp\Psr7\Request;
     7use GuzzleHttp\Promise;
    78
    89class MailniagaEmailSender {
    910    private $settings;
    1011    private $client;
     12    private $concurrency = 200;
     13    private $batch_size = 1000;
    1114
    1215    public function __construct($settings) {
     
    1417        $this->client = new Client([
    1518            'base_uri' => 'https://api.mailniaga.mx/api/v0/',
    16             'timeout'  => 99999999999999999, // Reduced timeout for individual requests
     19            'timeout'  => 30,
    1720        ]);
    1821    }
     
    2023    public function register() {
    2124        add_filter('pre_wp_mail', [$this, 'queue_mail'], 10, 2);
    22         add_action('init', [$this, 'schedule_queue_processing']);
    23         add_action('process_mailniaga_email_queue', [$this, 'process_email_queue']);
     25        add_action('init', [$this, 'schedule_actions']);
     26        add_action('mailniaga_process_queue', [$this, 'process_email_queue']);
     27        add_action('mailniaga_retry_failed', [$this, 'retry_failed_emails']);
     28    }
     29
     30    public function schedule_actions() {
     31        if (!as_next_scheduled_action('mailniaga_process_queue')) {
     32            as_schedule_recurring_action(time(), 1, 'mailniaga_process_queue');
     33        }
     34
     35        if (!as_next_scheduled_action('mailniaga_retry_failed')) {
     36            as_schedule_recurring_action(time(), 60, 'mailniaga_retry_failed'); // Every 5 minutes
     37        }
    2438    }
    2539
     
    5872    }
    5973
    60     public function schedule_queue_processing() {
    61         if (!as_next_scheduled_action('process_mailniaga_email_queue')) {
    62             as_schedule_recurring_action(time(), 1, 'process_mailniaga_email_queue');
    63             //$this->log("Email queue processing scheduled");
    64         }
    65     }
    66 
    6774    public function process_email_queue() {
    6875        global $wpdb;
     
    7178        $emails = $wpdb->get_results(
    7279            $wpdb->prepare(
    73                 "SELECT * FROM $table_name WHERE status = 'queued' ORDER BY created_at ASC LIMIT %d",
    74                 100
     80                "SELECT * FROM $table_name
     81                WHERE status = 'queued'
     82                ORDER BY created_at ASC
     83                LIMIT %d",
     84                $this->batch_size
    7585            )
    7686        );
    7787
    78         //$this->log("Processing " . count($emails) . " emails from queue");
    79 
    80         foreach ($emails as $email) {
    81             $this->send_queued_email($email);
    82         }
    83     }
    84 
    85     private function send_queued_email($email) {
     88        if (empty($emails)) {
     89            return;
     90        }
     91
     92        $email_ids = array_map(function($email) {
     93            return $email->id;
     94        }, $emails);
     95
     96        $this->mark_emails_processing($email_ids);
     97        $this->process_emails_batch($emails);
     98    }
     99
     100    public function retry_failed_emails() {
     101        global $wpdb;
     102        $table_name = $wpdb->prefix . 'mailniaga_email_queue';
     103
     104        $failed_emails = $wpdb->get_results(
     105            "SELECT * FROM $table_name
     106            WHERE status = 'failed'
     107            ORDER BY created_at ASC
     108            LIMIT {$this->batch_size}"
     109        );
     110
     111        if (empty($failed_emails)) {
     112            return;
     113        }
     114
     115        $email_ids = array_map(function($email) {
     116            return $email->id;
     117        }, $failed_emails);
     118
     119        $this->mark_emails_processing($email_ids);
     120        $this->process_emails_batch($failed_emails, true);
     121    }
     122
     123    private function process_emails_batch($emails, $is_retry = false) {
     124        $this->log("Starting batch process with " . count($emails) . " emails");
     125
     126        $requests = function() use ($emails) {
     127            foreach ($emails as $email) {
     128                $data = $this->prepare_email_data($email);
     129                $this->log("Preparing request for email ID {$email->id}");
     130
     131                yield function() use ($data) {
     132                    return $this->client->requestAsync('POST', 'messages', [
     133                        'headers' => [
     134                            'Content-Type' => 'application/json',
     135                            'X-API-Key' => $this->settings['api_key'],
     136                            'Accept' => 'application/json',
     137                        ],
     138                        'json' => $data,
     139                        'timeout' => 30,
     140                        'connect_timeout' => 10
     141                    ]);
     142                };
     143            }
     144        };
     145
     146        $pool = new Pool($this->client, $requests(), [
     147            'concurrency' => $this->concurrency,
     148            'fulfilled' => function($response, $index) use ($emails, $is_retry) {
     149                try {
     150                    $email = $emails[$index];
     151                    $result = json_decode($response->getBody(), true);
     152                    //$this->log("Response for email ID {$email->id}: " . print_r($result, true));
     153
     154                    if ($result && isset($result['status_code']) && $result['status_code'] === 200) {
     155                        $this->update_email_status($email->id, 'sent');
     156                        $this->log(($is_retry ? "Retry successful" : "Sent successfully") . " for email ID: {$email->id}");
     157                    } else {
     158                        $error = $result['message'] ?? 'Unknown error';
     159                        $this->update_email_status($email->id, 'failed', $error);
     160                        $this->log(($is_retry ? "Retry failed" : "Send failed") . " for email ID: {$email->id}. Error: $error", 'error');
     161                    }
     162                } catch (\Exception $e) {
     163                    $this->log("Error processing response for index $index: " . $e->getMessage(), 'error');
     164                    if (isset($email)) {
     165                        $this->update_email_status($email->id, 'failed', $e->getMessage());
     166                    }
     167                }
     168            },
     169            'rejected' => function($reason, $index) use ($emails, $is_retry) {
     170                try {
     171                    $email = $emails[$index];
     172                    $error_message = $reason instanceof \Exception ? $reason->getMessage() : 'Unknown error';
     173                    $this->update_email_status($email->id, 'failed', $error_message);
     174                    $this->log(($is_retry ? "Retry rejected" : "Send rejected") . " for email ID: {$email->id}. Error: $error_message", 'error');
     175                } catch (\Exception $e) {
     176                    $this->log("Error processing rejection for index $index: " . $e->getMessage(), 'error');
     177                }
     178            },
     179            'options' => [
     180                'timeout' => 30,
     181                'connect_timeout' => 10
     182            ]
     183        ]);
     184
     185        try {
     186            $promise = $pool->promise();
     187            $promise->wait();
     188            $this->log("Batch processing completed");
     189        } catch (\Exception $e) {
     190            $this->log("Error in pool promise: " . $e->getMessage(), 'error');
     191        }
     192    }
     193
     194    private function mark_emails_processing($email_ids) {
     195        global $wpdb;
     196        $table_name = $wpdb->prefix . 'mailniaga_email_queue';
     197
     198        $ids = implode(',', array_map('intval', $email_ids));
     199        $wpdb->query("UPDATE $table_name
     200            SET status = 'processing',
     201                updated_at = '" . current_time('mysql') . "'
     202            WHERE id IN ($ids)");
     203    }
     204
     205    private function prepare_email_data($email): array {
    86206        $to = explode(',', $email->to_email);
    87207        $headers = unserialize($email->headers);
     
    90210            'from' => sprintf('%s <%s>', $email->from_name, $email->from_email),
    91211            'to' => $to,
    92             'reply_to' => $headers['reply-to'] ?? '',
    93212            'subject' => $email->subject,
    94213            'as_html' => 1,
     
    96215        ];
    97216
     217        if (!empty($headers['reply-to'])) {
     218            $data['reply_to'] = $headers['reply-to'];
     219        }
     220
     221        if (!empty($headers['unsubscribe'])) {
     222            $data['unsubscribe_link'] = $headers['unsubscribe'];
     223        }
     224
    98225        if (!empty($headers['content-type']) && strpos($headers['content-type'], 'text/plain') !== false) {
    99226            $data['content_plain'] = $email->message;
     
    101228        }
    102229
    103         try {
    104             //$this->log("Sending email ID: {$email->id} to: {$email->to_email}");
    105 
    106             $response = $this->client->request('POST', 'messages', [
    107                 'headers' => [
    108                     'Content-Type' => 'application/json',
    109                     'X-API-Key' => $this->settings['api_key'],
    110                 ],
    111                 'json' => $data,
    112             ]);
    113 
    114             $result = json_decode($response->getBody(), true);
    115 
    116             if ($result['error'] || $result['status_code'] !== 200) {
    117                 throw new \Exception('Failed to send email: ' . ($result['message'] ?? 'Unknown error'));
    118             }
    119 
    120             $this->update_email_status($email->id, 'sent');
    121             //$this->log("Email ID: {$email->id} sent successfully");
    122         } catch (GuzzleException $e) {
    123             $this->log("Mailniaga API Error for email ID: {$email->id}: " . $e->getMessage(), 'error');
    124             $this->update_email_status($email->id, 'failed', $e->getMessage());
    125         } catch (\Exception $e) {
    126             $this->log("Mailniaga Send Error for email ID: {$email->id}: " . $e->getMessage(), 'error');
    127             $this->update_email_status($email->id, 'failed', $e->getMessage());
    128         }
     230        return $data;
    129231    }
    130232
     
    133235        $table_name = $wpdb->prefix . 'mailniaga_email_queue';
    134236
    135         $result = $wpdb->update(
    136             $table_name,
    137             [
    138                 'status' => $status,
    139                 'error_message' => $error_message,
    140                 'updated_at' => current_time('mysql'),
    141             ],
    142             ['id' => $email_id]
    143         );
    144 
    145         if ($result === false) {
    146             $this->log("Failed to update status for email ID: $email_id. DB Error: " . $wpdb->last_error, 'error');
    147         } else {
    148             $this->log("Updated status for email ID: $email_id to: $status");
    149         }
     237        $data = [
     238            'status' => $status,
     239            'updated_at' => current_time('mysql'),
     240        ];
     241
     242        if ($error_message !== null) {
     243            $data['error_message'] = $error_message;
     244        }
     245
     246        $wpdb->update($table_name, $data, ['id' => $email_id]);
    150247    }
    151248
     
    227324    }
    228325
    229     private function get_last_error() {
    230         if (function_exists('error_get_last')) {
    231             $error = error_get_last();
    232             if ($error !== null) {
    233                 return $error['message'];
    234             }
    235         }
    236         return 'Unknown error';
    237     }
    238 
    239326    private function log($message, $level = 'info') {
    240         $log_message = "[Mailniaga WP Connector] [$level] $message";
    241         error_log($log_message);
     327        error_log("[Mailniaga WP Connector] [$level] $message");
    242328    }
    243329}
  • mailniaga-smtp/trunk/includes/src/assets/css/settings-page.css

    r3170128 r3193246  
    117117    color: #666;
    118118    margin-top: 5px;
     119}
     120
     121.datetime-wrapper {
     122    display: inline-block;
     123    margin-right: 10px;
     124}
     125
     126.date-picker {
     127    width: 100px;
     128    margin-right: 5px;
     129}
     130
     131.time-picker {
     132    width: 100px;
    119133}
    120134
  • mailniaga-smtp/trunk/includes/vendor/composer/installed.php

    r3170128 r3193246  
    44        'pretty_version' => 'dev-main',
    55        'version' => 'dev-main',
    6         'reference' => '10d2719c6c3fc6712bf58442ed6e357bd593b98d',
     6        'reference' => 'e251f00736e1eeef80ca80b14ff2882f1be9d7e9',
    77        'type' => 'wordpress-plugin',
    88        'install_path' => __DIR__ . '/../../../',
     
    104104            'pretty_version' => 'dev-main',
    105105            'version' => 'dev-main',
    106             'reference' => '10d2719c6c3fc6712bf58442ed6e357bd593b98d',
     106            'reference' => 'e251f00736e1eeef80ca80b14ff2882f1be9d7e9',
    107107            'type' => 'wordpress-plugin',
    108108            'install_path' => __DIR__ . '/../../../',
  • mailniaga-smtp/trunk/mailniaga-smtp.php

    r3170128 r3193246  
    1313 * Plugin Name:         Mail Niaga SMTP
    1414 * Plugin URI:          https://mailniaga.com
    15  * Version:             2.0.0
     15 * Version:             2.1.0
    1616 * Description:         Streamline your WordPress email delivery with Mail Niaga API integration. Boost email deliverability, track performance, and ensure reliable SMTP service for all your website's outgoing emails.
    1717 * Author:              Web Impian
    1818 * Author URI:          https://webimpian.com
    1919 * Requires at least:   5.6
    20  * Tested up to:        6.6.1
    21  * Requires PHP:        7.4
     20 * Tested up to:        6.7
     21 * Requires PHP:        8.1
    2222 * License:             GPLv3
    2323 * License URI:         https://www.gnu.org/licenses/gpl-3.0.txt
  • mailniaga-smtp/trunk/readme.txt

    r3170132 r3193246  
    11=== MailNiaga SMTP ===
    22Contributors: webimpian
    3 Tags: SMTP, email, mailniaga, email queue, email log
     3Tags: SMTP, email, wp_mail, mailniaga, api, email queue, email log
    44Requires at least: 5.6
    5 Tested up to: 6.6.1
    6 Requires PHP: 7.4
    7 Stable tag: 2.0.0
     5Tested up to: 6.7
     6Requires PHP: 8.1
     7Stable tag: 2.1.0
    88License: GPLv3
    99License URI: https://www.gnu.org/licenses/gpl-3.0.txt
    1010
    11 Streamline WordPress email with Mail Niaga SMTP & API. Boost deliverability, manage queues, and track performance.
     11Streamline your WordPress email delivery with Mail Niaga SMTP & API integration. Boost email deliverability, manage email queues, and track email performance.
    1212
    1313== Description ==
    1414
    15 Mail Niaga SMTP integrates WordPress with Mail Niaga's services, improving email deliverability and tracking for reliable outgoing emails.
     15Mail Niaga SMTP is a powerful WordPress plugin that integrates your website with Mail Niaga's SMTP and API services. This plugin enhances your email deliverability, provides comprehensive tracking capabilities, and ensures a reliable email service for all your outgoing emails.
     16
     17Mail Niaga is one of the products from Web Impian Sdn Bhd, a leading technology company in Malaysia. By using this plugin, you're leveraging a robust email solution backed by a reputable tech firm.
    1618
    1719== How it works ==
    1820
    19 This plugin connects to Mail Niaga's endpoint to secure email processing for your WordPress site.
    20 
    21 It seamlessly integrates with the WordPress core wp_mail() function to ensure all your site's emails are sent through Mail Niaga's reliable SMTP servers or API.
    22 
    23 With the new email queue system, it can handle large volumes of emails efficiently, making it perfect for email blasts and high-traffic websites.
     21This plugin connects to Mail Niaga's endpoint to secure email processing for your WordPress site. It seamlessly integrates with the WordPress core wp_mail() function to ensure all your site's emails are sent through Mail Niaga's reliable SMTP servers or API. With the new email queue system, it can handle large volumes of emails efficiently, making it perfect for email blasts and high-traffic websites.
    2422
    2523Please visit our website [https://mailniaga.com/](https://mailniaga.com/) for terms of use and privacy policy, or email to support@mailniaga.com for any inquiries.
     
    7674= What is the Email Queue system? =
    7775
    78 The Email Queue system allows you to manage large email sending operations efficiently.
    79 
    80 It's particularly useful for email blasts or high-traffic websites that need to send a large number of emails without overwhelming the server.
     76The Email Queue system allows you to manage large email sending operations efficiently. It's particularly useful for email blasts or high-traffic websites that need to send a large number of emails without overwhelming the server.
    8177
    8278= How long are email logs kept? =
     
    9793
    9894== Changelog ==
     95
     96= 2.1.0 =
     97* Improve the queue speed email
     98* Fix a few bug
     99
    99100
    100101= 2.0.0 =
Note: See TracChangeset for help on using the changeset viewer.