We Recommend

Wicked Cool PHP: Real-World Scripts That Solve Difficult Problems Wicked Cool PHP: Real-World Scripts That Solve Difficult Problems
Wicked Cool PHP contains a wide variety of scripts to process credit cards, check the validity of email addresses, template HTML, and serve dynamic images and text.


Posted By

skywalker on 02/21/08


Tagged

php mail smtp


Versions (?)


Who likes this?

1 person has marked this snippet as a favorite

adix


PHP - SMTP Mail Class


Published in: PHP 


SMTP Mail Sender (PHP) - Kagan GNGR

  1. <?php
  2. /**
  3.  * This is a drop-in replacement for mail() for *nix systems to force them
  4.  * to use a SMTP server instead of sendmail. (I suppose it could also be
  5.  * used on windows, but theres not much point).
  6.  *
  7.  * To use: set the SMTP_SERVER, and just use the SendMail() function below
  8.  * (same paramters as mail()).
  9.  *
  10.  * Btw, I did not write most of this. I made a couple modifications and
  11.  * fixes, and wrote SendMail(), but thats it. So there is no warrenty on
  12.  * this at all :)
  13.  *
  14.  *
  15.  * - Greg MacLellan
  16. */
  17.  
  18. // the SMTP server to use
  19. define("SMTP_SERVER", "mail.yourserver.com");
  20.  
  21. /*
  22.  * smtp.php
  23.  *
  24.  * @(#) $Header: /cvsroot/PHPlibrary/smtp.php,v 1.10 2000/06/03 02:29:41 mlemos Exp $
  25.  *
  26.  */
  27.  
  28.  
  29. class smtp_class
  30. {
  31. var $host_name="";
  32. var $host_port=25;
  33. var $localhost="";
  34. var $timeout=0;
  35. var $error="";
  36. var $debug=0;
  37. var $esmtp=1;
  38. var $esmtp_host="";
  39. var $esmtp_extensions=array();
  40. var $maximum_piped_recipients=100;
  41.  
  42. /* private variables - DO NOT ACCESS */
  43.  
  44. var $state="Disconnected";
  45. var $connection=0;
  46. var $pending_recipients=0;
  47.  
  48. /* Private methods - DO NOT CALL */
  49.  
  50. Function OutputDebug($message)
  51. {
  52. echo $message,"\n";
  53. }
  54.  
  55. Function GetLine()
  56. {
  57. for($line="";;)
  58. {
  59. if(feof($this->connection))
  60. {
  61. $this->error="reached the end of stream while reading from socket";
  62. return(0);
  63. }
  64. if(($data=fgets($this->connection,100))==false)
  65. {
  66. $this->error="it was not possible to read line from socket";
  67. return(0);
  68. }
  69. $line.=$data;
  70. $length=strlen($line);
  71. if($length>=2
  72. && substr($line,$length-2,2)=="
  73. ")
  74. {
  75. $line=substr($line,0,$length-2);
  76. if($this->debug)
  77. $this->OutputDebug("< $line");
  78. return($line);
  79. }
  80. }
  81. }
  82.  
  83. Function PutLine($line)
  84. {
  85. if($this->debug)
  86. $this->OutputDebug("> $line");
  87. if(!fputs($this->connection,"$line
  88. "))
  89. {
  90. $this->error="it was not possible to write line to socket";
  91. return(0);
  92. }
  93. return(1);
  94. }
  95.  
  96. Function PutData($data)
  97. {
  98. if(strlen($data))
  99. {
  100. if($this->debug)
  101. $this->OutputDebug("> $data");
  102. if(!fputs($this->connection,$data))
  103. {
  104. $this->error="it was not possible to write data to socket";
  105. return(0);
  106. }
  107. }
  108. return(1);
  109. }
  110.  
  111. Function VerifyResultLines($code,$responses="")
  112. {
  113. if(GetType($responses)!="array")
  114. $responses=array();
  115. Unset($match_code);
  116. while(($line=$this->GetLine($this->connection)))
  117. {
  118. if(IsSet($match_code))
  119. {
  120. if(strcmp(strtok($line," -"),$match_code))
  121. {
  122. $this->error=$line;
  123. return(0);
  124. }
  125. }
  126. else
  127. {
  128. $match_code=strtok($line," -");
  129. if(GetType($code)=="array")
  130. {
  131. for($codes=0;$codes<count($code) && strcmp($match_code,$code[$codes]);$codes++);
  132. if($codes>=count($code))
  133. {
  134. $this->error=$line;
  135. return(0);
  136. }
  137. }
  138. else
  139. {
  140. if(strcmp($match_code,$code))
  141. {
  142. $this->error=$line;
  143. return(0);
  144. }
  145. }
  146. }
  147. $responses[]=strtok("");
  148. if(!strcmp($match_code,strtok($line," ")))
  149. return(1);
  150. }
  151. return(-1);
  152. }
  153.  
  154. Function FlushRecipients()
  155. {
  156. if($this->pending_sender)
  157. {
  158. if($this->VerifyResultLines("250")<=0)
  159. return(0);
  160. $this->pending_sender=0;
  161. }
  162. for(;$this->pending_recipients;$this->pending_recipients--)
  163. {
  164. if($this->VerifyResultLines(array("250","251"))<=0)
  165. return(0);
  166. }
  167. return(1);
  168. }
  169.  
  170. /* Public methods */
  171.  
  172. Function Connect()
  173. {
  174. $this->error=$error="";
  175. $this->esmtp_host="";
  176. $this->esmtp_extensions=array();
  177. if(!($this->connection=($this->timeout ? fsockopen($this->host_name,$this->host_port,&$errno,&$error,$this->timeout) : fsockopen($this->host_name,$this->host_port))))
  178. {
  179. switch($error)
  180. {
  181. case -3:
  182. $this->error="-3 socket could not be created";
  183. return(0);
  184. case -4:
  185. $this->error="-4 dns lookup on hostname \"".$host_name."\" failed";
  186. return(0);
  187. case -5:
  188. $this->error="-5 connection refused or timed out";
  189. return(0);
  190. case -6:
  191. $this->error="-6 fdopen() call failed";
  192. return(0);
  193. case -7:
  194. $this->error="-7 setvbuf() call failed";
  195. return(0);
  196. default:
  197. $this->error=$error." could not connect to the host \"".$this->host_name."\"";
  198. return(0);
  199. }
  200. }
  201. else
  202. {
  203. if(!strcmp($localhost=$this->localhost,"")
  204. && !strcmp($localhost=getenv("SERVER_NAME"),"")
  205. && !strcmp($localhost=getenv("HOST"),""))
  206. $localhost="localhost";
  207. $success=0;
  208. if($this->VerifyResultLines("220")>0)
  209. {
  210. if($this->esmtp)
  211. {
  212. $responses=array();
  213. if($this->PutLine("EHLO $localhost")
  214. && $this->VerifyResultLines("250",&$responses)>0)
  215. {
  216. $this->esmtp_host=strtok($responses[0]," ");
  217. for($response=1;$response<count($responses);$response++)
  218. {
  219. $extension=strtoupper(strtok($responses[$response]," "));
  220. $this->esmtp_extensions[$extension]=strtok("");
  221. }
  222. $success=1;
  223. }
  224. }
  225. if(!$success
  226. && $this->PutLine("HELO $localhost")
  227. && $this->VerifyResultLines("250")>0)
  228. $success=1;
  229. }
  230. if($success)
  231. {
  232. $this->state="Connected";
  233. return(1);
  234. }
  235. else
  236. {
  237. fclose($this->connection);
  238. $this->connection=0;
  239. $this->state="Disconnected";
  240. return(0);
  241. }
  242. }
  243. }
  244.  
  245. Function MailFrom($sender)
  246. {
  247. if(strcmp($this->state,"Connected"))
  248. {
  249. $this->error="connection is not in the initial state";
  250. return(0);
  251. }
  252. $this->error="";
  253. if(!$this->PutLine("MAIL FROM:<$sender>"))
  254. return(0);
  255. if(!IsSet($this->esmtp_extensions["PIPELINING"])
  256. && $this->VerifyResultLines("250")<=0)
  257. return(0);
  258. $this->state="SenderSet";
  259. if(IsSet($this->esmtp_extensions["PIPELINING"]))
  260. $this->pending_sender=1;
  261. $this->pending_recipients=0;
  262. return(1);
  263. }
  264.  
  265. Function SetRecipient($recipient)
  266. {
  267. switch($this->state)
  268. {
  269. case "SenderSet":
  270. case "RecipientSet":
  271. break;
  272. default:
  273. $this->error="connection is not in the recipient setting state";
  274. return(0);
  275. }
  276. $this->error="";
  277. if(!$this->PutLine("RCPT TO:<$recipient>"))
  278. return(0);
  279. if(IsSet($this->esmtp_extensions["PIPELINING"]))
  280. {
  281. $this->pending_recipients++;
  282. if($this->pending_recipients>=$this->maximum_piped_recipients)
  283. {
  284. if(!$this->FlushRecipients())
  285. return(0);
  286. }
  287. }
  288. else
  289. {
  290. if($this->VerifyResultLines(array("250","251"))<=0)
  291. return(0);
  292. }
  293. $this->state="RecipientSet";
  294. return(1);
  295. }
  296.  
  297. Function StartData()
  298. {
  299. if(strcmp($this->state,"RecipientSet"))
  300. {
  301. $this->error="connection is not in the start sending data state";
  302. return(0);
  303. }
  304. $this->error="";
  305. if(!$this->PutLine("DATA"))
  306. return(0);
  307. if($this->pending_recipients)
  308. {
  309. if(!$this->FlushRecipients())
  310. return(0);
  311. }
  312. if($this->VerifyResultLines("354")<=0)
  313. return(0);
  314. $this->state="SendingData";
  315. return(1);
  316. }
  317.  
  318. Function PrepareData($data,&$output)
  319. {
  320. $length=strlen(&$data);
  321. for($output="",$position=0;$position<$length;)
  322. {
  323. $next_position=$length;
  324. for($current=$position;$current<$length;$current++)
  325. {
  326. switch($data[$current])
  327. {
  328. case "\n":
  329. $next_position=$current+1;
  330. break 2;
  331. case "\r":
  332. $next_position=$current+1;
  333. if($data[$next_position]=="\n")
  334. $next_position++;
  335. break 2;
  336. }
  337. }
  338. if($data[$position]==".")
  339. $output.=".";
  340. $output.=substr(&$data,$position,$current-$position)."
  341. ";
  342. $position=$next_position;
  343. }
  344. }
  345.  
  346. Function SendData($data)
  347. {
  348. if(strcmp($this->state,"SendingData"))
  349. {
  350. $this->error="connection is not in the sending data state";
  351. return(0);
  352. }
  353. $this->error="";
  354. return($this->PutData(&$data));
  355. }
  356.  
  357. Function EndSendingData()
  358. {
  359. if(strcmp($this->state,"SendingData"))
  360. {
  361. $this->error="connection is not in the sending data state";
  362. return(0);
  363. }
  364. $this->error="";
  365. if(!$this->PutLine("
  366. .")
  367. || $this->VerifyResultLines("250")<=0)
  368. return(0);
  369. $this->state="Connected";
  370. return(1);
  371. }
  372.  
  373. Function ResetConnection()
  374. {
  375. switch($this->state)
  376. {
  377. case "Connected":
  378. return(1);
  379. case "SendingData":
  380. $this->error="can not reset the connection while sending data";
  381. return(0);
  382. case "Disconnected":
  383. $this->error="can not reset the connection before it is established";
  384. return(0);
  385. }
  386. $this->error="";
  387. if(!$this->PutLine("RSET")
  388. || $this->VerifyResultLines("250")<=0)
  389. return(0);
  390. $this->state="Connected";
  391. return(1);
  392. }
  393.  
  394. Function Disconnect($quit=1)
  395. {
  396. if(!strcmp($this->state,"Disconnected"))
  397. {
  398. $this->error="it was not previously established a SMTP connection";
  399. return(0);
  400. }
  401. $this->error="";
  402. if(!strcmp($this->state,"Connected")
  403. && $quit
  404. && (!$this->PutLine("QUIT")
  405. || $this->VerifyResultLines("221")<=0))
  406. return(0);
  407. fclose($this->connection);
  408. $this->connection=0;
  409. $this->state="Disconnected";
  410. return(1);
  411. }
  412.  
  413. Function SendMessage($sender,$recipients,$headers,$body)
  414. {
  415. if(($success=$this->Connect()))
  416. {
  417. if(($success=$this->MailFrom($sender)))
  418. {
  419. for($recipient=0;$recipient<count($recipients);$recipient++)
  420. {
  421. if(!($success=$this->SetRecipient($recipients[$recipient])))
  422. break;
  423. }
  424. if($success
  425. && ($success=$this->StartData()))
  426. {
  427. for($header_data="",$header=0;$header<count($headers);$header++)
  428. $header_data.=$headers[$header]."
  429. ";
  430. if(($success=$this->SendData($header_data."
  431. ")))
  432. {
  433. $this->PrepareData($body,&$body_data);
  434. $success=$this->SendData($body_data);
  435. }
  436. if($success)
  437. $success=$this->EndSendingData();
  438. }
  439. }
  440. $error=$this->error;
  441. $disconnect_success=$this->Disconnect($success);
  442. if($success)
  443. $success=$disconnect_success;
  444. else
  445. $this->error=$error;
  446. }
  447. return($success);
  448. }
  449.  
  450. }
  451.  
  452.  
  453. function SendMail($to, $subject = "", $message = "", $headers = "") {
  454. $smtp = new smtp_class;
  455.  
  456. $smtp->host_name = SMTP_SERVER;
  457. $smtp->localhost = "localhost";
  458.  
  459. // If the "to" variable contains the Person's name and email address,
  460. // separate them with the matches array ... eg. John Doe <johndoe@hotmail.com>
  461. if (preg_match("/(.*)[\(<](.*)[>\)]/", $to, $matches)) {
  462. $ToName = $matches[1];
  463. $ToAddress = $matches[2];
  464. } else {
  465. $ToAddress = $ToName = $to;
  466. }
  467.  
  468. $headers .= "To: $ToName <$ToAddress>\n";
  469. $headers .= "Subject: $subject\n";
  470. $temparray = explode("\n",$headers);
  471.  
  472. while (list($key,$val) = each($temparray)) {
  473. if (substr($val,0,4) == "From") {
  474. // it's the From header, handle it a bit differently
  475. $from = trim(substr($val, 6));
  476.  
  477. // trim out the name/address from "Person <person@domain.com>"
  478. if (preg_match("/(.*)[\(<](.*)[>\)]/", $from, $matches)) {
  479. $FromName = $matches[1];
  480. $FromAddress = $matches[2];
  481. } else {
  482. $FromAddress = $FromName = $to;
  483. }
  484. $headersarray[] = "From: $FromName <$FromAddress>";
  485. } else if (trim($val) != "") {
  486. $headersarray[] = $val;
  487. }
  488. }
  489.  
  490. if ($smtp->SendMessage($FromAddress, array($ToAddress), $headersarray, $message)) {
  491. return true;
  492. } else {
  493. return false;
  494. }
  495. }
  496.  
  497.  
  498. ?>

Report this snippet 

You need to login to post a comment.