Yes. Any active WordPress plugin can read every email your site sends: the recipient, the subject, the full body, the headers, and any attachments. It has been that way since the wp_mail filter shipped, and a site owner can’t switch it off without breaking the SMTP plugin most sites depend on for delivery.
A critical TranslatePress vulnerability disclosed on 26 August 2026 (CVE-2026-19632, CVSS 9.8) hinged on exactly this design. It’s the same hook WP Mail SMTP, FluentSMTP, and Post SMTP all rely on.
The wp_mail filter, and what it exposes
Every time WordPress core, a plugin, or a theme calls wp_mail(), the function fires a filter named wp_mail before the message is handed to PHPMailer:
$atts = apply_filters( 'wp_mail', compact( 'to', 'subject', 'message', 'headers', 'attachments', 'embeds' ) );
Any plugin can register a callback on that filter and receive the full $atts array. The keys are to, subject, message, headers, attachments, and (from WordPress 6.9) embeds. The callback sees the message before it leaves the site.
Further down the pipeline, wp_mail() fires the phpmailer_init action using do_action_ref_array(), which passes the PHPMailer object by reference. A callback on that action can read (and modify) everything a fully-built PHPMailer instance holds: Body, AltBody, custom headers, From, attachments on disk, DKIM configuration, transport settings.
This is not a bug. It is what WordPress deliberately provides so plugins can rewrite outbound mail. Every SMTP plugin uses one or both of these hooks to reroute delivery through an authenticated provider connection instead of the default PHP mail() path. See How does WordPress send emails? for the rest of that pipeline.
The consequence: the trust boundary is at plugin install, not at send time. Once a plugin is active, it can read every message. Every plugin you install has this capability. The only questions are whether it uses it, and whether it handles what it sees safely.
How the TranslatePress incident happened
TranslatePress is a multilingual plugin with hundreds of thousands of active installs. Its translate-emails feature registers a callback on wp_mail, translates the outgoing body into whichever language the recipient’s profile is set to, and returns the translated message for delivery.
To avoid re-translating the same strings on every send, the plugin cached translation pairs in its trp_dictionary_* database table. When automatic string saving was enabled (the default) and an administrator’s profile locale was set to a published secondary language, password-reset emails were translated and cached with their raw reset URLs, tokens and all.
The exploit path then completed itself. TranslatePress exposes an unauthenticated AJAX action, trp_get_translations_regular, which returns dictionary entries by ID. An attacker could walk the IDs, pull the cached translated strings back out, find a password-reset URL, and take over the administrator account. Versions up to and including 3.3.1 are vulnerable; 3.3.2 patches it.
The pattern is not new. Post SMTP has shipped two very similar CVEs. In January 2024, CVE-2023-6875 (Post SMTP ≤ 2.8.7, CVSS 9.8) let an unauthenticated attacker reset the admin’s API token and then read the plugin’s email log, where the password-reset message they had just triggered was waiting. In November 2025, CVE-2025-11833 (Post SMTP ≤ 3.6.0, CVSS 9.8) exposed the email log directly to unauthenticated visitors, reproducing the same account-takeover chain.
The shape repeats. A plugin hooks wp_mail, sees a sensitive message, writes it to a second location (a translation cache, a log, a review queue), and the second location is not defended as carefully as the first.
How to see which plugins are hooking your outbound mail
There is no admin screen that shows this, but two methods work well from a maintenance window.
With WP-CLI, run wp eval and print the callback list registered on the filter:
wp eval 'print_r( $GLOBALS["wp_filter"]["wp_mail"] );'
wp eval 'print_r( $GLOBALS["wp_filter"]["phpmailer_init"] );'
The output enumerates every registered callback with its priority. Class-based callbacks show as Array ( [0] => ClassName [1] => methodName ), and closures show as Closure. Cross-reference the class names against the plugins you have installed.
From the filesystem, grep the plugins directory:
cd wp-content
grep -rIln "add_filter[^)]*['\"]wp_mail['\"]" plugins/ mu-plugins/
grep -rIln "add_action[^)]*['\"]phpmailer_init['\"]" plugins/ mu-plugins/
Any plugin that hooks either name gets the full outbound message. A single match isn’t cause for alarm. WP Mail SMTP, FluentSMTP, and Post SMTP all match, and they need to. The question is which unfamiliar entries are on the list.
Practical habits that reduce exposure
Auditing every plugin against its future CVEs isn’t a realistic project. Three habits do more:
- Reduce your active plugin count. Every active plugin is another callback that could see your outbound mail. Deactivate what you don’t use; delete what you deactivated.
- Keep the remaining plugins updated. The three CVEs above were all patched within a week of disclosure. Sites that got taken over were on stale versions.
- Treat high-value messages as high-value in transit. Password resets, 2FA codes, and financial receipts pass through WordPress, then your SMTP plugin, then your ESP, then the recipient’s inbox. Every hop can store or log the content. Which of them do, and for how long, is the question.
The wp_mail hook is what makes every SMTP plugin we cover possible. But it is worth knowing what the hook exposes, so that when the next TranslatePress-shaped disclosure arrives, the question isn’t “how could a plugin possibly see my emails?” It is “which of my plugins is doing what with them?”
