Mail Queue by
WDM is a queue-only plugin for WordPress: it intercepts outbound mail before it leaves wp_mail(), stores it in the database, and drains the queue on a cron schedule. Version 1.5.1 shipped in May 2026, the plugin is tested up to WordPress 7.0, and the wp.org listing carries no staleness banner. At 900-plus active installs it is the largest of the three queue-focused plugins in the catalogue; the others are GD Mail Queue (eighteen months without a release at the time of its own review) and SMTP Mailing Queue (file-on-disk storage, ships its own SMTP mailer). For the case for queueing in the first place, see Understanding email queues in WordPress.
How it intercepts outbound mail
Mail Queue hooks the pre_wp_mail filter at priority 99999 with wdm_wpma_prewpmail(). pre_wp_mail is a WordPress 5.7 short-circuit hook: any non-null return value causes wp_mail() to return that value immediately, skipping the rest of its execution. The handler reads the outbound message, checks for an X-Mail-Queue-Prio header, strips the header before storage, serializes recipients, body, headers, and attachments to the {prefix}mail_queue table, and returns true. The calling code — a form plugin, WooCommerce, a membership system — sees a successful send. Nothing reached the wire.
The Instant value of X-Mail-Queue-Prio reverses this: the handler returns null, allowing wp_mail() to proceed normally. High stores the message but marks it for front-of-queue processing. These headers are consumed internally and stripped before the message leaves; they never appear in the delivered envelope.
Mail Queue does not own the mailer. When the cron processor drains the queue, it re-enters wp_mail() — with the interception filter temporarily removed — so whatever phpmailer_init or wp_mail filter hooks an SMTP plugin (FluentSMTP, WP Mail SMTP, Post SMTP, or others) has registered still fires. The message goes through whatever mailer is already configured. Mail Queue is a scheduling layer, not a transport.
This is the structural difference against GD Mail Queue, which intercepts at phpmailer_init by swapping WordPress’s PHPMailer instance for a stub. That approach gives the plugin tighter control over the mailer object but means the plugin owns the mailer and must reconstruct PHPMailer on drain. It is also why GD Mail Queue’s interception is documented as partial in its meta: it cannot queue messages sent via plugins that construct their own PHPMailer or use mail() directly. Mail Queue’s pre_wp_mail hook sits upstream of PHPMailer entirely; anything that calls wp_mail() is captured.
Queue processing and locking
The cron hook is wp_mail_queue_hook, running on a custom schedule registered via the cron_schedules filter (wdm_wpma_interval). The default interval is 5 minutes (queue_interval = 5, queue_interval_unit = 'minutes'). The default batch size is one message per tick (queue_amount = 1), which is conservative. Sites with meaningful queue volume should raise this in the plugin settings.
The processor uses two guards to avoid concurrent processing. A per-process triggercount rejects re-entry within the same PHP process. A cross-process lock stored in WordPress options uses a TTL of max(60, queue_interval * 2) seconds, providing a window large enough to cover the prior batch without blocking queue processing for longer than a full interval. Two simultaneous cron triggers cannot both drain the queue; the second exits immediately.
WordPress cron is involved. The standard caveat applies: on a low-traffic site, the cron hook does not fire until an HTTP request arrives to trigger wp-cron.php. For a queue to work reliably, disable WordPress cron in wp-config.php (define('DISABLE_WP_CRON', true)) and call wp-cron.php from a server-level cron job at the desired interval. This is not specific to Mail Queue; it is the operating requirement for any WordPress cron-backed feature on a site without steady traffic.
Priority, pause states, and alerts
Three queue states are available as of version 1.5.0: Enabled (normal operation), Paused (messages are accepted and stored but not sent), and Disabled (interception is switched off, wp_mail() runs normally). The pause state is useful when the upstream mail service has a problem: messages accumulate in the database without being lost, and re-enabling drains the backlog.
The alert system monitors queue depth against a configurable threshold (email_amount, default 10). When the queue exceeds the threshold, the plugin sends an alert to the configured address, at most once every six hours while the threshold remains exceeded. If pause_on_alert is enabled, the queue auto-pauses on the first alert. This is a reasonable default for contact-form sites where an abnormally large queue signals a spam burst or a form misconfiguration; it is less suited to WooCommerce stores during a marketing campaign where queue growth is expected.
Password reset emails are automatically prioritized via a filter on retrieve_password_notification_email. The effect is that password reset messages are flagged as high-priority and move to the front of the queue, ahead of standard outbound notifications. A user locked out of WordPress should not wait on a queue drain; the carve-out is correct.
The bulk “Send now” action in the admin queue view allows an operator to select queued messages and dispatch them immediately, bypassing the cron schedule. Useful for testing, for clearing a paused queue selectively, or for re-sending messages after a delivery issue.
Logging and retention
The plugin logs queue events, send completions, and failures (via the wp_mail_failed action) to its own tables. The default retention is 14 hours: the clear_queue option value is multiplied by HOUR_IN_SECONDS at deletion time. The admin UI presents the stored value divided by 24 with a “days” label, which produces a confusing display at the default setting. Operators who want a longer retention window should raise clear_queue explicitly; the default is tuned for operational hygiene, not long-horizon logging.
The queue table shows status, recipient, and timestamps; the event log records queue activity; failures are captured with enough context to diagnose send problems. It is not as deep as GD Mail Queue’s admin grid with inline preview and per-message retry. For operations where log depth is the primary requirement, that plugin’s logging panel is richer, on the understanding that it has not had a release since December 2024.
Compatibility
Anything that calls wp_mail() is captured by the queue, because the hook sits in wp_mail() itself. The two patterns that bypass it are the same as for any wp_mail-based interceptor: a plugin that constructs its own PHPMailer (or Symfony Mailer, or a vendor SDK) without going through wp_mail(), and a plugin that calls PHP’s mail() directly. Contact Form 7, WooCommerce, BuddyPress, bbPress, Gravity Forms, WPForms, and the major LMS plugins (LearnDash, MemberPress) all route through wp_mail() and are captured.
Multisite: activate per-subsite. The plugin uses $wpdb->prefix for table names, which means each subsite has its own queue table. The readme lists full multisite support as a planned feature. For operators running a multisite network, the current behaviour is functional but requires per-subsite configuration.
The plugin also registers REST endpoints via rest_api_init. These appear to serve the admin panel rather than expose a public queue-management API, though the endpoint implementations are not separately documented in the plugin readme as of version 1.5.1.
Where it sits against alternatives
Two kinds of plugin handle WordPress mail queuing: those where the queue is a feature of a larger SMTP plugin, and those where queueing is the only job.
For the first group, FluentSMTP, WP Mail SMTP Pro, and Post SMTP all ship queue or delayed-send features. These are tightly coupled to each plugin’s own mailer routing. Adding a separate queue plugin on top of a queueing-capable SMTP plugin creates a redundant layer; the two would compete over the same interception points. If the SMTP plugin in use already ships queueing in the tier the site is on, there is no reason to add Mail Queue.
For the second group, Mail Queue’s advantages over GD Mail Queue are the pre_wp_mail architecture (mailer-agnostic, captures any wp_mail() caller without a PHPMailer swap), the active maintenance record, and the lack of a staleness banner on WordPress.org. GD Mail Queue’s advantages are the htmlfy module (plain-text outbound wrapped in HTML before sending, useful for forum-style sites) and the deeper admin log. For the narrow profile where those features matter — a bbPress or BuddyPress forum site where plain-to-HTML wrapping is a requirement and log depth is valued — GD Mail Queue remains defensible, on the understanding that eighteen months without a release is a real cost.
Against SMTP Mailing Queue, the key difference is storage: SMTP Mailing Queue stores queued messages as flat files on disk rather than in the database. Those files fall outside the standard database backup path and must be covered separately. SMTP Mailing Queue also ships its own SMTP mailer, making it a different kind of plugin than Mail Queue’s queue-only design.
Assessment
Mail Queue is the correct default for adding a queue layer in front of an existing SMTP plugin. The pre_wp_mail interception architecture means the mailer configuration is untouched; the SMTP plugin keeps routing messages to whatever provider is configured, and Mail Queue controls when those calls happen. The active maintenance record and the tested-up-to WordPress 7.0 status support a clean recommendation. On low-traffic sites, ensure WordPress cron is replaced with a server-level cron job — the standard requirement for any WordPress cron-backed feature, not specific to this plugin.
Three cases where Mail Queue is not the right pick:
- The SMTP plugin in use already ships queueing. FluentSMTP’s retry queue, WP Mail SMTP Pro’s delayed-send feature, and Post SMTP’s built-in queue each handle this within their own plugin. A separate queue plugin adds complexity without benefit.
- A new install with no SMTP plugin yet. Choose FluentSMTP or Post SMTP first and use their built-in queue. Adding a queue plugin in front of PHP
mail()without an SMTP configuration behind it does not improve delivery — it delays it. - The requirement is plain-text-to-HTML wrapping with deep admin logging. That is the GD Mail Queue profile, for operators who accept the maintenance risk.
A site with an existing SMTP plugin that needs to absorb mail bursts, reduce PHP process blocking during form submissions, or add a controlled drain rate is the core case. Mail Queue handles it cleanly and is under active development.
For the broader setup the plugin slots into, see how to set up WordPress email.
Plugin data verified June 2026 against
https://wordpress.org/plugins/mail-queue/ and the plugin source on the WordPress plugin SVN.
