With a template
The cleanest way: the content lives in Lekalao, the application sends only the data. Create a template namedorder-confirmation (Transactional templates), then:
Without a template
Send the HTML as it is:The fields
Every address counts against the month’s allowance, copies included: an e-mail to one person in
to and two in cc counts three. A transactional e-mail is written to someone, not broadcast: more than 50 addresses answer 422 too_many_recipients.
In several languages
A template can have one version per language (Languages).locale picks it:
Pass your customer’s language as your application knows it: Lekalao falls back on its own.
The answer
The call is answered as soon as the e-mail is written down. It leaves from a queue a moment later.
A refusal is an error like any other —
message, code, doc_url — with the logged e-mail under data when there is one:
429 Too Many Requests
202 Accepted
201 and 202 the same way: Lekalao has the e-mail. Keep its id; status tells whether it has left yet.
Addresses on the suppression list are left out of to, cc and bcc without an error. The e-mail goes to the others, and fails only when no to is left.
Then, on the queue
Lekalao hands the e-mail to the provider. When the provider fails (a timeout, an error, a refusal), Lekalao tries again after 5 seconds, then 30 seconds, 2 minutes, 10 minutes and 30 minutes. It gives up after the sixth failed attempt, and in any case six hours after the call.status then becomes failed, with failure_code: provider_error and the provider’s last error in failure_reason.
An e-mail whose job was lost on the way — a worker stopped, a queue emptied — is not left pending for ever: seven hours after the call, it becomes failed with failure_code: lost. Its content may not have been kept, so it is not sent again behind your back: send it again yourself.
Transactional e-mails have a queue of their own: they never wait behind a campaign. The mailer’s rate limit still applies.
Follow it with webhooks
Rather than read the e-mail again and again, let Lekalao tell you. Subscribe an endpoint to thetransactional.* events (Webhooks):
Each one carries the e-mail as the API shows it: store its
id with your order, and match on it.
sent means the provider has it, not that it arrived. delivered_at is set when the provider reports a delivery, bounced_at when the address bounced for good, complained_at when a reader reported it as spam; status stays sent, and after a bounce failure_reason takes the provider’s reason. The address goes on the suppression list after a hard bounce or a complaint: the next e-mail to it will not leave. The same news also reaches mail.bounced and mail.complaint, with transactional_mail set to the e-mail’s id.
Or read it again
Without an endpoint, read the e-mail withGET /v1/transactional-mails/{id} until status is no longer pending. The token needs Read, which a Read and write token has.
When the call itself fails
A timeout or a5xx leaves you not knowing whether Lekalao has the e-mail. Send the same call again with the same Idempotency-Key:
- if Lekalao answered the first time, you get that first answer back, with
Idempotent-Replay: true, and no second e-mail leaves. It is the answer as it was then,pendingincluded: read the e-mail to know where it stands now. A422or a429is kept too: the same key gives the same refusal; - a
502is not kept, so the same key sends again.
Follow and send again
A resend takes the same recipients, variables, language, subject and sender address (
from_email), and the same provider. It does not take the attachments, which are never kept, nor a from_name or reply_to given in the first call: the template’s, or the team’s, are used. A test e-mail sent again stays a test e-mail.
Without sending anything
A test key sends nothing: the e-mail is checked, rendered and logged, markedsent with "sandbox": true, and counted against nothing. Written to delivered@sink.lekalao.dev, bounced@sink.lekalao.dev and their siblings, it gets the provider’s answer and its webhooks, to try your handlers end to end.
Other roads
- A Laravel application can keep
Mail::to()->send(): see Laravel transport. - Software that only speaks SMTP: see SMTP relay.