# Sending from Laravel

> Send email through Reggio Digital from a Laravel application, either through the API or by pointing Laravel's own mailer at our SMTP service.

Source: https://reggiodigital.com/developers/guides/laravel

A Laravel application can send through us in two ways. Pick the one that fits the code you already have.

- **Over SMTP**, if the application already sends with `Mail::to()` and Mailables. Nothing in your code changes: you point Laravel's own mailer at us in `.env`.
- **Through the API**, if you want what SMTP cannot give you: a message id back straight away, scheduling, batches, saved templates, and a [lookup](https://reggiodigital.com/developers/email#checking-what-happened) for every message.

Both send from the business's own verified domain, count toward the same monthly allowance, and show up on the account's [Sent page](https://reggiodigital.com/email/sent). Plenty of applications use both: SMTP for the framework's own mail, such as password resets, and the API for receipts they want to track.

## Before you start

The from address has to be on a sending domain the account has verified. If the business has not added one yet, they do it under [Sending domains](https://reggiodigital.com/domains/sending), and the dashboard lists the DNS records and checks them. See [the DNS a sending domain needs](https://reggiodigital.com/developers/smtp#the-dns-a-sending-domain-needs).

## Over SMTP

Open the domain under [Sending domains](https://reggiodigital.com/domains/sending) and choose to connect an app. Copy the host, username and password from that page into your `.env`:

```dotenv
MAIL_MAILER=smtp
MAIL_SCHEME=smtp
MAIL_HOST=YOUR_SMTP_HOST
MAIL_PORT=587
MAIL_USERNAME=YOUR_SMTP_USERNAME
MAIL_PASSWORD=YOUR_SMTP_PASSWORD
MAIL_FROM_ADDRESS=hello@yourdomain.com
MAIL_FROM_NAME="${APP_NAME}"
```

Port `587` with `MAIL_SCHEME=smtp` connects in plain text and upgrades to an encrypted connection before anything is sent, which is what our service expects. Do not set `MAIL_SCHEME=smtps`: that expects encryption from the first byte and the connection will hang until it times out.

Older applications may still have `MAIL_ENCRYPTION=tls` in their `.env` and an `encryption` key in `config/mail.php`. Recent versions of Laravel ignore both, so leaving them does no harm, but `MAIL_SCHEME` is the setting that counts.

Then send the way you already do, with `Mail::to()` and your Mailables. Run `php artisan config:clear` after changing `.env` on a server that caches its config, or the old mailer keeps being used.

The credentials send as any address on the domain they were issued for and nothing else. `MAIL_FROM_ADDRESS`, and any `from()` in a Mailable, has to be on that domain.

## Through the API

Get a key from [Connected apps](https://reggiodigital.com/email/api/keys) with the `email:send` ability. Keep it in `.env` and read it through a config file rather than calling `env()` in your code, so it still works once the config is cached:

.env:

```dotenv
REGGIO_API_KEY=rgo_your_key_here
```

config/services.php:

```php
return [

    'reggio' => [
        'key' => env('REGGIO_API_KEY'),
    ],

];
```

Sending is then one call with Laravel's HTTP client:

```php
use Illuminate\Support\Facades\Http;

$response = Http::withToken(config('services.reggio.key'))
    ->acceptJson()
    ->post('https://reggiodigital.com/api/v1/emails', [
        'from' => 'hello@yourdomain.com',
        'to' => [
            'success@simulator.amazonses.com',
        ],
        'subject' => 'Your receipt',
        'html' => '<p>Thanks for your order.</p>',
        'text' => 'Thanks for your order.',
        'tags' => [
            'kind' => 'receipt',
            'order' => '1042',
        ],
    ]);

if ($response->failed()) {
    throw new RuntimeException($response->json('error.message'));
}

$body = $response->json();
```

A `202` with an `id` means we accepted it. Store the id if you want to look the message up later or match it against a [webhook](https://reggiodigital.com/developers/webhooks). Anything else carries an [error](https://reggiodigital.com/developers/conventions#errors) whose `type` says what to do next.

Sending from a queued job keeps a slow network call out of the request. If a job can be retried, send an [Idempotency-Key](https://reggiodigital.com/developers/conventions#idempotency) so a retry after a timeout never sends the message twice:

```php
use Illuminate\Support\Facades\Http;

$response = Http::withToken(config('services.reggio.key'))
    ->acceptJson()
    ->withHeaders([
        'Idempotency-Key' => 'receipt-1042',
    ])
    ->post('https://reggiodigital.com/api/v1/emails', [
        'from' => 'hello@yourdomain.com',
        'to' => [
            'success@simulator.amazonses.com',
        ],
        'subject' => 'Your receipt',
        'html' => '<p>Thanks for your order.</p>',
        'text' => 'Thanks for your order.',
        'tags' => [
            'kind' => 'receipt',
            'order' => '1042',
        ],
    ]);

if ($response->failed()) {
    throw new RuntimeException($response->json('error.message'));
}

$body = $response->json();
```

## Testing without emailing anyone

Send to the [test addresses](https://reggiodigital.com/developers/email#testing-without-emailing-anyone). They work over SMTP and the API alike, produce a real delivery, bounce or complaint, and never reach an inbox.
