I originally wrote a guide for Mautic’s knowledge base, but it needs an update. Please use the following file and save it with this exact path and name:
/full_path_to_mautic/var/lock/consume_mautic.sh
Before using it, edit the configuration variables inside the script to match your environment. In particular, you will need to update:
- the sending frequency settings
- the path to your PHP binary
- the path to your Mautic installation
You will also need to create the `lock` directory inside Mautic’s `var` directory if it does not already exist:
/full_path_to_mautic/var/lock/
After saving the file, make it executable from the terminal with:
chmod +x /full_path_to_mautic/var/lock/consume_mautic.sh
Then create a cron job to run it once per minute. For example:
* * * * * /full_path_to_mautic/var/lock/consume_mautic.sh > /dev/null 2>&1
You can change the log output part if you want to store logs instead of discarding them.
What does this file do?
This script replaces the usual `messenger:consume` cron job and gives you much more control over how email sending is processed in Mautic.
With this script, you can:
- limit how many emails are processed per hour
- control the pacing of email processing through delays between runs
- restrict sending to specific days of the week
- restrict sending to specific hours of the day
- prevent overlapping executions by making sure only one worker runs at a time
In other words, it gives you a simple way to throttle email sending and avoid multiple workers running at the same time, which can be useful for controlling server load and keeping delivery behavior more predictable.
The file content starts here:
#!/bin/bash
set -euo pipefail
########################################
USER CONFIG
########################################
PHP_BIN=“/usr/bin/php8.3”
MAUTIC_ROOT=“/full_path_to_mautic”
MAUTIC_BIN=“$MAUTIC_ROOT/bin/console”
LOCK_DIR=“$MAUTIC_ROOT/var/lock”
LOCKFILE=“$LOCK_DIR/consume_mautic.lock”
STATEFILE=“$LOCK_DIR/consume_mautic_hourly.state”
LOCKFILE_TIMEOUT=50
1=Lun … 7=Dom
WORKING_DAYS=(“1” “2” “3” “4” “5” “6”)
Start time, end time
START_HOUR=6
END_HOUR=22
Cadence
INTERVAL=5
PER_BURST=1
HARD_LIMIT=50
Max per hour
HOURLY_LIMIT=500
Consumer limits
TIME_LIMIT=1
MEMORY_LIMIT=“8192M”
########################################
INTERNALS
########################################
mkdir -p “$LOCK_DIR”
current_hour_key() {
date +%Y%m%d%H
}
is_working_day() {
local dow
dow=$(date +%u)
for d in “${WORKING_DAYS[@]}”; do
if [ “$d” = “$dow” ]; then
return 0
fi
done
return 1
}
is_allowed_hour() {
local hour
hour=$(date +%H)
hour=$((10#$hour))
if [ “$hour” -lt “$START_HOUR” ] || [ “$hour” -ge “$END_HOUR” ]; then
return 1
fi
return 0
}
load_state() {
local now_hour
now_hour=$(current_hour_key)
if [ ! -f “$STATEFILE” ]; then
printf “%s|0\n” “$now_hour” > “$STATEFILE”
fi
local state_hour state_count
IFS=‘|’ read -r state_hour state_count < “$STATEFILE” || true
if [ -z “${state_hour:-}” ] || [ -z “${state_count:-}” ]; then
state_hour=“$now_hour”
state_count=0
printf “%s|%s\n” “$state_hour” “$state_count” > “$STATEFILE”
fi
if [ “$state_hour” != “$now_hour” ]; then
state_hour=“$now_hour”
state_count=0
printf “%s|%s\n” “$state_hour” “$state_count” > “$STATEFILE”
fi
STATE_HOUR=“$state_hour”
STATE_COUNT=“$state_count”
}
save_state() {
printf “%s|%s\n” “$STATE_HOUR” “$STATE_COUNT” > “$STATEFILE”
}
########################################
GUARDS
########################################
if ! is_working_day; then
echo “This is not an approved day. Exiting…”
exit 0
fi
if ! is_allowed_hour; then
echo “Outside of authorized time frame (${START_HOUR}:00-${END_HOUR}:00). Exiting…”
exit 0
fi
if [ -e “$LOCKFILE” ]; then
LOCKFILE_AGE=$(( $(date +%s) - $(stat -c %Y “$LOCKFILE”) ))
if [ “$LOCKFILE_AGE” -ge “$LOCKFILE_TIMEOUT” ]; then
echo “Lock > ${LOCKFILE_TIMEOUT}s. Deleting old lock file…”
rm -f “$LOCKFILE”
else
echo “Process already running. Exiting…”
exit 1
fi
fi
touch “$LOCKFILE”
trap ‘rm -f “$LOCKFILE”’ EXIT INT TERM
########################################
MAIN
########################################
load_state
if [ “$STATE_COUNT” -ge “$HOURLY_LIMIT” ]; then
echo “Hourly limit has been reached (${STATE_COUNT}/${HOURLY_LIMIT}) in the hour ${STATE_HOUR}. Exiting…”
exit 0
fi
SENT_REAL=0
START_TS=$(date +%s)
while (( $(date +%s) - START_TS < HARD_LIMIT )); do
load_state
if [ “$STATE_COUNT” -ge “$HOURLY_LIMIT” ]; then
echo “LÃmite horario alcanzado (${STATE_COUNT}/${HOURLY_LIMIT}).”
break
fi
if “$PHP_BIN” “$MAUTIC_BIN” messenger:consume email
–limit=“$PER_BURST”
–time-limit=“$TIME_LIMIT”
–memory-limit=“$MEMORY_LIMIT”
–no-interaction; then
STATE_COUNT=$(( STATE_COUNT + 1 ))
SENT_REAL=$(( SENT_REAL + 1 ))
save_state
echo "Processed: 1 | Hour: $STATE_HOUR | Accumulated on hour: $STATE_COUNT/$HOURLY_LIMIT"
else
echo “Messeger command returned:consume returned error. Exiting…”
break
fi
NOW=$(date +%s)
if (( NOW - START_TS + INTERVAL >= HARD_LIMIT )); then
break
fi
sleep “$INTERVAL”
done
echo “Processed in this run: $SENT_REAL”
exit 0