A small guide to send mails using doctrine for queue in Mautic 5

This is a small guide to configure doctrine to send the queue. Will be in the kb soon

But since this was a great pain for me for 2 or 3 weeks I want to share it now for any that finds the same issues I did.

I am using CPanel and no docker or any other thing but a simple Linux hosting.

Another thing, this is for Mautic 5, not previous versions.


Detailed Guide: Configuring Mautic for Email Queue Management with Doctrine and Cron Jobs

1. Introduction to the Concept

What is Mautic?
Mautic is an open-source marketing automation platform that enables you to engage with your audience through various channels such as email, SMS, social media, and more. It’s a powerful tool for managing marketing campaigns, segmenting your audience, and tracking engagement.

What is Doctrine?
Doctrine is an Object-Relational Mapper (ORM) for PHP, which is used by Mautic to manage database operations. In the context of this guide, Doctrine also serves as a transport layer for the Symfony Messenger component that Mautic uses to queue and process tasks, such as sending emails.

Why Use a Queue System for Emails?
Sending large volumes of emails directly can overwhelm your server, leading to performance issues or being flagged as spam by recipient email servers. A queue system allows you to process and send emails in smaller, controlled batches, which is more efficient and reduces the likelihood of your emails being marked as spam.

The Importance of Sending Emails in Small Batches
By sending emails in smaller batches, such as 60 emails every 10 minutes, you:

  • Reduce server load: Prevent the server from being overwhelmed by processing too many tasks at once.
  • Improve deliverability: Lower the chance of being marked as spam due to sending large volumes in a short time.
  • Increase reliability: Ensure that your email campaigns are delivered consistently and within acceptable time frames.

Introduction to Lock Files and Their Purpose
A lock file is used to ensure that only one instance of a process runs at a time. This is crucial when dealing with cron jobs that may overlap. By using a lock file, you can prevent multiple instances of the email sending process from running simultaneously, which could cause conflicts or excessive resource consumption.

2. Setting Up Mautic with Doctrine for Email Queues

Option 1: Configuring via local.php File

  1. Step 1: Locate the local.php File
    The local.php file is typically located in the app/config directory of your Mautic installation. This file contains the configuration settings for your Mautic instance.

  2. Step 2: Edit the Configuration File
    To configure Mautic to use Doctrine as the queue transport, you need to edit the local.php file. Add or modify the following settings:

    <?php
    
    return array(
    // Other Mautic configuration settings...
    
    'messenger' => [
    'default_bus' => 'messenger.bus.default',
    'transports' => [
        'doctrine' => [
            'dsn' => 'doctrine://default?table_name=messenger_messages',
        ],
    ],
    ],
    
    // Additional configuration settings...
    );
    
  3. Step 3: Save the File
    After making these changes, save the local.php file. These settings will now be applied the next time Mautic processes a queue.

Option 2: Configuring via Mautic’s Queue Configuration Screen

  1. Step 1: Access the Queue Configuration Screen

    • Log in to your Mautic dashboard.
    • Navigate to Settings by clicking on the gear icon in the top-right corner.
    • Select Queue Settings from the menu.
  2. Step 2: Configure the Queue Settings

    • Select Doctrine as the Queue Transport:
      • In the Queue Transport, type Doctrine. This tells Mautic to use Doctrine for queue management.
      • Configure the following settings:
        • Scheme: doctrine
        • Host: default
        • Table Name: messenger_messages (or any custom table name you prefer)
    • Save the Configuration:
      • Once you’ve entered the correct settings, click the Save & Close button to apply the configuration.

Explanation:
By setting the Queue Transport to Doctrine, you’re instructing Mautic to manage queued emails using Doctrine’s database storage. This allows Mautic to handle email processing more efficiently, especially under heavy loads.

3. Implementing Cron Jobs for Automated Email Sending

Creating the Shell Script

  1. Step 1: Create the Script
    Place the script in a suitable location, such as /path/to/mautic/var/lock/consume_mautic.sh:

    #!/bin/bash
    
    # Path to the lock file
    LOCKFILE="/path/to/mautic/var/lock/consume_mautic.lock"
    
    # Lock file timeout (9 minutes = 540 seconds)
    LOCKFILE_TIMEOUT=540
    
    # Check if the lock file exists
    if [ -e $LOCKFILE ]; then
    # Calculate the age of the lock file
    LOCKFILE_AGE=$(($(date +%s) - $(stat -c %Y $LOCKFILE)))
    
    # Remove the lock file if it is too old
    if [ $LOCKFILE_AGE -ge $LOCKFILE_TIMEOUT ]; then
        echo "Lock file is older than $LOCKFILE_TIMEOUT seconds. Removing..."
        rm -f $LOCKFILE
    else
        echo "Process is already running. Exiting..."
        exit 1
    fi
    fi
    
    # Create the lock file
    touch $LOCKFILE
    
    # Run the messenger:consume command for emails
    /usr/bin/php /path/to/mautic/bin/console messenger:consume email --limit=60 --time-limit=480 --memory-limit=128M
    
    # Remove the lock file when done
    rm -f $LOCKFILE
    
    exit 0
    
  2. Step 2: Make the Script Executable
    Give the script execute permissions:

    chmod +x /path/to/mautic/var/lock/consume_mautic.sh
    

Configuring the Cron Job

  1. Step 1: Open the Crontab
    Use the following command to edit your crontab:

    crontab -e
    
  2. Step 2: Add the Cron Job
    Add the following line to your crontab:

    */10 * * * * /path/to/mautic/var/lock/consume_mautic.sh >> /path/to/mautic/var/logs/mautic_consume.log 2>&1
    

    This will run the script every 10 minutes and log the output to mautic_consume.log.

Setting Up Directories and Permissions

  1. Step 1: Create Directories
    Ensure that the necessary directories exist and have the correct permissions:

    mkdir -p /path/to/mautic/var/lock
    mkdir -p /path/to/mautic/var/logs
    
  2. Step 2: Check Permissions
    Make sure that the user running the cron job has the necessary permissions to read/write in these directories.

Testing the Setup

  1. Step 1: Run the Script Manually
    You can run the script manually to ensure it works as expected:

    /path/to/mautic/var/lock/consume_mautic.sh
    
  2. Step 2: Check the Logs
    Review the log file to ensure that the emails are being processed:

    tail -f /path/to/mautic/var/logs/mautic_consume.log
    

4. Monitoring and Troubleshooting

How to Monitor Logs
Regularly check the log file (mautic_consume.log) to monitor the performance of the email queue and troubleshoot any issues that arise.

Common Issues and Solutions

  • Lock File Not Being Removed: Ensure that the script is properly configured to remove the lock file after processing. If the lock file remains, it could prevent future executions.
  • Emails Not Sending: If emails are not being sent, check the configuration of your SMTP server and ensure that the Mautic email settings are correctly configured.
7 Likes

Screenshot of cofngiruing in the web frontend:

There is also Queue settings in the docs.

is the bin/console mautic:messages:send cronjob still required after enabling the queue?

I don’t see such an option in the Queue Settings :frowning:

Good point, that’s an error, will rewrite that part.
It’s only cog > configuration > queue settings
The fill Scheme with “doctrine” and Host with “default”

I have it exactly like that but it doesn’t seem to work…

No, you have to remove that cron. The only cron needed is the one that will trigger this new file you are creating.

BTW this is only for mautic 5

you created your file with your files location in it, chmod it and then tested running it and it don’t work?

Testing it in the terminal should give you this

I just saw that the emails are correctly being processed by php /var/www/html/bin/console mautic:broadcasts:send. They get marked as sent but they never actually do get sent…

I see exactly what your showing here BTW.

What I couldn’t find is this config option:

So as far as I can see, the message queue is always empty… I don’t understand why…

Have to read more times after asking chatgpt to make my writing style better.
The idea is just to write doctrine and default

I just saw that the emails are correctly being processed by php /var/www/html/bin/console mautic:broadcasts:send. They get marked as sent but they never actually do get sent…

This part you are talking about puzzles me. That is something that Mautic is programmed to do.

Have you set up your email account in configuration > email settings?

I just realized I didn’t have MESSENGER_TRANSPORT=doctrine://default in my .env.

I added that and things seem to be moving forward. I saw some movement inside the messenger_messages table but no emails sent yet :frowning:

Well… I think I kind of figured it out. At least I saw some emails being sent :slight_smile:

I was going a little crazy so I updated my local dev environment to use my gmail credentials and tried to replicate the scenario and guess what… it worked!

So I went ahead to see what was going on in prod. I disabled the cronjobs to run everything manually.

First I noticed that when I run php /var/www/html/bin/console mautic:broadcasts:send --limit=50 --batch=20 I got 50 new messages inside the messenger_messages table.

But then I noticed something unusual: the messages would disappear after a couple of seconds without me running any new command.

This had me puzzled for a while but then I thought, since the cronjobs are stopped, there must be another consumer somewhere around…

I took a closer look at the docker-compose.yml definition and noticed I have two separate services: mautic_cron and mautic_worker (I got this from an example found here) but I’m not sure I actually need both of them.

That’s something I still need to figure out.

Anyway, once I stopped the mautic_worker the messages stopped disappearing magically. Bingo!

I’m still not sure why those messages consumed by the worker wouldn’t get sent but hey… things look good :wink:

Thanks for your support and I hope my story helps others.

1 Like

Will test that to add it to the guide

1 Like

the containerized mautic uses a container that just runs “messenger:consume” for email, hit and failed. This is the supervisor config used: docker-mautic/common/supervisord.conf at 084bcee5cc963379a8c519fe2fad4df8eeb37615 · mautic/docker-mautic · GitHub

The cron container creates this cronjobs if the file doesnt exist yet: docker-mautic/common/entrypoint_mautic_cron.sh at 084bcee5cc963379a8c519fe2fad4df8eeb37615 · mautic/docker-mautic · GitHub

It configures the doctrine queue for email and hit by env: docker-mautic/examples/basic/.mautic_env at 084bcee5cc963379a8c519fe2fad4df8eeb37615 · mautic/docker-mautic · GitHub

Can’t give an opinion on that because I don’t use that. This is for simple installations.
My case is on CPANEL using Softaculous, and for that I needed a different approach, so did this guide that is working for me.

It can be refined or corrected by the ones that know mautic more than me, but for now, after 3 weeks from migrating from Mautic 4 to 5, I can send emails again.

1 Like

We will need to further extend the script, as most mail services are rate limited.

Very often AWS SES limits e.g. to 14 mails/sec and just starts to drop anything above that limit. Sending via API its very likely to hit that limit.

I’m right now still testing - with my script, that records the time for sending X (=14) mails and calculates how long to wait until the next 14 mails can go.

I fill the queue up to 800 mails per cronjob in this example, thats why it will take up to 60 cycles (1 sec.) by 14 mails to send them. You can define the batch for all the calls - size them as you like them.

Have a look here - comments and feedback is welcome!

https://twentyzen.com/en/think/faq-items/mautic-v5-cron-job-with-rate-limit-for-mail-sending/

That script also runs the important mautic tasks in sequence, so no need to run them one by one, with a cronjob for each - one will be enough to trigger the whole script. You can run it every minute… if you have a fast enough server.

But in my example, the maximum amount of mails to be send in 1 min is 840 mails. Given that you have other jobs to run as well, 1 minute may often be to close to start the next round.

It has some locking, so it doesn’t start the next one until the one before is finished.

Well that sounds interesting.
I have no big issues because is my own dedicated server and have 1 IP por domain.

But your point is very valuable. Maybe we can do a symfony middleware to delay the sending of each message. I guess it can be also achieved by a plugin and apart from the delay per message (like 1 second delay per message) that can also prevent sending like too many emails form the same delay in the same period of time, like only 1 gmail recipent each 10 seconds.

It sounds plausible and would run in parallel on how the messages are sent (the guide I made for example).