Tema
Correo con PHPMailer (SMTP)
La función mail() de PHP suele terminar en spam o directamente no funciona. PHPMailer envía a través de un servidor SMTP real (el de tu hosting, Gmail, Brevo, Mailgun...), con autenticación y cifrado, así que tus correos sí llegan.
Instalación
bash
composer require phpmailer/phpmailerEsto crea la carpeta vendor/. Si tu hosting no tiene Composer, instálalo en tu computadora y sube la carpeta vendor/ completa por FTP.
Variables de entorno
env
MAIL_HOST=smtp.tudominio.com
MAIL_PORT=587
MAIL_USER=no-responder@tudominio.com
MAIL_PASS=contraseña-del-buzon
MAIL_SECURE=tls # tls (puerto 587) o ssl (puerto 465)
MAIL_FROM=no-responder@tudominio.com
MAIL_FROM_NAME="Mi Negocio"Datos SMTP de servicios comunes
| Servicio | Host | Puerto | Seguridad |
|---|---|---|---|
| cPanel / hosting | mail.tudominio.com | 465 / 587 | ssl / tls |
| Gmail (con contraseña de aplicación) | smtp.gmail.com | 587 | tls |
| Outlook / Microsoft 365 | smtp.office365.com | 587 | tls |
| Brevo (ex Sendinblue) | smtp-relay.brevo.com | 587 | tls |
Para Gmail necesitas activar la verificación en dos pasos y crear una contraseña de aplicación en tu cuenta de Google.
La función reutilizable
php
<?php
require_once __DIR__ . '/env.php';
require_once dirname(__DIR__) . '/vendor/autoload.php';
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
/**
* Envía un correo HTML.
*
* @param string|array $para 'ana@correo.com' o ['ana@correo.com' => 'Ana López', ...]
* @param string $asunto
* @param string $html Cuerpo en HTML
* @param array $opciones ['texto' => ..., 'responder_a' => ..., 'adjuntos' => [ruta, ...], 'cc' => [...]]
* @return bool true si se envió
*/
function enviar_correo(string|array $para, string $asunto, string $html, array $opciones = []): bool
{
$mail = new PHPMailer(true); // true = lanza excepciones
try {
// Servidor
$mail->isSMTP();
$mail->Host = env('MAIL_HOST');
$mail->SMTPAuth = true;
$mail->Username = env('MAIL_USER');
$mail->Password = env('MAIL_PASS');
$mail->SMTPSecure = env('MAIL_SECURE', 'tls') === 'ssl'
? PHPMailer::ENCRYPTION_SMTPS
: PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = (int) env('MAIL_PORT', 587);
$mail->CharSet = 'UTF-8';
// $mail->SMTPDebug = 2; // ← descomenta para ver el diálogo SMTP al depurar
// Remitente (debe ser del mismo dominio del buzón para no caer en spam)
$mail->setFrom(env('MAIL_FROM'), env('MAIL_FROM_NAME', ''));
// Destinatarios
foreach ((array) $para as $clave => $valor) {
is_int($clave) ? $mail->addAddress($valor) : $mail->addAddress($clave, $valor);
}
foreach ($opciones['cc'] ?? [] as $cc) {
$mail->addCC($cc);
}
if (!empty($opciones['responder_a'])) {
$mail->addReplyTo($opciones['responder_a']);
}
foreach ($opciones['adjuntos'] ?? [] as $ruta) {
$mail->addAttachment($ruta);
}
// Contenido
$mail->isHTML(true);
$mail->Subject = $asunto;
$mail->Body = plantilla_correo($asunto, $html);
$mail->AltBody = $opciones['texto'] ?? trim(strip_tags(str_replace(['<br>', '</p>'], "\n", $html)));
return $mail->send();
} catch (Exception $e) {
error_log('Error al enviar correo: ' . $mail->ErrorInfo);
return false;
}
}
/** Envuelve el contenido en un diseño sencillo compatible con clientes de correo */
function plantilla_correo(string $titulo, string $contenido): string
{
$marca = htmlspecialchars(env('MAIL_FROM_NAME', 'Mi sitio'));
return <<<HTML
<!DOCTYPE html>
<html lang="es"><body style="margin:0;background:#f1f5f9;font-family:Arial,sans-serif">
<table width="100%" cellpadding="0" cellspacing="0" style="padding:24px 0">
<tr><td align="center">
<table width="600" cellpadding="0" cellspacing="0" style="max-width:600px;background:#ffffff;border-radius:12px;overflow:hidden">
<tr><td style="background:#4f46e5;color:#fff;padding:20px 28px;font-size:20px;font-weight:bold">$marca</td></tr>
<tr><td style="padding:28px;color:#1e293b;font-size:15px;line-height:1.6">
<h2 style="margin-top:0">$titulo</h2>
$contenido
</td></tr>
<tr><td style="padding:16px 28px;background:#f8fafc;color:#64748b;font-size:12px">
Este correo se envió automáticamente, por favor no respondas.
</td></tr>
</table>
</td></tr>
</table>
</body></html>
HTML;
}Ejemplos de uso
php
<?php
require __DIR__ . '/includes/mailer.php';
// Simple
enviar_correo('cliente@correo.com', 'Tu pedido fue recibido', '<p>Gracias por tu compra, pedido <b>#1024</b>.</p>');
// Con nombre, copia, responder-a y adjunto PDF
$ok = enviar_correo(
['ana@correo.com' => 'Ana López'],
'Factura de octubre',
'<p>Hola Ana, adjuntamos tu factura.</p>',
[
'cc' => ['contabilidad@tudominio.com'],
'responder_a' => 'ventas@tudominio.com',
'adjuntos' => [__DIR__ . '/facturas/F-2026-0045.pdf'],
]
);
if (!$ok) {
echo 'No se pudo enviar el correo. Intenta más tarde.';
}Que tus correos no lleguen a spam
- Remitente del mismo dominio: envía desde
algo@tudominio.com, nunca desde un Gmail usando el SMTP de tu hosting. - Configura SPF, DKIM y DMARC en el DNS de tu dominio (cPanel → Email Deliverability lo hace casi solo).
- Incluye siempre
AltBody(versión en texto plano). - Evita asuntos en MAYÚSCULAS y palabras como "GRATIS!!!".
- Para envíos masivos (boletines) usa un servicio dedicado (Brevo, Mailchimp, Amazon SES), no tu hosting.
Error común
Poner MAIL_PORT=465 con MAIL_SECURE=tls, o 587 con ssl. El 465 va con ssl y el 587 con tls. Si no coinciden verás "SMTP connect() failed".