Saltar al contenido
Docs

Tutorial

Envía el correo de Laravel a través de Emailit con el transporte de correo y la facade de emailit/emailit-laravel, o con SMTP sin más, y verifica los webhooks de Emailit.

Actualizado el 1 oct 2026

En esta guía se explican dos formas de enviar el correo de Laravel a través de Emailit: el paquete emailit/emailit-laravel, que añade un transporte de correo emailit y una facade Emailit, y SMTP sin más con el mailer integrado de Laravel. Al final se incluye una ruta de webhook que verifica las firmas.

Requisitos previos

  • PHP 8.1 o posterior y Laravel 10, 11 o 12.
  • Un dominio de envío verificado, por ejemplo acme.com.
  • Una clave de API. Basta con una clave Sending Only limitada a tu dominio.
  • Hasta que tu espacio de trabajo tenga acceso de producción, solo puedes enviar a las direcciones de email de las cuentas de los miembros del espacio de trabajo.

Opción 1: el paquete de Laravel de Emailit

El paquete envía tus Mailables, Markdown mailables, notificaciones y correo en cola actuales a través de la API de Emailit, sin cambiar tu código de correo.

Instalar el paquete

Terminal
composer require emailit/emailit-laravel

El service provider se detecta automáticamente.

Configurar el transporte

Añade tu clave y haz que Emailit sea el mailer por defecto en .env:

.env
EMAILIT_API_KEY=secret_••••••••••••••••••••••••••••••••
MAIL_MAILER=emailit
MAIL_FROM_ADDRESS=hello@acme.com
MAIL_FROM_NAME="Acme"

Registra el mailer en config/mail.php:

config/mail.php
'mailers' => [
    // ...

    'emailit' => [
        'transport' => 'emailit',
    ],
],

MAIL_FROM_ADDRESS debe pertenecer a un dominio de envío verificado. Para cambiar la URL base de la API, publica el archivo de configuración con php artisan vendor:publish --tag=emailit-config; para un uso normal no hace falta.

Enviar un Mailable

Crea un Mailable como de costumbre:

Terminal
php artisan make:mail WelcomeEmail
app/Mail/WelcomeEmail.php
namespace App\Mail;

use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;

class WelcomeEmail extends Mailable
{
    use Queueable, SerializesModels;

    public function __construct(public User $user) {}

    public function envelope(): Envelope
    {
        return new Envelope(subject: 'Welcome to Acme');
    }

    public function content(): Content
    {
        return new Content(view: 'emails.welcome');
    }
}

Envíalo, o ponlo en cola para que la petición no espere a la API:

PHP
use App\Mail\WelcomeEmail;
use Illuminate\Support\Facades\Mail;

Mail::to($user)->send(new WelcomeEmail($user));

Mail::to($user)->queue(new WelcomeEmail($user));

Usar la facade para las funciones de la API

La facade Emailit expone todo el SDK de PHP para las funciones que el mailer de Laravel no contempla, como las plantillas guardadas y los envíos programados:

PHP
use Emailit\Laravel\Facades\Emailit;

$email = Emailit::emails()->send([
    'from'         => 'Acme <hello@acme.com>',
    'to'           => $user->email,
    'template'     => 'welcome',
    'variables'    => ['first_name' => $user->first_name],
    'scheduled_at' => 'tomorrow at 9am',
]);

$email->id; // em_…

La facade también cubre los dominios, los contactos, las listas de contactos, las direcciones bloqueadas, los webhooks y los demás recursos. Si prefieres la inyección de dependencias, declara el tipo Emailit\EmailitClient en un controlador o un job y Laravel lo resuelve con la clave que has configurado.

Captura las excepciones tipadas para gestionar los fallos:

PHP
use Emailit\Exceptions\ApiErrorException;
use Emailit\Exceptions\RateLimitException;

try {
    Emailit::emails()->send($payload);
} catch (RateLimitException $e) {
    // 429: release the job back to the queue and try again later
} catch (ApiErrorException $e) {
    report($e); // $e->getHttpStatus() has the status code
}

Opción 2: SMTP sin más

Si prefieres no añadir un paquete, apunta el mailer SMTP de Laravel al relay de Emailit:

.env
MAIL_MAILER=smtp
MAIL_HOST=smtp.emailit.com
MAIL_PORT=587
MAIL_USERNAME=emailit
MAIL_PASSWORD=secret_••••••••••••••••••••••••••••••••
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=hello@acme.com
MAIL_FROM_NAME="Acme"

En el puerto 587, el mailer de Laravel actualiza la conexión con STARTTLS. Los archivos config/mail.php antiguos leen MAIL_ENCRYPTION y los nuevos lo ignoran, así que puedes mantenerlo sin problemas. Para TLS implícito, usa el puerto 465; si tu proveedor de hosting bloquea el 587, usa 2525 o 2587. Los Mailables, las notificaciones y las colas funcionan exactamente igual que con el paquete. Consulta Configuración SMTP.

Por SMTP no puedes usar plantillas guardadas ni scheduled_at; para eso, usa la facade o la API.

Recibir webhooks

Crea un webhook que apunte a https://your-app.com/webhooks/emailit y después guarda su secreto de firma:

.env
EMAILIT_WEBHOOK_SECRET=whsec_••••••••
config/services.php
'emailit' => [
    'webhook_secret' => env('EMAILIT_WEBHOOK_SECRET'),
],

Añade un controlador que compruebe la firma con el cuerpo en bruto:

app/Http/Controllers/EmailitWebhookController.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class EmailitWebhookController extends Controller
{
    public function __invoke(Request $request)
    {
        $payload = $request->getContent();
        $signature = (string) $request->header('X-Emailit-Signature');
        $timestamp = (string) $request->header('X-Emailit-Timestamp');

        $expected = hash_hmac('sha256', $timestamp.'.'.$payload, config('services.emailit.webhook_secret'));

        if (abs(time() - (int) $timestamp) > 300 || ! hash_equals($expected, $signature)) {
            abort(401, 'Invalid signature');
        }

        // The body is a JSON array of up to 100 events.
        foreach (json_decode($payload, true) as $event) {
            match ($event['type']) {
                'email.bounced', 'email.complained' => $this->stopEmailing($event['data']['object']['to']),
                default => null,
            };
        }

        return response()->noContent();
    }

    private function stopEmailing(string $address): void
    {
        // Mark the address as undeliverable in your database.
    }
}

Registra la ruta y exclúyela de la protección CSRF, porque Emailit no puede enviar un token CSRF:

routes/web.php
use App\Http\Controllers\EmailitWebhookController;

Route::post('/webhooks/emailit', EmailitWebhookController::class);
bootstrap/app.php (Laravel 11 and 12)
->withMiddleware(function (Middleware $middleware) {
    $middleware->validateCsrfTokens(except: ['webhooks/emailit']);
})

En Laravel 10, añade en su lugar 'webhooks/emailit' al array $except de app/Http/Middleware/VerifyCsrfToken.php. Devuelve un 2xx en menos de 30 segundos y pasa el trabajo lento a una cola. Consulta Firma de las peticiones.

Consejos para producción

  • Pon el correo en cola. Usa queue() o ShouldQueue para que las peticiones web no esperen al email, y limita el ritmo de los jobs masivos (por ejemplo, con Redis::throttle) para no superar tus límites de envío. Por defecto, los espacios de trabajo nuevos pueden enviar 2 emails por segundo.
  • Usa la caché de configuración de forma segura. Después de php artisan config:cache, env() solo funciona dentro de los archivos de configuración. Lee la clave a través de la configuración, como hace el paquete.
  • Usa una clave dedicada. Da a cada aplicación y a cada entorno su propia clave Sending Only para poder rotar una sin tocar las demás. Consulta Claves de API.
  • Elimina los webhooks duplicados. Guarda cada event_id que procesas y omite las repeticiones, porque las entregas fallidas se reintentan.

Próximos pasos

El cliente que hay detrás de la facade.
Diseña emails en Emailit y envíalos por su alias.
Todos los eventos y su payload.
Corrige los errores de autenticación y de conexión.

¿Te ha resultado útil esta página?

Gracias por tu opinión.

Gracias. Leemos todos los mensajes.