Como enviar emails con wp_mail y plantillas HTML en PHP en WordPress

Contents

Introducción

Este tutorial explica de forma exhaustiva cómo enviar correos electrónicos desde WordPress usando la función wp_mail y plantillas HTML en PHP. Incluye ejemplos prácticos, configuración del tipo de contenido, carga de plantillas, seguridad, personalización del remitente y depuración. Los fragmentos de código están listados para copiar y pegar directamente en temas o plugins.

Qué es wp_mail y cómo funciona

wp_mail() es la envoltura de WordPress sobre PHPMailer. Permite enviar correo usando parámetros simples (to, subject, message, headers, attachments). Por defecto envía texto plano para enviar HTML hay que indicar el Content-Type adecuado o usar filtros. Además, hay filtros útiles como wp_mail_from, wp_mail_from_name y wp_mail_content_type para personalizar comportamiento.

Requisitos y buenas prácticas previas

  • Asegúrate de que tu servidor puede enviar correo saliente. En muchos casos conviene configurar un SMTP real (por ejemplo mediante el plugin WP Mail SMTP) o usando phpmailer_init para ajustar credenciales.
  • Sanitiza y valida las direcciones de correo con sanitize_email() y is_email() antes de pasarlas a wp_mail.
  • Usa nonces y comprobaciones de permisos al enviar correos desde formularios públicos para evitar abuso y envío masivo no autorizado.

Contenido HTML: establecer el tipo correctamente

Para que los clientes de correo interpreten correctamente HTML, debes indicar el Content-Type. Lo habitual es añadir un filtro temporal que lo ponga en text/html charset=UTF-8:

add_filter(wp_mail_content_type, function() {
    return text/html charset=UTF-8
})

Tras enviar el correo conviene restablecer el tipo por defecto (text/plain) para no romper otros envíos:

// Añadir antes de wp_mail
add_filter(wp_mail_content_type, my_html_content_type)
wp_mail(to, subject, message, headers, attachments)
remove_filter(wp_mail_content_type, my_html_content_type)

function my_html_content_type() {
    return text/html charset=UTF-8
}

Carga de una plantilla HTML desde el tema o plugin

Lo ideal es mantener plantillas HTML separadas en archivos y cargarlas para evitar concatenar cadenas en el código. A continuación un patrón seguro para cargar una plantilla y pasarle variables.

Ejemplo de plantilla (archivo: email-templates/user-welcome.php) — contiene HTML completo y placeholders:

lt!doctype htmlgt
lthtml lang=esgt
ltheadgt
  ltmeta charset=utf-8gt
  ltmeta name=viewport content=width=device-widthgt
  lttitlegtBienvenidolt/titlegt
  ltstylegt
    / CSS mínimo inline recomendado para compatibilidad en clientes de correo /
    body { font-family: Arial, sans-serif color: #333 }
    .container { width: 100% max-width: 600px margin: 0 auto }
    .btn { display:inline-block padding:10px 16px background:#0073aa color:#fff text-decoration:none border-radius:3px }
  lt/stylegt
lt/headgt
ltbodygt
  lttable role=presentation width=100% cellpadding=0 cellspacing=0gt
    lttrgtlttd class=containergt
      lth2gtHola, {{name}}!lt/h2gt
      ltpgtGracias por registrarte en nuestro sitio. Para activar tu cuenta pulsa el siguiente botón:lt/pgt
      ltpgtlta class=btn href={{activation_url}}gtActivar cuentalt/agtlt/pgt
      ltpgtSi no has solicitado esto, ignora este correo.lt/pgt
    lt/tdgtlt/trgt
  lt/tablegt
lt/bodygt
lt/htmlgt

Función para renderizar y enviar usando la plantilla anterior:

function send_templated_email( to, subject, template_path, vars = array(), attachments = array() ) {
    // Validaciones básicas
    to = sanitize_email( to )
    if ( ! is_email( to ) ) {
        return false
    }

    // Localiza la plantilla en tema/child o en plugin
    located = locate_template( template_path )
    if ( ! located ) {
        // Si estás en un plugin puedes usar plugin_dir_path(__FILE__) . templates/ . template_path
        return false
    }

    // Cargar plantilla y capturar salida
    ob_start()
    load_template( located, false )
    message = ob_get_clean()

    // Reemplazar variables seguras (usar esc_html para valores simples)
    foreach ( vars as key => value ) {
        safe = esc_html( value )
        message = str_replace( {{ . key . }}, safe, message )
    }

    // Cabeceras: indicar HTML
    add_filter(wp_mail_content_type, function() { return text/html charset=UTF-8 })

    // Enviar
    sent = wp_mail( to, subject, message, array(), attachments )

    // Restaurar filtros
    remove_filter(wp_mail_content_type, wp_mail_content_type)

    return sent
}

Ejemplo práctico: envío tras registro (procesamiento de formulario) con nonce y sanitización

if ( isset(_POST[my_register_form]) ) {
    if ( ! isset(_POST[_wpnonce])  ! wp_verify_nonce( _POST[_wpnonce], my_register_action ) ) {
        wp_die(Nonce no válido)
    }

    email = isset(_POST[email]) ? sanitize_email(_POST[email]) : 
    name  = isset(_POST[name]) ? sanitize_text_field(_POST[name]) : 

    if ( ! is_email(email) ) {
        wp_die(Email no válido)
    }

    activation_link = add_query_arg( array( key => wp_generate_uuid4(), email => rawurlencode(email) ), home_url(/activar/) )

    vars = array(
        name => name,
        activation_url => activation_link,
    )

    sent = send_templated_email( email, Activa tu cuenta, email-templates/user-welcome.php, vars )

    if ( sent ) {
        // Redirigir o mostrar mensaje de éxito
    } else {
        // Gestionar error
    }
}

Personalizar el remitente (From) de forma segura

Modificar From mediante cabeceras puede funcionar, pero lo recomendado es usar los filtros de WordPress para evitar problemas con múltiples envíos concurrentes. Ejemplo:

function my_mail_from( original_email_address ) {
    return no-reply@tudominio.com
}
function my_mail_from_name( original_email_from ) {
    return Tu Sitio
}

// Antes de enviar
add_filter(wp_mail_from, my_mail_from)
add_filter(wp_mail_from_name, my_mail_from_name)

wp_mail(to, subject, message)

// Después de enviar (restaurar)
remove_filter(wp_mail_from, my_mail_from)
remove_filter(wp_mail_from_name, my_mail_from_name)

Configurar SMTP mediante phpmailer_init (opción programática)

Si no quieres usar plugins, puedes configurar PHPMailer con el hook phpmailer_init. Útil para entornos donde el mail() está deshabilitado.

add_action(phpmailer_init, function(phpmailer) {
    phpmailer->isSMTP()
    phpmailer->Host = smtp.example.com
    phpmailer->SMTPAuth = true
    phpmailer->Port = 587
    phpmailer->Username = usuario@smtp
    phpmailer->Password = contraseña
    phpmailer->SMTPSecure = tls // o ssl
    phpmailer->From = no-reply@tudominio.com
    phpmailer->FromName = Tu Sitio
})

Adjuntos y cabeceras adicionales

wp_mail acepta un array de cabeceras y un array de rutas de archivos como adjuntos. Ejemplo:

headers = array(
    Reply-To: Soporte ,
    X-Mailer: WordPress/ . get_bloginfo(version)
)
attachments = array( WP_CONTENT_DIR . /uploads/manual.pdf )

wp_mail( to, subject, message, headers, attachments )

Cómo depurar envíos que fallan

  • Activa WP_DEBUG y revisa logs. A veces wp_mail devuelve false y no hay mensajes: habilita el log del servidor SMTP o depura PHPMailer con el hook phpmailer_init.
  • Plugins como WP Mail SMTP ofrecen registros para ver errores SMTP.
  • Comprueba que el servidor no esté bloqueando el puerto SMTP y revisa SPF/DKIM/DMARC si los correos llegan marcados como spam.

Seguridad y compatibilidad

  1. Sanitiza inputs antes de incluirlos en la plantilla para evitar inyección de HTML no deseada. Usa esc_html() para texto simple y wp_kses_post() si permites etiquetas HTML limitadas.
  2. No incluyas datos sensibles en correos no cifrados (contraseñas en texto claro, tokens permanentes, etc.).
  3. Para emails transaccionales críticos, usa proveedores SMTP/servicios dedicados (SendGrid, Mailgun, Amazon SES) para mayor entregabilidad y métricas.
  4. Para plantillas con CSS avanzado, aplica estilos inline o utiliza herramientas para inlinizar CSS antes de enviar (mejor compatibilidad con clientes de correo).

Pruebas y flujo recomendado

Prueba localmente con servicios de inspección de correo (MailHog, Mailtrap) o plugins que redirijan correos a logs durante desarrollo. Implementa primero la versión en texto plano y luego añade HTML para depurar de forma más sencilla.

Resumen

Enviar correos HTML en WordPress con wp_mail implica:

  • Establecer el content-type a text/html.
  • Organizar plantillas HTML separadas y cargarlas con locate_template/load_template o desde carpetas de plugin.
  • Sanitizar datos, usar nonces en formularios y configurar el remitente de forma segura mediante filtros.
  • Si el servidor no envía correctamente, configurar SMTP vía plugin o phpmailer_init.

Enlaces útiles



Acepto donaciones de BAT's mediante el navegador Brave 🙂



Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *