Skip to the content

Transactional

Your application’s e-mails, finally kept

A receipt that does not arrive is a customer who calls. Lekalao sends your applications’ e-mails through your provider, and keeps every one of them in a log.

Try it free

14-day trial. Nothing to pay to start.

Three ways to plug in

The API
One POST: variables, attachments, the language, the provider.
The Laravel transport
MAIL_MAILER=lekalao, and your code does not change.
The SMTP relay
For what only speaks SMTP: an API token is the password. No TLS today, so self-hosted or behind your own terminator.
curl -X POST "$LEKALAO_URL/api/v1/transactional-mails/send" \
  -H "Authorization: Bearer $LEKALAO_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-2026-00481-confirmation" \
  -d '{
    "template": "order-confirmation",
    "to": ["ada@example.com"],
    "locale": "fr",
    "variables": {
      "customer": { "name": "Ada" },
      "order": { "number": "2026-00481", "total": "12 500 FCFA" }
    }
  }'
// config/mail.php
'mailers' => [
    'lekalao' => [
        'transport' => 'lekalao-api',
        'endpoint' => env('LEKALAO_URL'),
        'token' => env('LEKALAO_TOKEN'),
    ],
],

// .env: MAIL_MAILER=lekalao
Mail::to($order->customer)->send(new OrderConfirmed($order));
MAIL_MAILER=smtp
MAIL_HOST=$LEKALAO_SMTP_HOST
MAIL_PORT=2525
MAIL_USERNAME=lekalao
# An API token with the "write" ability
MAIL_PASSWORD=$LEKALAO_TOKEN

The log answers “did they get it?”

Recipients, content, delivery, opens, clicks, and a button to send it again. Statistics per template.

Two streams, two providers

Campaigns through one, invoices through the other. A campaign that draws complaints never spoils the stream that sends your receipts.

Templates marketing can proofread

HTML, Markdown or MJML, one version per language, default recipients. The application sends the variables; the wording is corrected without a deployment.

Webhooks that prove themselves

Subscriptions, departures, tags, bounces, complaints: each call is signed with HMAC-SHA256. The log keeps the answer it received, and an address that fails ten times in a row is switched off.

Verify a webhook

Route::post('/webhooks/lekalao', function (Request $request) {
    $expected = hash_hmac(
        'sha256',
        $request->getContent(),
        config('services.lekalao.webhook_secret'),
    );

    $received = (string) $request->header('X-Lekalao-Signature');

    abort_unless(hash_equals($expected, $received), 401);

    // subscriber.unsubscribed, mail.bounced, campaign.sent…
    return response()->noContent();
});

Everything the interface does, your code does too

The same key never writes twice: an Idempotency-Key returns the first answer for 24 hours. Limits are counted per token, not per address. A thousand subscribers go in one call, with a report per row.

A test refuses any route without a description, and any description without a route.

No SDK, on purpose

Five packages to maintain while the API still moves would cost more than they bring. The OpenAPI specification is right; your generator does the rest. For Laravel, the transport is ready.

How it is built

Laravel, PostgreSQL, Redis. More than 500 automated tests, one of which opens every page with data in it. This site subscribes to its own list through the product’s form.

Fourteen days to see for yourself

Create the account, connect your provider, send your first campaign. Nothing to pay to start.