Send product email from PHP. Keep retries out of the controller.
Send transactional email and publish lifecycle events from modern PHP applications with the Send & Retain API.
✓Call the HTTP API with your framework client, Guzzle, or any PSR-18 implementation.
One request, complete trace
Request
POST /api/v1/emails
Authorization: Bearer aem_…
Idempotency-Key: welcome-8f21
{ "to": "[email protected]", "template": "welcome" }
202 Accepted
{ "id": "msg_7ca31", "status": "queued" }
[ 01 / 04 ]Client contract
Use familiar PHP clients and a stable JSON contract.
Bring the HTTP client you use
Use Laravel's client, Guzzle, a PSR-18 client, or the standard library. No special runtime is required.
Send typed payloads
Associative arrays or typed DTOs for sender, recipients, template, and props.
Handle delivery events
Use php://input for the raw body so the signature verifies before any framework parsing.
[ 02 / 04 ]Server quickstart
Queue one email from PHP.
Keep the key server-side; the idempotency key makes retries safe.
Use the framework HTTP client and treat the accepted ID as the start of the trace.
$response = Http::withToken(env('AEM_KEY'))
->withHeaders(['Idempotency-Key' => "welcome-{$user->id}"])
->post('https://sendandretain.com/api/v1/emails', [
'to' => $user->email, 'template' => 'welcome',
])->throw()->json();Accepted response
{ "id": "msg_7ca31", "status": "queued" }[ 03 / 04 ]Quickstart
Queue email after the application commits its work.
Configure one server client
Read the API key from environment configuration and set an explicit timeout.
Dispatch after commit
Queue the send from a job or application service after the order, user, or reset record exists.
Log the message ID
Keep the accepted identifier with the job so support can follow the exact delivery timeline.
Production checklist
- Secrets stay server-side
- Timeout and retry policy
- Idempotent webhook handler
- Structured error logging
[ 04 / 04 ]Related
Use PHP in context
Questions people ask us
Queue your first PHP email.
Use your existing HTTP client and keep the returned ID with the job that sent it.