Skip to content
Skip to the article
In Linux: 9 articles
Linux

Release Stuck Messages in the Postal Mail Server Queue

Clear stale locks and retry delays on Postal's queued_messages table so stuck outbound mail is picked up and delivered again.

Updated
Applies to
  • Postal v3
Tags
  • postal
  • email
  • mariadb
  • troubleshooting
Reading time
2 min

Postal workers lock each outbound message while they process it. If a worker crashes or the server restarts mid-delivery, messages can stay locked or keep waiting on a long retry delay, so the queue stops draining. Releasing the locks puts those messages back in front of the workers.

Warning

Postal treats a lock older than queued_message_lock_stale_days (one day by default) as stale and removes the message without retrying it. Release stuck messages promptly, within that window, or they'll be dropped.

1. Check the Queue

Connect to Postal's main MariaDB database (named postal by default; see main_db in postal.yml) and look at what's waiting:

SELECT COUNT(*) AS queued,
       SUM(locked_by IS NOT NULL) AS locked,
       SUM(retry_after > NOW()) AS waiting_to_retry
FROM queued_messages;

To see the oldest locks:

SELECT id, domain, locked_by, locked_at, retry_after, attempts
FROM queued_messages
WHERE locked_by IS NOT NULL
ORDER BY locked_at
LIMIT 20;

2. Stop the Workers

Stop Postal's worker processes so no message is being processed when you clear its lock. Otherwise a message could be delivered twice. With the standard Docker-based install:

postal stop

3. Release the Locks

Clear the lock and retry fields on every queued message:

UPDATE queued_messages
SET locked_by = NULL,
    locked_at = NULL,
    retry_after = NULL;

To release only some messages, add a WHERE clause, for example WHERE domain = 'example.com' or WHERE locked_at < NOW() - INTERVAL 1 HOUR.

4. Start Postal Again

postal start
postal logs worker

Watch the worker logs to confirm the messages are being sent. If they lock up again straight away, the underlying cause (DNS, the remote server refusing connections, or an IP blocklisting) is still there, and the message's delivery log in the Postal web interface usually shows it.

From the Rails Console

The same release can be done through Postal's application console instead of raw SQL:

postal console
QueuedMessage.update_all(locked_by: nil, locked_at: nil, retry_after: nil)

Sources

This article is in the public domain (CC0 1.0), code samples included. Use it however helps you.