3

In my web application, when a user makes a change to their account, I call the php mail() function to send that user an email notification. After implementing this, I found that the account change action takes a very large amount of time (>20 seconds) to complete. I suspect that this is because PHP waits for the mail() function to send the email. Is there any way to make this call without waiting and immediately continue to the next line of code?

Thanks,

Paul

Paul
  • 256
  • 4
  • 18
  • You suspect? Have you benchmarked this at all? – MonkeyZeus Feb 21 '14 at 17:36
  • @MonkeyZeus If I comment out the call to the mail function, the server response takes less than three seconds. If I allow it to call the mail function, it takes more than twenty seconds. I think it is safe to say that the mail function is the culprit. – Paul Feb 21 '14 at 17:42
  • Something is wrong. The mail() function shouldn't take that long to execute. You might want to try to figure out why the mail() function is taking that long. Your php.ini file should show you the underlying system command that the mail() function is using. It should be specified as the sendmail_path. If you login to the server and send a message from the command line by way of the command specified as the sendmail_path, does it take ~10 seconds to execute? If so, it sounds like there may be trouble with the MTA running on your server. – mti2935 Feb 21 '14 at 17:48
  • Even 3 seconds, without the `mail()`, is far too much time in the eyes of the average user. Something is going on in your network causing the `mail()` slowdown so that should definitely be resolved but you definitely need to look into optimizing the account update process. I don't know of any way which PHP can spawn separate functions and not wait for them but on the client-side you can certainly implement AJAX. – MonkeyZeus Feb 21 '14 at 17:57
  • @MonkeyZeus The reason for the three second delay is that the action in question is putting a subscription payment through on a credit card. – Paul Feb 21 '14 at 19:23
  • I see, well in that case I definitely recommend using AJAX on the client-side because it will give you the ability to display a `spinner.gif` and disable form-submission so that the user doesn't get antsy and hit `submit` twice. OF course server-side validation should always be present but at least the UX experience will also be nice =) – MonkeyZeus Feb 21 '14 at 19:41
  • @MonkeyZeus I do use AJAX on the client side to submit the form to do this. I just did not want to rely on AJAX to send the email, as was suggested in another answer, for security reasons. – Paul Feb 21 '14 at 23:53

4 Answers4

6

Create another PHP script (we'll call it "mailuser.php" for this example). In this file your code would look for activated accounts that haven't been emailed yet... then send the email.

In your original code (after activating the account) call :

exec("php mailuser.php > /dev/null 2>&1 &");

This should spawn the process, but not wait for it to return.

For more information, see these posts : php exec command (or similar) to not wait for result & Run PHP Task Asynchronously

You could also elect to pass the user id on the command line, so that the mailuser.php doesn't have to look for the users based on a field/flag.

Community
  • 1
  • 1
DragonYen
  • 958
  • 9
  • 22
  • 1
    Worked perfectly, thank you. I'd like to add for anyone that is trying to do this, more information on how to send parameters with the exec command can be found in the php manual: http://php.net/manual/en/reserved.variables.argv.php – Paul Feb 21 '14 at 19:24
0

You could put the call to the mail function in a separate php file called, says, sendMail.php, and then send the request to the function with (jQuery AJAX)[https://api.jquery.com/jQuery.ajax/].

$.ajax({
   type: "POST",
    url: "sendMail.php",
    data: { name: "Foo", email: "foobar@baz.com" }
})
.done(function( msg ) {
    alert( "Email sent: " + msg );
});
larsAnders
  • 3,813
  • 1
  • 15
  • 19
0

You can send Ajax call for sending mail and then for security purposes if the mail is not sent you can call a rollback on database query, this way your code will be secure.

Shashi
  • 474
  • 6
  • 21
0

I had the same issue. Write a sendmail.php program and call it with ajax.

<?
session_start();
header("Content-Type: text/html; charset=iso-8859-1");
require_once("libreria/class.phpmailer.php");
$mail             = new PHPMailer();
$body="";
$body.="<body>";
$body.=$_POST['cbody'];
$body.="</body>";
$mail->IsSMTP();
$mail->SMTPAuth   = true;                  
//$mail->SMTPDebug  = 2;
$mail->Host       = "mail.xxx.xxx";
$mail->Port       = 25;
$mail->Username   = "usermail@xxx.xxx";  
$mail->Password   = "xxxxxx";        
$mail->From       = "usermail@xxx.xxx";
$mail->FromName   = "xxx";
$mail->Subject    = $_POST['subject'];
$mail->WordWrap   = 50;
$mail->MsgHTML($body);
$mail->AddAddress($_POST['email'], "User");
$mail->IsHTML(true);
$mail->Send();
?>

(You can use the response of the ajax call to manage errors).

gtryonp
  • 397
  • 5
  • 13