/wcfsetup/install/files/lib/system/mail/SMTPMailSender.class.php

https://github.com/KomHunter2/WCF · PHP · 214 lines · 131 code · 23 blank · 60 comment · 41 complexity · 35ab87c93e5c2fae2ee737f708f893fb MD5 · raw file

  1. <?php
  2. namespace wcf\system\mail;
  3. use wcf\system\exception\SystemException;
  4. use wcf\system\io\RemoteFile;
  5. /**
  6. * Sends a Mail with a connection to a smtp server.
  7. *
  8. * @author Michael Schaefer
  9. * @copyright 2001-2011 WoltLab GmbH
  10. * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  11. * @package com.woltlab.wcf
  12. * @subpackage data.mail
  13. * @category Community Framework
  14. */
  15. class SMTPMailSender extends MailSender {
  16. protected $connection = null;
  17. protected $statusCode = '';
  18. protected $statusMsg = '';
  19. protected $recipients;
  20. /**
  21. * Creates a new SMTPMailSender object.
  22. */
  23. public function __construct() {
  24. Mail::$crlf = "\r\n";
  25. }
  26. /**
  27. * Destroys the SMTPMailSender object.
  28. */
  29. public function __destruct() {
  30. $this->disconnect();
  31. }
  32. /**
  33. * Connects to the smtp-server
  34. */
  35. protected function connect() {
  36. // connect
  37. $this->connection = new RemoteFile(MAIL_SMTP_HOST, MAIL_SMTP_PORT);
  38. $this->getSMTPStatus();
  39. if ($this->statusCode != 220) {
  40. throw new SystemException($this->formatError("can not connect to '".MAIL_SMTP_HOST.":".MAIL_SMTP_PORT."'"));
  41. }
  42. // send ehlo
  43. $this->write('EHLO '.$_SERVER['HTTP_HOST']);
  44. $this->getSMTPStatus();
  45. if ($this->statusCode == 250) {
  46. // do authentication
  47. if (MAIL_SMTP_USER != '' || MAIL_SMTP_PASSWORD != '') {
  48. $this->auth();
  49. }
  50. }
  51. else {
  52. // send helo
  53. $this->write('HELO '.$_SERVER['HTTP_HOST']);
  54. $this->getSMTPStatus();
  55. if ($this->statusCode != 250) {
  56. throw new SystemException($this->formatError("can not connect to '".MAIL_SMTP_HOST.":".MAIL_SMTP_PORT."'"));
  57. }
  58. }
  59. }
  60. /**
  61. * Formats a smtp error message.
  62. *
  63. * @param string $message
  64. * @return string
  65. */
  66. protected function formatError($message) {
  67. return $message.': '.$this->statusMsg.' ('.$this->statusCode.')';
  68. }
  69. /**
  70. * Does the Authentification of the Client at the Server
  71. */
  72. protected function auth() {
  73. // Init Authentication
  74. $this->write('AUTH LOGIN');
  75. $this->getSMTPStatus();
  76. // checks if auth is supported
  77. if ($this->statusCode != 334) {
  78. throw new SystemException($this->formatError("smtp mail server '".MAIL_SMTP_HOST.":".MAIL_SMTP_PORT."' does not support user authentication"));
  79. }
  80. // sending user information to smtp-server
  81. $this->write(base64_encode(MAIL_SMTP_USER));
  82. $this->getSMTPStatus();
  83. if ($this->statusCode != 334) {
  84. throw new SystemException($this->formatError("unknown smtp user '".MAIL_SMTP_USER."'"));
  85. }
  86. $this->write(base64_encode(MAIL_SMTP_PASSWORD));
  87. $this->getSMTPStatus();
  88. if ($this->statusCode != 235) {
  89. throw new SystemException($this->formatError("invalid password for smtp user '".MAIL_SMTP_USER."'"));
  90. }
  91. }
  92. /**
  93. * @see wcf\system\mail\MailSender::sendMail()
  94. */
  95. public function sendMail(Mail $mail) {
  96. $this->recipients = array();
  97. if (count($mail->getTo()) > 0) $this->recipients = $mail->getTo();
  98. if (count($mail->getCC()) > 0) $this->recipients = array_merge($this->recipients, $mail->getCC());
  99. if (count($mail->getBCC())> 0) $this->recipients = array_merge($this->recipients, $mail->getBCC());
  100. // apply connection
  101. if ($this->connection === null) {
  102. $this->connect();
  103. }
  104. // send mail
  105. $this->write('MAIL FROM:<'.$mail->getFrom().'>');
  106. $this->getSMTPStatus();
  107. if ($this->statusCode != 250) {
  108. throw new SystemException($this->formatError("wrong from format '".$mail->getFrom()."'"));
  109. }
  110. // recipients
  111. $recipientCounter = 0;
  112. foreach ($this->recipients as $recipient) {
  113. $this->write('RCPT TO:<'.$recipient.'>');
  114. $this->getSMTPStatus();
  115. if ($this->statusCode != 250 && $this->statusCode != 251) {
  116. if ($this->statusCode < 550) {
  117. throw new SystemException($this->formatError("wrong recipient format '".$recipient."'"));
  118. }
  119. continue;
  120. }
  121. $recipientCounter++;
  122. }
  123. if (!$recipientCounter) {
  124. $this->write("RSET");
  125. return;
  126. }
  127. // data
  128. $this->write("DATA");
  129. $this->getSMTPStatus();
  130. if ($this->statusCode != 354 && $this->statusCode != 250) {
  131. throw new SystemException($this->formatError("smtp error"));
  132. }
  133. $header =
  134. "Date: ".gmdate('r').Mail::$crlf
  135. ."To: ".$mail->getToString().Mail::$crlf
  136. ."Message-ID: <".md5(uniqid())."@".$_SERVER['SERVER_NAME'].">".Mail::$crlf
  137. ."Subject: ".Mail::encodeMIMEHeader($mail->getSubject()).Mail::$crlf
  138. .$mail->getHeader();
  139. $this->write($header);
  140. $this->write("");
  141. $this->write($mail->getBody());
  142. $this->write(".");
  143. $this->getSMTPStatus();
  144. if ($this->statusCode != 250) {
  145. throw new SystemException($this->formatError("message sending failed"));
  146. }
  147. }
  148. /**
  149. * Disconnects the Client-Server connection
  150. */
  151. function disconnect() {
  152. if ($this->connection === null) {
  153. return;
  154. }
  155. $this->write("QUIT");
  156. $this->read();
  157. $this->connection->close();
  158. $this->connection = null;
  159. }
  160. /**
  161. * Reads the Information wich the Server sends back.
  162. *
  163. * @return string
  164. */
  165. protected function read() {
  166. $result = '';
  167. while ($read = $this->connection->gets()) {
  168. $result .= $read;
  169. if (substr($read, 3, 1) == " ") break;
  170. }
  171. return $result;
  172. }
  173. /**
  174. * Gets error code and message from a server message.
  175. *
  176. * @param string $data
  177. */
  178. protected function getSMTPStatus($data = null) {
  179. if ($data === null) $data = $this->read();
  180. $this->statusCode = intval(substr($data, 0, 3));
  181. $this->statusMsg = substr($data, 4);
  182. }
  183. /**
  184. * Sends Information to the smtp-Server
  185. *
  186. * @param string $data
  187. */
  188. protected function write($data) {
  189. $this->connection->puts($data.Mail::$crlf);
  190. }
  191. }