I’ve been adding additional admin addresses for a long-time to WordPress installations, the sites actual admin and a few of my own its important to get those your site is having issues emails and to make sure everyone gets a copy particularly if you have clients. After all how good must it be to say its already fixed when they raise an issue or concern with you.
I’ve been doing this with an ever evolving snippet and today following a facebook post requesting this sort of thing thought i’d publish the latest snippet of how I am doing this.
Snippet
Using your snippet manager of choice for me thats wpcodebox, you need to add the below code
<?php
/** ---------------------------
* Settings field + sanitize
* --------------------------*/
add_action('admin_init', function () {
add_settings_field(
'additional_admin_emails',
'Additional Admin Emails',
'naf_render_email_field',
'general',
'default'
);
register_setting('general', 'additional_admin_emails', [
'type' => 'string',
'sanitize_callback' => 'naf_sanitize_emails',
'default' => '',
]);
});
function naf_render_email_field() {
$emails = get_option('additional_admin_emails', '');
echo '<textarea name="additional_admin_emails" id="additional_admin_emails" class="large-text" rows="3" placeholder="Enter emails separated by commas, semicolons, or new lines">'
. esc_textarea($emails)
. '</textarea>';
echo '<p class="description">These addresses will receive <em>separate</em> copies of any email originally sent to the main admin email.</p>';
}
function naf_sanitize_emails($value) {
$raw = preg_split('/[\s,;]+/', (string) $value, -1, PREG_SPLIT_NO_EMPTY);
$valid = [];
foreach ($raw as $e) {
$e = strtolower(trim($e));
if (is_email($e)) $valid[$e] = true;
}
return implode(', ', array_keys($valid));
}
function naf_get_extra_recipients() {
$list = get_option('additional_admin_emails', '');
if ($list === '') return [];
$raw = preg_split('/[\s,;]+/', (string) $list, -1, PREG_SPLIT_NO_EMPTY);
$out = [];
foreach ($raw as $e) {
$e = strtolower(trim($e));
if (is_email($e)) $out[$e] = true;
}
return array_keys($out);
}
/** ---------------------------------
* Fan-out mailer via pre_wp_mail
* --------------------------------*/
function naf_pre_wp_mail_fanout($pre, $atts) {
$extras = naf_get_extra_recipients();
if (!$extras) return $pre;
$admin_email = strtolower(get_option('admin_email'));
$original_to = is_array($atts['to']) ? $atts['to'] : explode(',', $atts['to']);
$original_to = array_map('trim', $original_to);
$original_to = array_map('strtolower', $original_to);
// Abort if admin email isn't a recipient
if (!in_array($admin_email, $original_to, true)) {
return $pre;
}
// Collect original recipients (to/cc/bcc) to avoid duplicates
$original = [];
foreach ($original_to as $addr) {
if (is_email($addr)) $original[$addr] = true;
}
$headers = isset($atts['headers']) ? (array)$atts['headers'] : [];
foreach ($headers as $h) {
if (!is_string($h)) continue;
if (preg_match('/^(Cc|Bcc):\s*(.+)$/i', $h, $m)) {
foreach (preg_split('/\s*,\s*/', $m[2]) as $a) {
$a = strtolower(trim($a));
if (is_email($a)) $original[$a] = true;
}
}
}
$fanout = array_values(array_diff($extras, array_keys($original)));
if (!$fanout) return $pre;
// Prevent recursion (named function removal works now)
remove_filter('pre_wp_mail', 'naf_pre_wp_mail_fanout', 10);
$ok_all = true;
// Send original
$ok = wp_mail(
$atts['to'],
$atts['subject'],
$atts['message'],
$atts['headers'] ?? [],
$atts['attachments'] ?? []
);
$ok_all = $ok_all && (bool)$ok;
// Send clones
foreach ($fanout as $rcpt) {
$ok = wp_mail(
$rcpt,
$atts['subject'],
$atts['message'],
$atts['headers'] ?? [],
$atts['attachments'] ?? []
);
$ok_all = $ok_all && (bool)$ok;
}
add_filter('pre_wp_mail', 'naf_pre_wp_mail_fanout', 10, 2);
return $ok_all;
}
add_filter('pre_wp_mail', 'naf_pre_wp_mail_fanout', 10, 2);
/** -------------------------------------------
* Test button (POST form) with nonce
* ------------------------------------------*/
add_action('admin_footer-options-general.php', function () {
if (!current_user_can('manage_options')) return;
$action = esc_url( admin_url('admin-post.php') );
$nonce = wp_create_nonce('naf_send_test_action');
?>
<script>
(function(){
const field = document.getElementById('additional_admin_emails');
if (!field) return;
const row = field.closest('tr');
if (!row) return;
const cell = row.querySelector('td');
const form = document.createElement('form');
form.method = 'POST';
form.action = <?php echo json_encode($action); ?>;
form.style.marginTop = '8px';
form.style.display = 'inline-block';
const act = document.createElement('input');
act.type = 'hidden';
act.name = 'action';
act.value = 'naf_send_test';
const nonce = document.createElement('input');
nonce.type = 'hidden';
nonce.name = '_wpnonce';
nonce.value = <?php echo json_encode($nonce); ?>;
const btn = document.createElement('button');
btn.type = 'submit';
btn.className = 'button';
btn.textContent = 'Send Test Email';
form.appendChild(act);
form.appendChild(nonce);
form.appendChild(btn);
cell.appendChild(document.createElement('br'));
cell.appendChild(form);
})();
</script>
<?php
});
add_action('admin_post_naf_send_test', function () {
if (!current_user_can('manage_options') || !check_admin_referer('naf_send_test_action')) {
wp_die('Not allowed.');
}
$to = get_option('admin_email');
$subject = 'Test: Additional Admin Emails (Fan-out)';
$message = "Hello!\n\nThis is a test email sent on " . date('c') . ".\nEach additional recipient should receive a separate email (only triggers because it's addressed to the admin email).";
$ok = wp_mail($to, $subject, $message);
add_settings_error(
'general',
'naf_test_mail',
$ok ? '✅ Test email sent.' : '❌ Test email failed.',
$ok ? 'updated' : 'error'
);
wp_safe_redirect( admin_url('options-general.php#additional_admin_emails') );
exit;
});
PHPThe above adds a new options in the settings > General Tab at the bottom called additional admin emails

Additional emails can be added as new lines, commas or semicolons and when you use the send test email option you should get the following test email to ALL email accounts

Warning: This includes all admin emails will now be sent to the full round robin, if wpmail is sending an email to the admin email, it will be filtered and a copy will go to each additional admin address including the admin users password resets IF also a user account. i.e like below
