Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

In PHP I've written a relatively simple mail delivery script. Here is the actual delivery portion:

        private function SendMail($to, $subj) {
            if(!$this->smtp) { $this->OpenSMTPSock(); }
            fwrite($this->smtp, "MAIL FROM:<root@email.com>\r\n");
            fwrite($this->smtp, "RCPT TO:<$to>\r\n");
            fwrite($this->smtp, "DATA\r\n");
            fwrite($this->smtp, "Received: from email.com by domain.com ; ".date("r")."\r\n");
            fwrite($this->smtp, "Date: ".date("r")."\r\n");
            fwrite($this->smtp, "From:  ".$this->message["display_name"]." <root@email.com>\r\n");
            fwrite($this->smtp, "Reply-to: ".$this->message["reply"]."\r\n");
            fwrite($this->smtp, "Subject: $subj\r\n");
            fwrite($this->smtp, "To: $to\r\n");
            if($this->message["type"] == "H") {
                    fwrite($this->smtp, "content-type: text/html; charset=`iso-8859-1`");
                    fwrite($this->smtp, "\r\n".$this->m_html."\r\n");
            }
            if($this->message["type"] == "T") {
                    fwrite($this->smtp, "\r\n".$this->m_text."\r\n");
            }
            if($this->message["type"] == "B") {
                    echo "Sending multi part message\r\n";
                    $boundary = "_----------=_10167391337129230";
                    fwrite($this->smtp, "content-type: multipart/alternative; boundary=\"$boundary\"\r\n");
                    $outMsg = "This is a multi-part message in MIME format.\r\n";
                    $outMsg .= "--$boundary\r\nContent-Type: text/plain; charset=\"US-ASCII\"\r\n\n";
                    $outMsg .= "Content-Transfer-Encoding: 7bit\r\n\n";
                    $outMsg .= $this->m_text;
                    $outMsg .= "\r\n--$boundary\r\nContent-Type: text/html; charset=\"US-ASCII\"\r\n\n";
                    $outMsg .= $this->m_html;
                    $outMsg .= "\r\n--$boundary--";
                    fwrite($this->smtp, "Message: $outMsg\r\n");
            }
            fwrite($this->smtp, ".\r\n"); //This sends the message
            $this->Log("Message sent to $to");
    }

Here is where the socket is opened:

        private function OpenSMTPSock() {
            $this->Log("Attempting to open socket connection to SMTP host.");
            $this->smtp = fsockopen("localhost", 25, $errno, $errstr, 30);
            if(!$this->smtp) {
                    $this->Log("Failed to connect to SMTP server The following was observed.");
                    $this->Log("Fatal Error: $errno : $errstr");
                    exit;
            }
            else {
                    $this->Log("Connected to SMTP socket.");
                    fwrite($this->smtp, "HELO email.com\r\n");
            }
    }

*A destructor closes the socket Basically I loop through the list of recipients and send out a customized message to each one. It works perfectly until it gets to the last message, which doesn't get sent.

If I change $this->smtp to fopen("file", "w"), all the contents are there as expected. Additionally, if I then open that file and dump the contents into: telnet localhost 25 All the messages go out properly. Also, if I open the "file" within the PHP script, and write the lines into the socket, all messages go out as intended.

For the life of me, I can't figure out what is going wrong here. Halp!

share|improve this question
add comment

1 Answer

up vote 1 down vote accepted

Is your destructor sending the QUIT command? I concur that if everything is happening the way you think, the mail should have sent if the server returns the "250 OK" (does it after your last message? are you debugging this?). Try adding this to your code right after the 'CRLF.CRLF':

fwrite($this->smtp, "NOOP\r\n");

Maybe your class is having some sort of race condition with the buffer, the class is closing the connection before that final data in the buffer is sent. Adding a dummy NOOP to the chain might cause it to flush the previous bits out the pipe.

share|improve this answer
    
Yes, the destructor is basically, fwrite($this->smtp, "QUIT\r\n"); I will try your suggestion now, thanks for your input. –  Kyle Buser Oct 5 '10 at 15:34
    
I tried adding the NOOP command before QUIT and then again after every CRLF.CRLF No luck. I'll have to add some response reading I guess. Thanks for the suggestion, I'll let you know what I find. –  Kyle Buser Oct 5 '10 at 15:41
    
I added echo fgets($this->smtp) after every CRLF.CRLF The first one responded with 220 (SMTP Service ready.) - Was expecting 250. The following messages responded with 250, even the to the last recipient which wasn't receiving the message. I added more fgets, specifically after sending the HELO command. After doing this, I receive a 220, and then a 250 for each of the messages going out. This time, everyone on the list received the e-mail! So, I'm still not sure exactly why it's happening, but reading the response seems to fix the issue. Thanks for your help. –  Kyle Buser Oct 5 '10 at 15:54
    
Good to hear you got it - it's possible that the mail server was thinking you were flooding it's input, as technically you are not supposed to proceed with the next command until you've verified it's OK from the previous. Dumping it all at once without checking possibly resulted in the server not liking you going so fast, the fgets perhaps adds just enough delay to let it breathe some. shrug –  troyengel Oct 6 '10 at 0:26
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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