PHP errors on a WordPress site can go unnoticed for days. A plugin update breaks a checkout flow, a theme function throws a fatal error, or a deprecated function starts failing after a PHP upgrade — and nobody knows until a client reports it. Email notifications let you find out about errors as they happen, not after the damage is done.
WP Debug Toolkit (WPDT) installs a must-use plugin that catches PHP errors and sends email alerts based on rules you configure. This guide covers manual approaches, third-party services, and the WPDT method for setting up error notifications.
There are several ways to get email alerts when PHP errors occur on a WordPress site. Each has trade-offs in complexity, reliability, and coverage.
You can write a custom PHP error handler and drop it into wp-content/mu-plugins/. MU-plugins load before regular plugins, so the handler catches errors early in the WordPress boot process.
Create wp-content/mu-plugins/error-notifier.php:
<?php
/**
* Custom error notification handler.
*/
set_error_handler( function ( $severity, $message, $file, $line ) {
$monitored = array( E_ERROR, E_PARSE, E_WARNING, E_USER_ERROR );
if ( ! in_array( $severity, $monitored, true ) ) {
return false;
}
$severity_labels = array(
E_ERROR => 'E_ERROR',
E_PARSE => 'E_PARSE',
E_WARNING => 'E_WARNING',
E_USER_ERROR => 'E_USER_ERROR',
);
$label = $severity_labels[ $severity ] ?? 'UNKNOWN';
$subject = "[PHP {$label}] " . substr( $message, 0, 80 );
$body = "Error: {$message}\nFile: {$file}\nLine: {$line}\nTime: " . gmdate( 'Y-m-d H:i:s T' );
wp_mail( 'dev@example.com', $subject, $body );
return false;
} );
This works, but has problems. Every error sends an email immediately. A broken plugin that throws a warning on every page load generates thousands of emails per hour. There is no deduplication, no rate limiting, and no way to configure it without editing the file.
PHP’s set_error_handler() cannot catch fatal errors (E_ERROR, E_PARSE, compile errors). To catch those, register a shutdown function that checks error_get_last():
<?php
/**
* Fatal error notification via shutdown function.
*/
register_shutdown_function( function () {
$error = error_get_last();
if ( null === $error ) {
return;
}
$fatal_types = array( E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR );
if ( ! in_array( $error['type'], $fatal_types, true ) ) {
return;
}
$subject = '[Fatal Error] ' . substr( $error['message'], 0, 80 );
$body = sprintf(
"Type: %d\nMessage: %s\nFile: %s\nLine: %d\nTime: %s",
$error['type'],
$error['message'],
$error['file'],
$error['line'],
gmdate( 'Y-m-d H:i:s T' )
);
// Cannot use wp_mail() here — WordPress may be in a broken state.
// Fall back to PHP mail().
mail( 'dev@example.com', $subject, $body );
} );
This catches fatal errors but has its own limitations. The mail() function may be disabled on your host. WordPress’s SMTP configuration is not available during shutdown. And there is still no rate limiting — if a fatal error triggers on every request, you get an email per request.
External monitoring services take a different approach. They provide SDKs that you install as plugins or MU-plugins:
These services offer dashboards, Slack/PagerDuty integrations, and sophisticated deduplication. They are designed for teams that need deep observability across multiple applications. For a single WordPress site, they may be more infrastructure than you need.
WPDT provides a built-in notification system that handles rate limiting, error level filtering, template customization, and delivery through WordPress’s wp_mail(). Configuration happens in the admin dashboard — no code to write or maintain.
WPDT’s notification system runs through a must-use plugin. MU-plugins load before regular plugins in the WordPress boot sequence, so the error handler is active early enough to catch errors from any plugin, theme, or WordPress core.
WPDT copies wpdebugtoolkit-notifications.php to wp-content/mu-plugins/. If the directory does not exist, WPDT creates it.
Note: On some hosting setups, WPDT installs the MU-plugin automatically when you enable notifications. If the MU-Plugin section shows “Installed,” skip this step.
Toggle Enable Notifications to on. With the toggle off, the MU-plugin is loaded by WordPress but does not process or send any emails.
Enter the email address where notifications are sent. This defaults to your WordPress admin email. You can set it to a team address, a shared inbox, or a monitoring alias.
For agencies managing multiple sites, use a per-site alias (e.g., alerts+clientname@youragency.com) so you can filter and route notifications in your email client.
Select which PHP error levels trigger notifications. WPDT provides presets and a full list.
Click Recommended to select four error levels that indicate real problems:
| Level | What it means |
|---|---|
E_ERROR | Fatal runtime error — execution stops |
E_PARSE | Syntax error — PHP cannot parse the file |
E_WARNING | Non-fatal runtime warning — execution continues but something is wrong |
E_USER_ERROR | User-triggered fatal error via trigger_error() |
This preset covers errors that break or degrade functionality. It excludes deprecation notices, strict standards warnings, and other low-severity messages that generate noise on production sites.
| Level | Severity |
|---|---|
E_ERROR | Fatal |
E_WARNING | Warning |
E_PARSE | Fatal |
E_NOTICE | Notice |
E_DEPRECATED | Notice |
E_USER_ERROR | Fatal |
E_USER_WARNING | Warning |
E_USER_NOTICE | Notice |
E_STRICT | Notice |
E_RECOVERABLE_ERROR | Warning |
E_CORE_ERROR | Fatal |
E_CORE_WARNING | Warning |
E_COMPILE_ERROR | Fatal |
E_COMPILE_WARNING | Warning |
Enabling E_NOTICE and E_DEPRECATED on a production site with many plugins generates high email volume. Most WordPress plugins produce deprecation notices that are harmless in the short term. Start with the recommended preset and expand later if you need broader coverage.
Rate limiting is the most important setting in the notification system. Without it, a single broken page that throws an error on every request floods your inbox with thousands of identical emails.
Controls how long WPDT waits before re-reporting the same error. “Same error” means identical error message and file location.
| Cooldown | Use case |
|---|---|
| 15 minutes | Active debugging — you want frequent updates |
| 30 minutes | Development sites |
| 1 hour | General production use |
| 6 hours | High-traffic production sites |
| 12 hours | Low-priority monitoring |
| 24 hours | Minimal alerting — one email per error per day |
For most production sites, 1 hour is a reasonable starting point. You get notified about new errors quickly, but recurring errors do not repeat until the cooldown expires.
A hard cap on total notification emails per hour, across all error types.
Available presets: 5, 10, 20, 50, 100
This protects your inbox during cascading failures. When a WordPress update goes wrong and twenty different plugins throw errors simultaneously, the hourly cap prevents a flood. Once the cap is hit, no more emails are sent until the next hour begins. Errors are still logged to debug.log — you just stop getting emails about them.
For most production sites, 10–20 per hour balances awareness with noise. Set it higher during active debugging sessions.
A real-world scenario: a plugin throws an E_WARNING on every WooCommerce product page. The site has 500 products. A Google crawl hits all 500 pages in 10 minutes. Without rate limiting, you receive 500 emails in 10 minutes about the same warning. With a 1-hour cooldown, you receive one email and then silence until the cooldown resets.
Go to Debug Toolkit > Settings > Email Design to customize the notification emails.
| Setting | Description | Default |
|---|---|---|
| Company name | Displayed in the email header and footer | Your site name |
| Logo URL | URL to your company or site logo image | WPDT logo |
| Logo height | Height of the logo in the email header (20–200px) | 40px |
| Brand color | Primary color for buttons and accents (hex value) | #e83f94 |
Toggle White-label mode to remove WPDT branding from notification emails. The email appears as a generic error notification from your brand. This is designed for agencies managing client sites — clients receive professional error alerts without third-party tool branding.
Use these in content fields:
| Variable | Replaced with |
|---|---|
{site_name} | Your WordPress site name |
{site_url} | Your WordPress site URL |
{date} | Current date |
{time} | Current time |
{support_email} | The configured support email address |
{support_url} | The configured support page URL |
A live preview updates as you change settings, so you can see the result before sending.
Click Send Test Email at the bottom of the Notifications settings page. WPDT sends a sample notification to your configured recipient. Check your inbox and spam folder.
If the test email arrives, the system is working. If it does not, see the troubleshooting section below.
On a staging or development site, trigger an actual PHP error to confirm the full pipeline works:
// Add temporarily to your theme's functions.php:
trigger_error( 'WPDT notification test error', E_USER_ERROR );
This fires a user-level fatal error. If E_USER_ERROR is in your monitored levels, you should receive an email within seconds. Remove the test code after confirming.
Rate limiting deserves its own section because misconfigured limits are the most common source of problems — either too many emails or none at all.
WPDT uses two independent mechanisms:
Suppose your per-error cooldown is 1 hour and your hourly cap is 10.
| Scenario | Per-error cooldown | Hourly cap |
|---|---|---|
| Active debugging session | 15 min | 50 |
| Standard production site | 1 hour | 10 |
| High-traffic production site | 6 hours | 5 |
| Agency monitoring many client sites | 6–12 hours | 5 |
On a production site, start with the recommended preset (E_ERROR, E_PARSE, E_WARNING, E_USER_ERROR). These cover errors that affect site functionality.
Add E_RECOVERABLE_ERROR if you want to catch type-hint violations (PHP throws these when a function receives the wrong type and the error is recoverable).
Avoid E_NOTICE and E_DEPRECATED on production unless you have a specific reason. Most WordPress plugin ecosystems generate deprecation notices that are harmless in the short term, and notices for undefined variables are common in older plugins.
Email notifications tell you that something happened. The standalone viewer tells you what happened and why. A typical workflow:
WordPress 5.2+ sends its own recovery mode email when a fatal error occurs. WPDT enhances that email with a link to the standalone viewer and additional debug context. You may receive both a WPDT notification email and a WordPress recovery email for the same fatal error — this is expected. The WPDT notification has more detail (stack trace, error level, rate-limited history). The recovery email has the one-time login link.
The notification system depends on WordPress being able to send email. If wp_mail() does not work on your site, notifications do not send.
WordPress uses PHP’s mail() function by default, which many hosts block or limit. Install an SMTP plugin to route emails through a real mail server:
Configure the SMTP plugin first, verify it can send basic emails, then set up WPDT notifications.
If notification emails land in spam, the problem is usually missing email authentication records. These DNS records prove your domain is authorized to send email:
Your SMTP provider (SendGrid, Mailgun, Google Workspace, etc.) provides the specific records to add. Without these, spam filters are more likely to flag notification emails.
Some shared hosts limit outgoing emails to 100–500 per hour. If your site hits that limit (from WooCommerce order emails, contact forms, and other sources), notification emails queue up or get dropped. Check your host’s documentation for sending limits. If limits are tight, keep the WPDT hourly cap low and use the per-error cooldown to reduce volume.
Check SMTP configuration. The most common cause. WordPress’s default mail() function is unreliable. Install an SMTP plugin and verify it sends test emails.
Check the MU-plugin. Go to Debug Toolkit > Settings > Notifications and confirm the MU-Plugin section shows “Installed.” If it was removed (manually or by a host cleanup), reinstall it.
Verify notifications are enabled. The enable toggle must be on. The MU-plugin loads regardless, but it only sends emails when enabled.
Verify wp_mail() works. Test with a basic call:
$result = wp_mail( 'you@example.com', 'Test', 'Testing wp_mail' );
var_dump( $result ); // Should output: bool(true)
If this returns false, the problem is with your mail configuration, not WPDT.
Check hosting SMTP restrictions. Some hosts (especially free tiers) disable outgoing SMTP entirely. Contact your host to confirm email sending is enabled.
Check error levels. If you only selected E_ERROR but the error is an E_WARNING, no email is sent. Verify the error’s level matches your monitored levels.
Lower the hourly cap. If you receive more emails than you can process, reduce the max emails per hour. Start with 5 or 10 and increase if you need more.
Increase the per-error cooldown. A 1-hour cooldown means you receive at most one email per unique error per hour. A 6-hour cooldown reduces repeat notifications further.
Narrow the error levels. Remove E_WARNING temporarily if warnings dominate the email volume. Focus on fatal errors until you address the underlying issues.
Configure SPF/DKIM records. Missing authentication records are the primary cause.
Change the from name. Go to Settings > Email Design and set a recognizable sender name. “WordPress” as a sender name triggers spam filters on some providers.
Use a from address on your domain. An SMTP plugin lets you set the from address to something like alerts@yourdomain.com instead of wordpress@yourdomain.com.
Check the email content. Some spam filters flag emails with large code blocks or technical content. If stack traces are enabled, the email contains raw PHP paths and function names — some filters flag this as suspicious. Try disabling the stack trace option and see if deliverability improves.
WPDT installs a fatal-error-handler.php drop-in to catch fatal errors that bypass set_error_handler(). If another plugin or your host has its own fatal-error-handler.php in wp-content/, only one can be active. Check if the file exists and whether it belongs to WPDT.
WordPress 5.2+ is required for the fatal error handler. Older WordPress versions do not support the fatal-error-handler.php drop-in.
When a fatal error triggers WordPress recovery mode, two things happen:
The WPDT notification includes additional debug context (WPDT version, viewer status, MU-plugin status) that helps support teams assess the situation without logging in.
For agencies managing multiple WordPress sites, set each site’s recipient to a shared inbox or a per-site alias. Use the white-label feature to brand notifications with your agency name. Set conservative rate limits (6-hour cooldown, 5 per hour) to keep aggregate email volume manageable.
WPDT sends emails through wp_mail(). If you need alerts in Slack, PagerDuty, or another channel, set the recipient to an email-to-Slack bridge address (most Slack workspaces support incoming email) or use a service like Zapier to forward notification emails to other channels.
WPDT installs wp-content/fatal-error-handler.php to extend WordPress’s default WP_Fatal_Error_Handler. The drop-in processes recovery mode normally, then delegates to the MU-plugin to send a WPDT notification. This ensures coverage for errors that set_error_handler() cannot catch: memory exhaustion, maximum execution time, and parse errors.
If another plugin also uses fatal-error-handler.php, only one can be active. Check wp-content/ for this file and verify it belongs to WPDT.
| WPDT | Manual error handler | Sentry / Bugsnag / New Relic | |
|---|---|---|---|
| Setup | Admin UI, no code | Write and maintain PHP code | SDK installation + account setup |
| Rate limiting | Built-in (per-error + hourly cap) | You implement it | Built-in (event grouping) |
| Error level filtering | Checkboxes in UI | You implement it | Configurable via SDK |
| Fatal error coverage | Yes (fatal-error-handler.php drop-in) | Requires shutdown function | Yes |
| Email customization | Full template editor with live preview | You build the email format | Dashboard alerts, not email-focused |
| White-label | Yes | N/A | No |
| Works when WordPress is down | Standalone viewer link in email | No (wp_mail unavailable) | Yes (external service) |
| Cost | Included with Site Monitor or Pro license | Free (your time) | Free tier or paid plans |
| Additional features | Error grouping in dashboard | None | APM, distributed tracing, release tracking |
| Best for | WordPress-specific monitoring | Quick one-off solution | Teams needing cross-application observability |