views:

206

answers:

6

I am writing a function to send a mail to specific user?

What I am trying to do is, if error occurs I want to keep on sending the mail until the mail is sent.

    function sendmail() {
        $name = mysql_escape_string($name);
        $email = mysql_escape_string($email);
        $phone = mysql_escape_string($phone);
        $content = nl2br(mysql_escape_string($content));
        $subject = "mail from ".$name." (".$email.", Ph: ".$phone.")";
        $mail = @mail($feedback,$subject,$content,$headers);
        if($mail) { echo "Your mailis send"; }
        else { echo "We are sorry for the inconvienience, but we could not send your mailnow."; }
}   

the above function displays error message but instead of giving the error, I want to try to send the mail until the mail is finally sent.

A: 
function sendmail() {
        $name = mysql_escape_string($name);
        $email = mysql_escape_string($email);
        $phone = mysql_escape_string($phone);
        $content = nl2br(mysql_escape_string($content));
        $subject = "mail from ".$name." (".$email.", Ph: ".$phone.")";

        $retries = 0;
        while (!@mail($feedback,$subject,$content,$headers))
        {
            $retries++;

            if ($retries >= MAX_RETRIES)
            {
                break;
            }

            sleep(WAITING_PERIOD);
        }

        if ($retries < MAX_RETRIES) { echo "Your mail has been sent."; }
        else { echo "We are sorry for the inconvienience, but we could not send your mail now." ; }
}

Set WAITING_PERIOD and MAX_RETRIES to something that works for you, just don't set MAX_RETRIES too long or you may get stuck for a long wait, nor set WAITING_PERIOD too low, or you may flood your mail agent.

Francisco Soto
Probably worth putting some kind of delay or sleep into the function, and setting a maximum retry limit.
Neil Aitken
That's just not a practical real world answer, you wouldn't want any server to run this code under any condition
Ben
I changed it a bit to reflect real world code.
Francisco Soto
better.. won't work if you don't use set_time_limit though, it'll eventually die after the default execution time
Ben
+2  A: 

You realize that if your mail server is out of business for more than 30 second it will just exhaust the time it has (which usually is 30 seconds) with that while loop?

The error is a better way probably, it will not wait to re-send it will just send over and over, possibly 782428424 times before those 30 seconds are over, wasting bandwith and probabl annoying some people in the processor.

What you would better do is on failure write the contents to some database which you flush and try to send every 5 minutes or so until success.

Lajla
All the people in my processor are annoyed.
Gabriel
I think mine are on strike, that's why my computer is so slow today.
deceze
Ahahaha, I mean 'process',Besides, we all know that CPU's are filled with little mythical dwarghs that work really hard all day to sequentially perform float multiplication.
Lajla
No Dwarfs here, I am using Intel... all tiny Canadian children trying to do binary math in Spanish. Es o ci que es, eh?
Gabriel
A: 

I would recommend putting in a counter and/or sleep statement.

The counter is to ensure that the script eventually quits and doesn't just hang around and keeps executing a failing statement.

The sleep statement is for "dealing" with momentary load issues.

Something like:

$remainingTries = 5;
while ($remainingTries > 0 && !sendmail())
{
  $remainingTries--; // we used a try, decrement
  sleep(5);          // wait five seconds before next try
}
kasper pedersen
+16  A: 

what if it cannot send? Daemon stopped, malformed data, connection loss, etc. What do you want the server to do? I advise setting a queue up on failure to retry later. Cron the retry (that way it is not hanging on a client request). Log tries and if certain error conditions occur then notify the admin.

[UPDATE] I have been reading the Pragmatic Programmer and I have to highly recommend it for dealing specifically with this question. It sets a standard in the way you think about error/exception handling and for me definitely cleared the fog regarding what an error is, vs an exception, vs an assertion condition (or impossible condition). In particular Chapter 4 Pragmatic Paranoia:

"When everyone actually is out to get you, paranoia is just good thinking" -Woody Allen

Gabriel
How about I mix the answer of Francisco Soto and Gabriel.First retry for 5 times and then setup a cron to try sending it later or inform the administratorWould this be good technique?
Starx
I think trying 5 times out of the gate is user abuse. The server is going to cycle that time away while the user sits there waiting to find out what happened. Try once, if you succeed inform the user, if you fail inform the user that it will be sent soon and queue it up (thanks Will for the spell check on that).
Gabriel
+4  A: 

So, what could possibly have gone wrong if mail() fails?

  • If your system is configured to hand mail to a local daemon, the daemon may be dead or misconfigured.
  • If you're talking to an SMTP server directly, the server is most likely dead, or something is misconfigured.

In both cases, how would you know when the responsible parties become responsive again? How long do you want to keep retrying?
The local mail daemon shouldn't ever die, or at least it should be resurrected immediately by the system. If that doesn't happen, you should fix the server instead of handling this situation in code.
If you're talking to an SMTP server, the only legitimate case where retrying a second or so later may actually succeed is if the server is being overloaded or DDoS'd and you're lucky enough to get through. That case is probably rare enough not to worry about though.

Either way, if mail() returns false, there's usually no point in trying again until you fix some other problem. Therefore, just fail gracefully, keep a complete log of things with a copy of the unsent mail and send it again later manually.

Anything beyond that point is out of your control, i.e. even if mail() succeeds, the email may or may not arrive at its destination. It's your job as server admin to catch bounced or error'd mails and act on them manually/try to figure out what's wrong.

deceze
A: 

Try something like this:

function doSomething($arg1, $arg2, $retry = 10)
{
    $result = false;

    /* do stuff */

    if ($result === false)
    {
        static $original = null;

        if (is_null($original))
        {
            set_time_limit(0);
            $original = $retry;
        }

        sleep(pow(2, $original - $retry));

        while (--$retry > 0)
        {
            return doSomething($arg1, $arg2, $retry);
        }
    }

    return $result;
}

If it fails, it retry $retry times and wait:

1 second before the 1st retry
2 seconds before the 2nd retry
4 seconds before the 3rd retry
8 seconds before the 4th retry
16 seconds before the 5th retry
32 seconds before the 6th retry
64 seconds before the 7th retry
128 seconds before the 8th retry
256 seconds before the 9th retry
512 seconds before the 10th retry
...
2 ^ ($retry - 1) seconds before the ($retry)th retry

By doing this you ensure you don't get your server overloaded.

Alix Axel