Jump to content


Corporate Sponsors


Latest News: (loading..)

* * * * * 1 votes

SMTP Authentication and OSCommerce


9 replies to this topic

#1 bscanzoni

  • Community Member
  • 1 posts
  • Real Name:Bryan Scanzoni

Posted 22 May 2004, 23:38

Hello all,

I am usually not so nice as to post things of this nature, but since I have bruises (exaggeration) on my knuckles from punching the walls earlier, I figured I'd go ahead and share. As much as I'd love to package this up and "contribute", I am in the middle of a big project. If anyone wants to do this, feel free to do it and credit yourself as I am only doing this so noone else considers suicide over this crap (kidding).

Basically, a huge problem arrises with the php function "mail" if your server requires SMTP authentication. Tell tale sign of this, is the ability for you to send mail to your domain or any domain on the server (if virtual).

While, I found a contribution that was supposed to address this, I could not get to work. So I said screw it, and went with what I know works and have had to use in my other scripts. A script is circulating the internet dubbed sock_mail.php which bascially uses pear(?) to open an actual SMTP connection. This function supports authentication.

So what I did was scrap the whole email class and modified the tep_mail function to gather and restructure the incoming data and pass it to sock_mail. Simple enough - here is the code. Keep in mind, I just did this, so there could be potential issues which I would be very grateful if someone would point out now.

These instructions are for /includes/functions/general.php only - you will probably need to do the same general.php under /admin

Anyway, open /includes/functions/general.php.

Before the tep_mail function insert (configure the variables located at the top of this function to match your configuration (username/pass)):

function sock_mail($auth,$to, $subj, $body, $head, $from){
       $lb="\r\n";                        //linebreak
       $body_lb="\r\n";                //body linebreak
       $loc_host = "localhost";        //localhost
       $smtp_acc = "username";        //account
       $smtp_pass="password";            //password
       $smtp_host="localhost";    //server SMTP
       #$hdr = explode($lb,$head);        //header
       
       if($body) {$bdy = preg_replace("/^\./","..",explode($body_lb,$body));}
       
       // build the array for the SMTP dialog. Line content is array(command, success code, additonal error message)
       if($auth == 1){// SMTP authentication methode AUTH LOGIN, use extended HELO "EHLO"
           $smtp = array(
               // call the server and tell the name of your local host
               array("EHLO ".$loc_host.$lb,"220,250","HELO error: "),
               // request to auth
               array("AUTH LOGIN".$lb,"334","AUTH error:"),
               // username
               array(base64_encode($smtp_acc).$lb,"334","AUTHENTIFICATION error : "),
               // password
               array(base64_encode($smtp_pass).$lb,"235","AUTHENTIFICATION error : "));
       } 
       else {// no authentication, use standard HELO    
           $smtp = array(
               // call the server and tell the name of your local host
               array("HELO ".$loc_host.$lb,"220,250","HELO error: "));
       }
   
       
       // envelop
       $smtp[] = array("MAIL FROM: <".$from.">".$lb,"250","MAIL FROM error: ");
       $smtp[] = array("RCPT TO: <".$to.">".$lb,"250","RCPT TO error: ");
       // begin data        
       $smtp[] = array("DATA".$lb,"354","DATA error: ");
       // header
       $smtp[] = array("Subject: ".$subj.$lb,"","");
       $smtp[] = array("To:".$to.$lb,"","");        
       foreach($head as $h) {$smtp[] = array($h.$lb,"","");}
       // end header, begin the body
       $smtp[] = array($lb,"","");
       if($bdy) {foreach($bdy as $b) {$smtp[] = array($b.$body_lb,"","");}}
       // end of message
       $smtp[] = array(".".$lb,"250","DATA(end)error: ");
       $smtp[] = array("QUIT".$lb,"221","QUIT error: ");

       // open socket
       $fp = @fsockopen($smtp_host, 25);
       if (!$fp) echo "<b>Error:</b> Cannot conect to ".$smtp_host."<br>";
       
       $banner = @fgets($fp, 1024);
       // perform the SMTP dialog with all lines of the list
       foreach($smtp as $req){
           $r = $req[0];
           // send request
           @fputs($fp, $req[0]);
           // get available server messages and stop on errors
           if($req[1]){
               while($result = @fgets($fp, 1024)){if(substr($result,3,1) == " ") { break; }};
               if (!strstr($req[1],substr($result,0,3))) echo"$req[2].$result<br>";
           }
       }
       $result = @fgets($fp, 1024);
       // close socket
       @fclose($fp);
       return 1;
   }  

Next, scrap the whole tep_mail function and replace with :

  function tep_mail($to_name, $to_email_address, $email_subject, $email_text, $from_email_name, $from_email_address) {
    $headers[0]='MIME-Version: 1.0';
	$headers[1]='Content-type: text/html; charset=iso-8859-1';
	$headers[2]='From: '.$from_email_name.'<'.$from_email_address.'>';
	$from = $from_email_address;
	$subject = $email_subject;
	$catre = $to_email_address;
	$email_text = str_replace("\n", "<br>", $email_text);
	sock_mail(1,$catre,$subject,$email_text,$headers,$from);
 	 
  }

Finally, verify that your email settings in the admin panel are as follows:

E-Mail Transport Method: smtp
E-Mail Linefeeds: CRLF
Use MIME HTML When Sending Emails: true
Verify E-Mail Addresses Through DNS: false
Send E-Mails: true

There you go, problem solved - you should be able to send mail without an issue now. Or this will at least be a good starting point for you.

#2 graficalicus

  • Community Member
  • 23 posts
  • Real Name:mike
  • Location:nc

Posted 31 May 2004, 02:53

thanks for this - I plan on giving it a try later this week -

^_^
_mike

#3 fl70

  • Community Member
  • 450 posts
  • Real Name:Ray
  • Location:NJ, USA

Posted 04 June 2004, 05:15

Nice Job!
1 error I encountered in:
  function tep_mail($to_name, $to_email_address, $email_subject, $email_text, $from_email_name, $from_email_address) {
   $headers[0]='MIME-Version: 1.0';
$headers[1]='Content-type: text/html; charset=iso-8859-1';
$headers[2]='From: '.$from_email_name.'<'.$from_email_address.'>';
$from = $from_email_address;
$subject = $email_subject;
$catre = $to_email_address;
$email_text = str_replace("\n", "<br>", $email_text);
sock_mail(1,$catre,$subject,$email_text,$headers,$from);
 
 }
Could not use the last bracket }
Also they must comment out or remove the following in /includes/classes/email.php:
      if (EMAIL_TRANSPORT == 'smtp') {
        return mail($to_addr, $subject, $this->output, 'From: ' . $from . $this->lf . 'To: ' . $to . $this->lf . implode($this->lf, $this->headers) . $this->lf . implode($this->lf, $xtra_headers));
      } else {
        return mail($to, $subject, $this->output, 'From: '.$from.$this->lf.implode($this->lf, $this->headers).$this->lf.implode($this->lf, $xtra_headers));
      }
Also in admin under Configuration-My Store- Send Extra Order Emails To
it should be you@yoursite.com not You <you@yoursite.com>

Nice job!
It ain't your grandma's box!

#4 fl70

  • Community Member
  • 450 posts
  • Real Name:Ray
  • Location:NJ, USA

Posted 04 June 2004, 05:33

To late to edit.
In this section of code to eliminate the double spacing in the email change this line:

$email_text = str_replace("\n", "<br>", $email_text);
to:
$email_text = str_replace("\n", "\r\n", $email_text);
so it all looks like:
function sock_mail($auth,$to, $subj, $body, $head, $from){
      $lb="\r\n";                        //linebreak
      $body_lb="\r\n";                //body linebreak
      $loc_host = "localhost";        //localhost
      $smtp_acc = "username";        //account
      $smtp_pass="password";            //password
      $smtp_host="localhost";    //server SMTP
      #$hdr = explode($lb,$head);        //header
     
      if($body) {$bdy = preg_replace("/^\./","..",explode($body_lb,$body));}
     
      // build the array for the SMTP dialog. Line content is array(command, success code, additonal error message)
      if($auth == 1){// SMTP authentication methode AUTH LOGIN, use extended HELO "EHLO"
          $smtp = array(
              // call the server and tell the name of your local host
              array("EHLO ".$loc_host.$lb,"220,250","HELO error: "),
              // request to auth
              array("AUTH LOGIN".$lb,"334","AUTH error:"),
              // username
              array(base64_encode($smtp_acc).$lb,"334","AUTHENTIFICATION error : "),
              // password
              array(base64_encode($smtp_pass).$lb,"235","AUTHENTIFICATION error : "));
      }
      else {// no authentication, use standard HELO    
          $smtp = array(
              // call the server and tell the name of your local host
              array("HELO ".$loc_host.$lb,"220,250","HELO error: "));
      }
 
     
      // envelop
      $smtp[] = array("MAIL FROM: <".$from.">".$lb,"250","MAIL FROM error: ");
      $smtp[] = array("RCPT TO: <".$to.">".$lb,"250","RCPT TO error: ");
      // begin data        
      $smtp[] = array("DATA".$lb,"354","DATA error: ");
      // header
      $smtp[] = array("Subject: ".$subj.$lb,"","");
      $smtp[] = array("To:".$to.$lb,"","");        
      foreach($head as $h) {$smtp[] = array($h.$lb,"","");}
      // end header, begin the body
      $smtp[] = array($lb,"","");
      if($bdy) {foreach($bdy as $b) {$smtp[] = array($b.$body_lb,"","");}}
      // end of message
      $smtp[] = array(".".$lb,"250","DATA(end)error: ");
      $smtp[] = array("QUIT".$lb,"221","QUIT error: ");

      // open socket
      $fp = @fsockopen($smtp_host, 25);
      if (!$fp) echo "<b>Error:</b> Cannot conect to ".$smtp_host."<br>";
     
      $banner = @fgets($fp, 1024);
      // perform the SMTP dialog with all lines of the list
      foreach($smtp as $req){
          $r = $req[0];
          // send request
          @fputs($fp, $req[0]);
          // get available server messages and stop on errors
          if($req[1]){
              while($result = @fgets($fp, 1024)){if(substr($result,3,1) == " ") { break; }};
              if (!strstr($req[1],substr($result,0,3))) echo"$req[2].$result<br>";
          }
      }
      $result = @fgets($fp, 1024);
      // close socket
      @fclose($fp);
      return 1;
  }
  function tep_mail($to_name, $to_email_address, $email_subject, $email_text, $from_email_name, $from_email_address) {
   $headers[0]='MIME-Version: 1.0';
$headers[1]='Content-type: text/html; charset=iso-8859-1';
$headers[2]='From: '.$from_email_name.'<'.$from_email_address.'>';
$from = $from_email_address;
$subject = $email_subject;
$catre = $to_email_address;
$email_text = str_replace("\n", "\r\n", $email_text);
sock_mail(1,$catre,$subject,$email_text,$headers,$from);

It ain't your grandma's box!

#5 sonofsmog

  • Community Member
  • 1 posts
  • Real Name:Daniel Blackmon

Posted 28 August 2008, 01:51

Good stuff.

This is how I ended up tying it all together.

I left the tep_mail function alone and added the sock_mail function with a minor tweak to allow the usual e-mail address format.

Stick this in general.php (both of em)

	function sock_mail($auth,$to, $subj, $body, $head, $from)
	{
		$lb="\r\n";                        	//linebreak
		$body_lb="\r\n";                	//body linebreak
		$loc_host = "localhost";        	//localhost
		$smtp_acc = "account";        	//account
		$smtp_pass="password";   		//password
		$smtp_host="192.168.0.1";    		//server SMTP
		#$hdr = explode($lb,$head);        	//header
		
		// mod for $from = "joe blow joe@blow" - dblackmon
		if (strrpos($from,' ')!= false) 
		{
			$from = substr($from, strrpos($from,' ') + 1);
			$from = str_replace(array("<", ">"), '', $from);
		}
		 
		if($body) {$bdy = preg_replace("/^\./","..",explode($body_lb,$body));}
		 
		// build the array for the SMTP dialog. Line content is array(command, success code, additonal error message)
		if($auth == 1){// SMTP authentication methode AUTH LOGIN, use extended HELO "EHLO"
		    $smtp = array(
		        // call the server and tell the name of your local host
		        array("EHLO ".$loc_host.$lb,"220,250","HELO error: "),
		        // request to auth
		        array("AUTH LOGIN".$lb,"334","AUTH error:"),
		        // username
		        array(base64_encode($smtp_acc).$lb,"334","AUTHENTIFICATION error : "),
		        // password
		        array(base64_encode($smtp_pass).$lb,"235","AUTHENTIFICATION error : "));
		}
		else {// no authentication, use standard HELO    
		    $smtp = array(
		        // call the server and tell the name of your local host
		        array("HELO ".$loc_host.$lb,"220,250","HELO error: "));
		}
				
		// envelop
		$smtp[] = array("MAIL FROM: <".$from.">".$lb,"250","MAIL FROM error: ");
		$smtp[] = array("RCPT TO: <".$to.">".$lb,"250","RCPT TO error: ");
		// begin data        
		$smtp[] = array("DATA".$lb,"354","DATA error: ");
		// header
		$smtp[] = array("Subject: ".$subj.$lb,"","");
		$smtp[] = array("To:".$to.$lb,"","");        
		foreach($head as $h) {$smtp[] = array($h.$lb,"","");}
		// end header, begin the body
		$smtp[] = array($lb,"","");
		if($bdy) {foreach($bdy as $B) {$smtp[] = array($b.$body_lb,"","");}}
		// end of message
		$smtp[] = array(".".$lb,"250","DATA(end)error: ");
		$smtp[] = array("QUIT".$lb,"221","QUIT error: ");
				 // open socket
		$fp = @fsockopen($smtp_host, 25);
		if (!$fp) echo "<b>Error:</b> Cannot conect to ".$smtp_host."<br>";
				 $banner = @fgets($fp, 1024);
		// perform the SMTP dialog with all lines of the list
		foreach($smtp as $req){
		    $r = $req[0];
		    // send request
		    @fputs($fp, $req[0]);
		    // get available server messages and stop on errors
		    if($req[1]){
		        while($result = @fgets($fp, 1024)){if(substr($result,3,1) == " ") { break; }};
		        if (!strstr($req[1],substr($result,0,3))) echo"$req[2].$result<br>";
		    }
		}
		$result = @fgets($fp, 1024);
		// close socket
		@fclose($fp);
		return 1;
	}

Then I added this function to general.php because the way oscommerce was handling (mishandling) line breaks was making me crazy.

//
// dblackmon - replaces tep_convert_linefeeds
//
	function dan_convert_linefeeds($to, $string)
	{
		$text = explode("\n", $string );
		foreach ($text as $text_piece)
		{
			$new_piece[] = str_replace("\r", '', $text_piece);
		}
		return implode($to,$new_piece);
	}

Finally,

I made these changes is e-mail.php (both of them)
    function add_text($text = '') 
	{
//dblackmon - fix double lf's	$this->text = tep_convert_linefeeds(array("\r\n", "\n", "\r"), $this->lf, $text);
		$this->text = dan_convert_linefeeds($this->lf, $text);
    }

	function add_html($html, $text = NULL, $images_dir = NULL) 
	{
//dblackmon - fix double lf's    	$this->html = tep_convert_linefeeds(array("\r\n", "\n", "\r"), '<br>', $html);
//dblackmon - fix double lf's     	$this->html_text = tep_convert_linefeeds(array("\r\n", "\n", "\r"), $this->lf, $text);
		$this->html = dan_convert_linefeeds('<br>', $html);
		$this->html_text = dan_convert_linefeeds($this->lf, $text);

      if (isset($images_dir)) $this->find_html_images($images_dir);
    }

Finally, this fixes up the SMTP

// dblackmon - SMTP AUTH        return mail($to_addr, $subject, $this->output, 'From: ' . $from . $this->lf . 'To: ' . $to . $this->lf . implode($this->lf, $this->headers) . $this->lf . implode($this->lf, $xtra_headers));
		return sock_mail(1, $to_addr, $subject, $this->output, explode($this->lf,'From: '.$from.$this->lf.
						 implode($this->lf, $this->headers).$this->lf.implode($this->lf, $xtra_headers)),$from_addr);


#6 catch

  • Community Member
  • 77 posts
  • Real Name:Ali

Posted 26 July 2011, 22:30

Hi

I have the ssme problem right now. My host disabling PHPMail function and need I to update the scripts and use SMTP authentication.

Can anyone describe exactly what I should do? I´ts little hard to find round in this thread.

#7 Acknowledeged74

  • Community Member
  • 99 posts
  • Real Name:Ashley Smith
  • Gender:Female
  • Location:London, UK

Posted 31 August 2011, 15:05

Yep tricky stuff, mine is now using SMTP auth. annoyingly aswell, be great if there was an ad on that would achieve all this for you.

Struggling........

Edited by Acknowledeged74, 31 August 2011, 15:05.


#8 jtjt

  • Community Member
  • 2 posts
  • Real Name:Jonathan

Posted 17 September 2011, 15:11

It wasn't easy for me to get this working as an amateur, but I did get there in the end. Issues I had to deal with:

(1) different error codes (actually status codes as I learnt) kept being thrown up through the smtp communication. Apparently they weren't errors - which begin 4xx or 5xx - so I added them to the list of allowed "error" codes in the code:

eg instead of $smtp[] = array("DATA".$lb,"354","DATA error: ");

I used $smtp[] = array("DATA".$lb,"250,354","DATA error: ");

ie I added to 250 to the list as it kept coming up when it didn't seem to indicate a real problem

(2) don't forget to use the correct port number in $fp = @fsockopen($smtp_host, 25); my port was actually 465!

(3) after getting the code to deliver e-mails they all turned out to be empty - in the end I traced it case sensitive code - the error required a large "B" to be changed to a small "b" in if($bdy) {foreach($bdy as $B) {$smtp[] = array($b.$body_lb,"","");}} - not "as $B" but "as $b"!!!!!!!!!!!!!!!!!!!

So at least don't waste time on these ...

#9 jtjt

  • Community Member
  • 2 posts
  • Real Name:Jonathan

Posted 17 September 2011, 15:13

... funny my dollar capital B turned into a dollar smiley as I posted ...

#10 Acknowledeged74

  • Community Member
  • 99 posts
  • Real Name:Ashley Smith
  • Gender:Female
  • Location:London, UK

Posted 03 May 2012, 16:59

Hi

The new code for general.php and email.php is this meant to replace something, or just be added? If so where?