Queue emails to send in background

Created on 11 May 2022, over 2 years ago
Updated 17 October 2023, about 1 year ago

Sites may wish to send emails in a background process - especially for high traffic sites that can send a lot of emails on individual page requests. Similar to existing module Queue mail โ†’ .

Symfony Mailer library already has support for Sending Messages Async so we may be able to use that.

We could create an Email Adjuster that sends messages async.

Original issue Summary

PHP 8.0.17
D 9.3.12
Symfony mailer module is running
Queue mail installed via composer.

Also see this post โœจ Support Symfony Mailer module Active

Mail are sent via SMTP correctly but they are not queued by Queue mail

Uninstall Symfony mailer and queing works smoothly.

I am pleased with Symfony Mailer for SMTP+HTML but I need queing. What could be the way ?
Thanks in advance for help

EDIT: Some more testing
If I uninstall Symfony Mailer Back-compatibility emails are correctly queued but they are send in text mode (not HTML)

โœจ Feature request
Status

Closed: duplicate

Version

1.0

Component

Miscellaneous

Created by

๐Ÿ‡ซ๐Ÿ‡ทFrance gilbertdelyon

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • ๐Ÿ‡จ๐Ÿ‡ญSwitzerland ayalon

    @gilbertdelyon
    You created a lot of threads and issues on Drupal.org regarding this topic. Several module maintainers helped you.

    Unfortunately, you did not share your solution and the code of your custom module which could help others. This is a bit sad.

    Maybe you can rethink this and share your code?

    Thanks in advance.

  • ๐Ÿ‡ฎ๐Ÿ‡ณIndia agudivad

    @gilbertdelyon,

    It is good to know that you are able to achieve it with custom module. Request you to help us by sharing it.

    Regards
    Ajaykumar Gudivada

  • ๐Ÿ‡ซ๐Ÿ‡ทFrance gilbertdelyon

    Sorry, I am only a poor old (very old!) part time hobyist self made developper and I did not have in mind that my poor skills could help confirmed coders!
    In addition I have been very busy these monthes without any time for Drupal.
    So, let me explain how it works in my very humble module:
    Please notice that this custom module is taylor made for my needs, so you will see hereunder only some abstracts in regard with mailing:

    1 - Queueing:
    Drupal queing is very simple to use (you only have to google a bit!):
    Somewhere in your code you will prepare the data that will be used for your mailng and then, thanks to the above function you will queue this data. Then it will be used at next CRON .

    /**
      * Somewhere in you module
      * for example in a custom service
      *
      */
     
      /**
       * Queueing function
       * $notifdata is an array that will include all the resqted stuff for mail processing (subject, content, to, from,...)
       * Each item of the array is for ONE email
       *
       */  
      protected function queueing($notifdata){ 
      
            $queue = \Drupal::queue('my_queue_name');
            $queue->createQueue();             
    
    	foreach ($notifdata as $item => $value){
    		$queue->createItem($value); //One queue item per email
    	}//end foreach
            
        }//end function
    

    Cannot be more simple!

    2 - Unqueueing:
    Unqueing can be made in different ways:
    - Old fashion by way of a hook_cron() function
    - New fashion by way of a queueWorker.
    As I am an old guy I will use the old fashion.

    So, here is the hook_cron() function in my_module.module file

    /**
     * Implements hook_cron()
     * This function will send email at each crom
     * 
     */
    
    function mycustommodule_cron() {
    
         //My queue
          $myqueue = \Drupal::queue('my_queue_name');
          
          // Number of queue items to be sent at each cron 
          // (You have to set this value somewhere in you module config)
          $nbitems = mycustommodule_settings()["maxiItemsPerCron"];
          
          //Items processing
          for ($i=0; $i<($nbitems); $i++){
           
            // Test if items  to be processed from the queue
            // $queue->claimItem() returns only one item from the queue
            if ($queue_item =  $myqueue->claimItem()) {
                    
                //Extract data from item
                $notifdata = $queue_item->data;
                
                //Send Email (using a custom service )
                $notif = \Drupal::service('my_custom_service');
                $sendnotif = $notif->sendnotif2users($notifdata); // sendnotif2users() method is now trigered
                //Delete item if success
                if($sendnotif){
                     $myqueue->deleteItem($queue_item);
                }//fin if
    
            }//fin if
          
        }//fin for
    }//end function
    

    3 - Sending the emails
    In my custom module, heach time an item will be unqueued in hook_cron() the sendnotif2users() method (from my_custom_service) will be triggered.
    You can also simply use a function. IMHO services is the best way.

    /**
     * In my_custom_service file
     *
     */
    namespace Drupal\node2notifs\NotifServices;
    
    use Drupal\Core;
    
    //Complรฉments pour envoi mails avec SymfonyMailer
    use Symfony\Component\Mailer\Transport;
    use Symfony\Component\Mailer\Mailer;
    use Symfony\Component\Mime\Email;
    
    /**
     * This function will mainly process the email content  and trigger the sending process (one email per target adress)
     *
     */ 
     
     public function sendnotif2users($notifdata) { 
                    
    	// Prossessing the email content
    	$this->mailcontents($notifdata); // mailcontents() to be coded as as per your needs
                    
            // Targets
    	$targets = ["name1@domain1","name2@domain2","name3@domain3","name4@domain4", ];// array of all target email adresses
                   
            //Sending loop
            foreach($targets as $item => $to){
    
                  $this->to = $to;
                  $this->sendEmail();//here we send an email only ONE email 
    				   
            }//fin foreach
                    
             return TRUE;  //This will allow queue item delete in  hook_cron()
                   
     }//fin public  function
    

    4 - And finally the mail is sent via SymfonyMailer
    Of course you have to install Symfony Mailer and use the relative classes in your service (see heareabove)

     /**
     * This function will send the email with help of SymfonyMailer
     *
     */
     
     public function sendEmail() {
    
            $email = (new Email())
                ->from( \Drupal::config('system.site')->get('mail'))
                ->to($this->to)
                //->cc('cc@example.com')
                //->bcc('bcc@example.com')
                //->replyTo('replyto@example.com')
                //->priority(Email::PRIORITY_HIGH)
                ->subject($this->subject)
                ->text( $this->plaintextbodybuilder() )
                ->html( $this->htmlbodybuilder() );
    
            $transport = Transport::fromDsn('sendmail://default');
            $mailer = new Mailer($transport);
            $mailer->send($email);
    
        }//fin function
    

    Please forgive some possible mistakes, I am only a poor hobbyist.
    I hope this can help

  • ๐Ÿ‡ฎ๐Ÿ‡ณIndia agudivad

    Thank you so much! @gilbertdelyon for sharing these details.

  • ๐Ÿ‡ฆ๐Ÿ‡บAustralia dpi Perth, Australia

    Symfony Mailer has inbuilt support for Messenger with precisely this feature: https://symfony.com/doc/current/mailer.html#sending-messages-async

    I'm presently working on Symfony Messenger integration, which is effectively Emails to Queues suggested by this issue.

    See โœจ Add Symfony Messenger support for async messsages (emails as queues) Active

    As of this writing, Messenger integration is in active development; not ready for public consumption yet. Though it works great locally!

  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom adamps

    Great thanks @dpi. We now have two issues for the same thing, so let's close one as a duplicate.

  • Status changed to Closed: duplicate about 1 year ago
  • ๐Ÿ‡ฆ๐Ÿ‡บAustralia dpi Perth, Australia

    Despite this issue being older I'm going to close as a dupe as suggested.

    I think the solution is different enough to support this.

    I think there could ultimately be multiple solutions implemented. If a different proposal and solution is devised then this issue could be reopened.

  • ๐Ÿ‡ซ๐Ÿ‡ทFrance gilbertdelyon

    #13 โœจ Queue emails to send in background Closed: duplicate
    Sounds good. I am impatiently waiting for the next release!

  • ๐Ÿ‡ฆ๐Ÿ‡บAustralia dpi Perth, Australia

    The messenger code is now public. Have at it.

Production build 0.71.5 2024