WordPress’s wp_mail() function wraps PHP’s native mail() and adds filter hooks that let you control the sender name, sender address, content type, and headers from anywhere in your code — no plugin required.
Problem: How do you send a custom HTML email from WordPress — triggered by a form submission, a post status change, or any custom event — without installing a plugin?
Solution: Use wp_mail() with a Content-Type: text/html header added via the wp_mail_content_type filter. It respects the site's configured mail transport (PHP mail, SMTP, or a plugin) and reads the From address from WordPress settings.
Sending a basic HTML email:
add_filter( 'wp_mail_content_type', function() {
return 'text/html';
} );
$to = 'recipient@example.com';
$subject = 'Your order has shipped';
$body = '
<p>Hi there,</p>
<p>Your order #<strong>1042</strong> has been shipped and is on its way.</p>
<p>Thanks for shopping with us.</p>
';
$headers = [
'From: My Shop <shop@example.com>',
'Reply-To: support@example.com',
'Cc: manager@example.com',
];
wp_mail( $to, $subject, $body, $headers );
// Important: reset content type after sending to avoid affecting other emails
remove_filter( 'wp_mail_content_type', function() {
return 'text/html';
} );
A cleaner approach — use a named function so it can be removed:
function set_html_content_type() {
return 'text/html';
}
add_filter( 'wp_mail_content_type', 'set_html_content_type' );
wp_mail( $to, $subject, $body, $headers );
remove_filter( 'wp_mail_content_type', 'set_html_content_type' );
Override the default "WordPress" sender name and address globally:
add_filter( 'wp_mail_from', function() { return 'noreply@example.com'; } );
add_filter( 'wp_mail_from_name', function() { return 'My Website'; } );
NOTE: For reliable deliverability, configure an SMTP plugin (WP Mail SMTP, Post SMTP) to route emails through a transactional mail service like SendGrid, Mailgun, or Amazon SES. PHP's built-in mail() function is frequently blocked or flagged as spam by receiving servers.