Queue and Retry Email Delivery in PHP

Last updated: August 29, 2026.

A queue makes requests faster and protects delivery from short provider outages. Store the message intent, let a worker claim it, and distinguish temporary failures from permanent ones.

Calculate bounded backoff

<?php
function nextEmailAttempt(int $attempt): DateTimeImmutable
{
    $seconds = min(3600, 30 * (2 ** min($attempt, 7)));
    return (new DateTimeImmutable())->modify('+' . ($seconds + random_int(0, 15)) . ' seconds');
}

Prevent duplicate sends

  • Claim queue rows transactionally.
  • Give each logical message a unique key.
  • Do not retry invalid recipients indefinitely.
  • Store provider message IDs for webhooks.
  • Apply a retention policy to message data.

Adding automated email to a data-driven application?
PHPRunner supports event-driven email and generated application workflows. Explore PHPRunner.

Define ownership and final states

A worker must claim one queue row atomically so two workers cannot send the same message. Store a logical message key, attempt count, next-attempt time, and provider message ID.

Test worker crashes before and after provider acceptance, then confirm that idempotency prevents duplicates. Permanent errors should move to a failed state instead of retrying forever.

  • Use bounded exponential backoff.
  • Add jitter to spread retries.
  • Retain only necessary message data.

Keep resource limits explicit and make failure cleanup part of the example. Log enough context to diagnose the operation without recording passwords, private message bodies, or uploaded file contents.

Continue with HTTP email API, SMTP with PHPMailer, and delivery troubleshooting.

Practical implementation check

Put the operation in a small function or service with explicit inputs and a clear failure result. Test invalid input, missing extensions, permission failures, and concurrent requests. Production logs should identify the operation and record ID without storing secrets or private content. Clean up partially created files or queue records when any later step fails.

Return a clear result to the caller and keep user-facing messages separate from detailed diagnostics. This makes the same code usable from a web request, command-line job, or queue worker.

Reference: PHP DateTimeImmutable reference.

admin

admin