2

I am developing an ecommerce component.

I have noticed that when the user makes the purchase, the process takes between 18 and 20 seconds, which is quite unacceptable.

Following up the code, I have found that sending emails using Joomla Mailer takes between 1.8 to 2.4 seconds each, and as I have to send several Emails, this explains why the process takes so long.

Is there a way by which we can send emails asynchronous?.

thanks

5
  • This might help you: joomla.stackexchange.com/a/1117/168
    – Lodder
    May 27, 2015 at 9:27
  • I have tried that too. But ultimatly the: $send = $mailer->Send(); command waits for the SMTP server response and takes a lot of time. I really don´t need to wait for the anwser so the best for my is to send the email and continue the procees witout waiting for the smtp. May 27, 2015 at 9:32
  • Maybe if you could find a way to trigger the email sent, after the completion of the purchase.
    – FFrewin
    May 27, 2015 at 10:04
  • Email send function should not take so long unless you are using external SMTP server. If your server has mail server, try using it.
    – Nagarjun
    May 27, 2015 at 13:58
  • @Piero - The answer in the link I provided doesn't result in an asynchronous process, however it will take the strain off your server, so the 3rd party server can process the emails for you.
    – Lodder
    May 27, 2015 at 14:28

3 Answers 3

4

It seems to me that the question you are asking is perhaps not the one you meant to ask (if I may be so bold). I'm assuming that 18-20s response is unacceptable either because it's a poor user experience and/or it's annoying for any admin type work (perhaps undertaken by just you). Your analysis of the problem lying with e-mail dispatch suggests that by significantly altering that will improve the primary symptom - the 18-20s response.

So, perhaps your question should have been "How can I alter the mail dispatch process so that it doesn't block the remainder of the processing?"

The possible answers to that question depend on whether you are self-hosting / virtual-hosting or are using a shared server. With most mail dispatch procedures, mail(s) are submitted to an SMTP server for onward delivery to the final destination(s). Note, I make the distinction between dispatch (what you need to do) and delivery (what the SMTP server(s) do). For a variety of reasons, hosting providers normally recommend you send mail via one or other of their servers - which would normally respond much quicker than the 1.8-2.4s you quote - mail submission should be tens or hundreds of milliseconds only.

If you feel you have the skills, inclination and full server access, then you could implement one of the many available SMTP servers (for *nix systems, Postfix and Exim are good options - for Windows, you could try hMailServer). Then, that local SMTP server would handle your mail submissions, queue them up and then handle the onward delivery asynchronously. But, of course, this comes at the cost of setting up and managing those services (and ensuring you don't inadvertently set up an open mail relay (very bad)).

If you are already using your ISP's mail server (perhaps called a "smart host") and it is taking circa 2s per mail, you should check whether the bulk of that delay is in the PHP handling before submission to the server or whether it really is the server. If you have terminal access to your own server, then you could try telnetting from there to the ISP's mail server on port 25 and seeing if the response time for the banner does take a "long" time (many servers do, either by intention or due to loading). Here's a Microsoft link to how to do such testing: MS Technet article - SMTP telnet testing. If the delay is long, I'd ask the ISP why - if the response is unsatisfactory, you may have to go back to the own-SMTP-server scenario.

Incidentally, I assume you are using BCC to send the mails out, otherwise you can normally submit several e-mail addresses with one body (BCC does one body per recipient so that each one cannot see the others) - if BCC is not required, then this would potentially cut the response time from N x 2s to just 2s, for N recipients. N is limited to about 20, but there are many factors determining that which you would have to investigate in your environment.

If you want to stick with the original question about asynchronous PHP scripting - you might end up going down a complex but ultimately dead-end path. From what you say, I strongly advise making sure your mail submissions are quick and queued in a "fast" SMTP service.

3

You can't run asynchronous PHP processes. What you can do is to try using a queue system. The simplest thing would have a cron job running which checks for mailjobs to be sent. Then your component just has to enter the information into a database table and the cron then picks it up and creates the emails. Depending on how often you run the cron, it obviously means a delay between the order and the email being sent.

1

I agree with @MarkBradley that there is something odd if dispatching emails is taking that long. That said, I had a somewhat related requirement to send a large volume of emails in a single web request (not a bulk mailer as such, but similar behaviour).

I created the following general purpose async command launcher utility for PHP. I'm sure it could do with some polishing, but it serves my purpose at least:

function invokeAsyncCommand($p_command) {

    // Escape any single quotes in the command string before passing to shell
    $command = str_replace("'", "'\"'\"'", $p_command);

    // Launch the command via an authorised user account using the 'at' command
    $command = "echo '$command' | sudo -u somelimiteduser at now ";

    exec($command, $output, $return_var);

    return $return_var;
}

Note the use of sudo there. This is to account for the fact that the web server user account would generally be configured without a shell and so unable to use 'at' or related commands. Also, we don't want to give the web server general shell access, so instead we authorise it to run just that command as another user with limited privileges (discussion here). To do so, add a line similar to the following in your sudoers config (eg. visudo -f /etc/sudoers.d/mysudoers:

www-data        ALL = (somelimiteduser) NOPASSWD:/usr/bin/at

where www-data is the web server user account.

Word of advice: Be absolutely certain the $p_command value supplied here either contains no user-supplied content (ie. is generated entirely within your own code), or is suitably sanitised before use!

Lastly, FWIW, I created a Joomla CLI utility that I invoke via the above function to perform my mass mailing task, so my command invocation was along the lines of:

invokeAsyncCommand(JPATH_BASE . '/cli/mycliutil.php --arg=someval');

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.