Problems, need help? Have a tip or advice? Post it here.
5 posts Page 1 of 1
Hi

In our CouchCMS based application we send a lot of mails via phpMailer. Sending mails consumes a lot of time in the GUI.

I'd like to have a alternative 'send_mail' tag, e.g. 'send_mail_buffer' that has the same params as send_mail (additionally a param for the folder to write the file to), but writes all the data needed to send the mail into a json file on the server in the following format:
Code: Select all
{
   "timestamp":"2022-03-22 11:38:54",
   "from":"sender@mail.com",
   "to":"receiver@mail.com",
   "cc":null,
   "bcc":null,
   "subject":"Subject of the email",
   "html":1,
   "message":"<html>....html content...</html>",
   "mailserver":null
}

Then, later, a cron job would call a CouchCMS template that performs the following:
Code: Select all
<cms:each files as='file'>
   <cms:capture into='mail' is_json='1'>
      <cms:embed "../logs/mail-buffer/<cms:show file />"/>
   </cms:capture>
   <cms:if (mail.from) && (mail.to) && (mail.subject) && (mail.message)>
      <cms:send_mail from=mail.from to=mail.to cc=mail.cc bcc=mail.bcc html=mail.html subject=mail.subject>
         <cms:show mail.message />
      </cms:send_mail>
   </cms:if>
   <cms:php>
      $dir = $_SERVER['DOCUMENT_ROOT'].'/logs/';
      unlink($dir."<cms:show file />");
   </cms:php>
</cms:each>

Can anybody give me a hint how to implement this via adding a tag in kfunctions.php and using the multi value variables from couch?

Regards,
Oliver
In our CouchCMS based application we send a lot of mails via phpMailer. Sending mails consumes a lot of time in the GUI.

1. Oliver, the emboldened part is not very clear – how a submitted form consumes time.


writes all the data needed to send the mail into a json file

2. If the task was that simple, you'd use Tweakus-Dilectus » write tag. Illustrated JSON has user-provided params that can be written to disk instead of passing them to send_mail tag.

- - -

Let me share details about my experiments with time-consuming intensive tasks. New thoughts may cross your mind and inspire the solution. First, 'paginated' approach is possible without frontend, by passing query string params to a page. I wrote a few pieces on that in my repo (see Cms-Fu » Routines). Second, if you look at KK's couch/addons/mosaic/gc/gc.php there is a "fork" approach (function 'check_and_fork'). Forking means the form is submitted and user may go about his business and navigate to other pages, while the initial code is still running in a continued process in background, detached from the frontend.
Thanks for the idea. I finally got it to work with an additional tag send_mail_buffer. Code see here:
Code: Select all
<?php

   $FUNCS->register_tag( 'send_mail_buffer', 'my_new_tag_send_mail_buffer' );
   function my_new_tag_send_mail_buffer( $params, $node ){
      global $FUNCS;

      extract( $FUNCS->get_named_vars(
         array(
            'from'=>'',
            'to'=>'',
            'cc'=>'',
            'bcc'=>'',
            'html'=>'',
            'subject'=>'',
            'path'=>'',
            'attachment'=>'',
         ),
         $params)
      );

      $filename=date('Y-m-d_His', strtotime('now')).'_'.bin2hex(random_bytes(3)).'.json';

      $path = trim( $path );
      if( !$path ){
         $path = 'logs/mail-log-buffer/';
      }

      $file = K_SITE_DIR . $path . $filename;

      $content='';
      foreach( $node->children as $child ){
         $content .= $child->get_HTML();
      }
      $content=trim($content);
      $attachment=trim($attachment);

      $dirname = dirname($file);
      if (!is_dir($dirname)){
         mkdir($dirname, 0755, true);
      }

      $json = array();
      $json['timestamp'] = date('Y-m-d H:i:s', strtotime('now'));
      $json['from'] = $from;
      $json['to'] = $to;
      $json['cc'] = $cc;
      $json['bcc'] = $bcc;
      $json['subject'] = $subject;
      $json['html'] = $html;
      $json['message'] = $content;
      $json['attachment'] = $attachment;
      $json['status'] = 'Buffer';
      $json['mailserver'] = NULL;

      $fp = @fopen( $file,'a' );
      if( $fp ){
         @flock( $fp, LOCK_EX );
         ftruncate( $fp, 0 );
         rewind( $fp );
         @fwrite( $fp, json_encode($json) );
         @flock( $fp, LOCK_UN );
         @fclose( $fp );
      }
      return;
   }


This allows me to send the mails later with a cronjob or manually by loading a script:
Code: Select all
<cms:each files as='file'>
   <cms:capture into='mail' is_json='1'>
      <cms:embed "../logs/<cms:show file />"/>
   </cms:capture>
   <cms:if (mail.from) && (mail.to) && (mail.subject) && (mail.message)>
      <cms:send_mail from=mail.from to=mail.to cc=mail.cc bcc=mail.bcc html=mail.html subject=mail.subject><cms:show mail.message /><cms:if mail.attachment><cms:each mail.attachment><cms:attachment file="<cms:php>echo explode('=', '<cms:show item />')[1];</cms:php>" name="<cms:php>echo explode('=', '<cms:show item />')[0];</cms:php>" /></cms:each></cms:if></cms:send_mail>
   </cms:if>
</cms:each>

Regards,
Olliwalli
@olliwalli, great solution!

I wonder if it'd be possible for you to share the complete cron template with us?
Should be immensely useful for someone requiring something similar.

Thanks.
@olliwalli, you are welcome

@all, notice that following original parameters are not used in Oliver's solution: reply_to, sender, charset, debug, logfile. Copy-paste with attention ☺

@KK, If 'cms:send_mail' had a token parameter, it'd be nice! A token may be used in custom functions to put mail in a buffer file (what Oliver is showing us done in a different way), choose alternative mailserver config etc.
5 posts Page 1 of 1
cron