> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lettr.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Sending Emails

> Send emails with Lettr in Laravel using the Mail facade, Lettr facade, quick template sending, email builder, or custom Mailables

Lettr integrates seamlessly with Laravel's mail system. This page covers every approach — from the standard Mail facade to the low-level email builder — so you can choose the one that fits your use case.

| Approach                                          | Best For                                                        |
| ------------------------------------------------- | --------------------------------------------------------------- |
| [Mail Facade](#using-laravels-mail-facade)        | Existing Laravel apps — drop-in replacement, no code changes    |
| [Quick Template Sending](#quick-template-sending) | One-off template emails without creating a Mailable class       |
| [Lettr Facade](#using-the-lettr-facade)           | Direct API access with full control over every parameter        |
| [Email Builder](#email-builder)                   | Complex emails with tracking, metadata, and multiple recipients |
| [Custom Mailables](#custom-mailable-classes)      | Reusable, testable email classes using Lettr templates          |

## Using Laravel's Mail Facade

If you've set Lettr as your default mailer, use Laravel's standard Mail facade:

```php theme={null}
use App\Mail\OrderShipped;
use Illuminate\Support\Facades\Mail;

Mail::to('customer@example.com')->send(new OrderShipped($order));
```

This is the simplest approach if you're migrating from another mail provider. Your existing Mailable classes work without modification — just change the mailer in your `.env` and all emails route through Lettr.

If Lettr isn't your default mailer, specify it explicitly:

```php theme={null}
Mail::mailer('lettr')->to('customer@example.com')->send(new OrderShipped($order));
```

## Quick Template Sending

Send a Lettr template without creating a Mailable class:

```php theme={null}
use Illuminate\Support\Facades\Mail;

Mail::lettr()
    ->to('user@example.com')
    ->sendTemplate('welcome-email', substitutionData: [
        'name' => 'John',
        'company' => 'Acme Inc',
    ]);
```

The array keys map to merge tags in your Lettr template. For example, `'name' => 'John'` fills the `{{name}}` merge tag. See [Merge Tags & Template Language](/learn/templates/template-language) for the full syntax.

With additional options:

```php theme={null}
Mail::lettr()
    ->to('user@example.com')
    ->cc('manager@example.com')
    ->bcc('archive@example.com')
    ->sendTemplate(
        templateSlug: 'order-confirmation',
        subject: 'Order Confirmation',
        substitutionData: [
            'order_id' => $order->id,
            'items' => $order->items->toArray(),
        ],
        version: 2,
    );
```

<Tip>
  Use `version` to pin a specific template version in production. Omit it to always use the active (published) version. See [Template Versioning](/quickstart/laravel/templates#template-versioning) for details.
</Tip>

## Using the Lettr Facade

For full control, use the Lettr facade directly. This bypasses Laravel's mail abstraction and calls the Lettr API with explicit parameters.

### HTML Email

```php theme={null}
use Lettr\Laravel\Facades\Lettr;

Lettr::emails()->sendHtml(
    from: 'hello@yourdomain.com',
    to: 'recipient@example.com',
    subject: 'Hello from Lettr',
    html: '<h1>Welcome!</h1><p>Thanks for signing up.</p>'
);
```

### Plain Text Email

```php theme={null}
Lettr::emails()->sendText(
    from: 'hello@yourdomain.com',
    to: ['user1@example.com', 'user2@example.com'],
    subject: 'Plain text update',
    text: 'This is a plain text email.'
);
```

The `to` parameter accepts both a single email string and an array of recipients.

### Template Email

```php theme={null}
Lettr::emails()->sendTemplate(
    from: 'hello@yourdomain.com',
    to: 'customer@example.com',
    subject: 'Your order is ready!',
    templateSlug: 'order-ready',
    substitutionData: [
        'customer_name' => $customer->name,
        'order_number' => $order->number,
    ]
);
```

<Note>
  When using the Lettr facade, you must provide the `from` address explicitly since it doesn't use Laravel's `MAIL_FROM_ADDRESS` config automatically.
</Note>

## Email Builder

For complex emails, use the fluent email builder. This gives you access to every option the Lettr API supports in a chainable interface:

```php theme={null}
use Lettr\Laravel\Facades\Lettr;

$response = Lettr::emails()->send(
    Lettr::emails()->create()
        ->from('sender@yourdomain.com', 'Your Company')
        ->to(['recipient@example.com'])
        ->cc(['cc@example.com'])
        ->bcc(['bcc@example.com'])
        ->subject('Monthly Newsletter')
        ->html('<h1>Newsletter</h1><p>{{content}}</p>')
        ->text('Newsletter: {{content}}')
        ->substitutionData(['content' => $newsletterContent])
        ->withOpenTracking(true)
        ->withClickTracking(true)
        ->tag('welcome')
);

// Access the response
echo $response->requestId;
echo $response->accepted;
```

The builder is useful when you need to combine multiple features in a single email — for example, HTML content with a plain text fallback, tracking, metadata, and attachments.

### Response Object

The `send()` method returns a response object with:

| Property    | Description                                                                                              |
| ----------- | -------------------------------------------------------------------------------------------------------- |
| `requestId` | Unique identifier for the API request — useful for debugging in [Lettr logs](https://app.lettr.com/logs) |
| `accepted`  | Number of recipients the API accepted for delivery                                                       |

## Custom Mailable Classes

Create a Mailable that uses Lettr templates:

```php theme={null}
namespace App\Mail;

use Lettr\Laravel\Mail\LettrMailable;
use Illuminate\Mail\Mailables\Envelope;

class OrderConfirmation extends LettrMailable
{
    public function __construct(
        private Order $order
    ) {}

    public function envelope(): Envelope
    {
        return new Envelope(
            subject: "Order #{$this->order->id} Confirmed",
        );
    }

    public function build(): static
    {
        return $this
            ->template('order-confirmation')
            ->substitutionData([
                'order_id' => $this->order->id,
                'customer_name' => $this->order->customer->name,
                'items' => $this->order->items->toArray(),
                'total' => $this->order->total,
            ]);
    }
}
```

Send it like any Laravel Mailable:

```php theme={null}
Mail::to($customer->email)->send(new OrderConfirmation($order));
```

Custom Mailables are the best choice when you send the same template from multiple places in your application. They encapsulate the template slug, merge tag mapping, and subject line in one class, keeping your controllers and jobs clean.

<Tip>
  You can auto-generate Mailable classes from your Lettr templates. See [Mailable Classes](/quickstart/laravel/type-safety#mailable-classes) for details.
</Tip>

### Mailables with Queues

`LettrMailable` classes work with Laravel's queue system. To send asynchronously:

```php theme={null}
Mail::to($customer->email)->queue(new OrderConfirmation($order));
```

Make sure your Mailable class implements `ShouldQueue` and uses the `Queueable` trait, as you would with any standard Laravel Mailable.

## Attachments

Add attachments to your emails:

```php theme={null}
use Lettr\Laravel\Facades\Lettr;
use Lettr\Dto\Attachment;

Lettr::emails()->send(
    Lettr::emails()->create()
        ->from('billing@yourdomain.com')
        ->to(['customer@example.com'])
        ->subject('Your Invoice')
        ->template('invoice-email')
        ->substitutionData(['invoice_number' => 'INV-001'])
        ->attachments([
            new Attachment(
                name: 'invoice.pdf',
                type: 'application/pdf',
                data: base64_encode(file_get_contents($pdfPath))
            ),
        ])
);
```

Attachments must be base64-encoded. The `type` parameter should be a valid MIME type. See [Attachments](/learn/sending/attachments) for supported types and size limits.

## Tracking

Enable open and click tracking:

```php theme={null}
Lettr::emails()->send(
    Lettr::emails()->create()
        ->from('marketing@yourdomain.com')
        ->to(['subscriber@example.com'])
        ->subject('Check out our new features')
        ->html($htmlContent)
        ->withOpenTracking(true)
        ->withClickTracking(true)
);
```

When tracking is enabled, Lettr inserts a tracking pixel for opens and rewrites links for click tracking. You can view tracking data in the [Analytics dashboard](https://app.lettr.com/analytics) or receive events via [webhooks](/learn/webhooks/introduction). See [Tracking](/learn/sending/tracking) for details on how tracking works and privacy considerations.

## Tags

Tags let you group emails for analytics. You can filter and break down metrics by tag in the [Analytics dashboard](/learn/analytics/filtering-and-breakdowns), and the home dashboard shows per-tag Sent, Opened, and Rate stats automatically. See [Tags](/learn/sending/tags) for the full reference.

In most cases you don't need to set a tag yourself — the Laravel package resolves it automatically using this priority:

1. **Explicit tag** — if you call `->tag()` on the Mailable, that value wins.
2. **Template slug** — if you use `->template('slug')`, the server uses the slug as the tag.
3. **Class name** — if neither of the above applies, the package generates a kebab-case tag from the Mailable class name (e.g., `OrderConfirmation` becomes `order-confirmation`).

### Automatic Tag from Lettr Template

When you use `->template('slug')` on a LettrMailable, the server automatically uses the template slug as the tag. No code needed — your analytics are grouped by template out of the box. The Emails page in the dashboard shows Sent, Opened, and Rate per template.

### Automatic Tag from Mailable Class Name

When sending raw HTML (without a Lettr template) through a `LettrMailable`, the package auto-generates a kebab-case tag from the class name. For example, `OrderConfirmation` becomes `order-confirmation`.

### Overriding with Laravel's `tag()` Method

Call `->tag('my-tag')` on any Mailable to override the automatic tag:

```php theme={null}
class WeeklyNewsletter extends LettrMailable
{
    public function build(): static
    {
        return $this
            ->template('newsletter')
            ->tag('welcome'); // overrides the automatic 'newsletter' tag
    }
}
```

If multiple tags are set (via Laravel's `tag()` method), they are joined with `_` into a single string. The combined string must not exceed 64 characters.

### Quick Template Sending

The `sendTemplate` method accepts a `tag` parameter. If omitted, the template slug is used automatically:

```php theme={null}
Mail::lettr()
    ->to('user@example.com')
    ->sendTemplate('welcome-email', 'Welcome!', [
        'name' => 'John',
    ], tag: 'onboarding'); // omit to use 'welcome-email' as the tag
```

### Email Builder

Use `->tag()` on the email builder:

```php theme={null}
Lettr::emails()->send(
    Lettr::emails()->create()
        ->from('marketing@yourdomain.com')
        ->to(['subscriber@example.com'])
        ->subject('Monthly Newsletter')
        ->html($htmlContent)
        ->tag('newsletter-2024-01')
);
```

### Raw HTML via Lettr Facade

When sending raw HTML via the Lettr facade (`sendHtml`, `sendText`), no automatic tag is applied. Set one manually using the email builder with `->tag()`.

### Summary

| Approach                                | Auto Tag                          | Override                  |
| --------------------------------------- | --------------------------------- | ------------------------- |
| LettrMailable with `->template('slug')` | Template slug (server-side)       | `->tag()` on the Mailable |
| LettrMailable with raw HTML             | Mailable class name in kebab-case | `->tag()` on the Mailable |
| Quick `sendTemplate`                    | Template slug (server-side)       | `tag:` parameter          |
| Email builder / Lettr facade            | None                              | `->tag()` on the builder  |

## Testing

Use Laravel's `Mail::fake()` for testing:

```php theme={null}
use Illuminate\Support\Facades\Mail;
use Lettr\Laravel\Mail\InlineLettrMailable;

public function test_welcome_email_is_sent()
{
    Mail::fake();

    // Trigger the email
    $this->post('/register', ['email' => 'user@example.com']);

    Mail::assertSent(InlineLettrMailable::class, function ($mail) {
        return $mail->hasTo('user@example.com');
    });
}
```

`Mail::fake()` intercepts all outbound mail, so no real emails are sent during tests. This works identically to testing any other Laravel mailer.

For custom Mailable classes, assert against the class directly:

```php theme={null}
Mail::assertSent(OrderConfirmation::class, function ($mail) {
    return $mail->hasTo('customer@example.com')
        && $mail->order->id === 42;
});
```

## What's Next

<CardGroup cols={2}>
  <Card title="Templates" icon="file-code" href="/quickstart/laravel/templates">
    Work with Lettr templates, versioning, and projects
  </Card>

  <Card title="Type Safety" icon="shield-check" href="/quickstart/laravel/type-safety">
    Generate enums, DTOs, and Mailables for compile-time safety
  </Card>
</CardGroup>
