[ Index ]

MailPress 7.2

[ Index ]     [ Classes ]     [ Functions ]     [ Variables ]     [ Constants ]     [ Statistics ]    

title

Body

[close]

/mp-includes/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/ -> AbstractSmtpTransport.php (source)

   1  <?php
   2  
   3  /*
   4   * This file is part of SwiftMailer.
   5   * (c) 2004-2009 Chris Corbyn
   6   *
   7   * For the full copyright and license information, please view the LICENSE
   8   * file that was distributed with this source code.
   9   */
  10  
  11  /**
  12   * Sends Messages over SMTP.
  13   *
  14   * @author Chris Corbyn
  15   */
  16  abstract class Swift_Transport_AbstractSmtpTransport implements Swift_Transport
  17  {
  18      /** Input-Output buffer for sending/receiving SMTP commands and responses */
  19      protected $buffer;
  20  
  21      /** Connection status */
  22      protected $started = false;
  23  
  24      /** The domain name to use in HELO command */
  25      protected $domain = '[127.0.0.1]';
  26  
  27      /** The event dispatching layer */
  28      protected $eventDispatcher;
  29  
  30      protected $addressEncoder;
  31  
  32      /** Whether the PIPELINING SMTP extension is enabled (RFC 2920) */
  33      protected $pipelining = null;
  34  
  35      /** The pipelined commands waiting for response */
  36      protected $pipeline = [];
  37  
  38      /** Source Ip */
  39      protected $sourceIp;
  40  
  41      /** Return an array of params for the Buffer */
  42      abstract protected function getBufferParams();
  43  
  44      /**
  45       * Creates a new EsmtpTransport using the given I/O buffer.
  46       *
  47       * @param string $localDomain
  48       */
  49      public function __construct(Swift_Transport_IoBuffer $buf, Swift_Events_EventDispatcher $dispatcher, $localDomain = '127.0.0.1', Swift_AddressEncoder $addressEncoder = null)
  50      {
  51          $this->buffer = $buf;
  52          $this->eventDispatcher = $dispatcher;
  53          $this->addressEncoder = $addressEncoder ?? new Swift_AddressEncoder_IdnAddressEncoder();
  54          $this->setLocalDomain($localDomain);
  55      }
  56  
  57      /**
  58       * Set the name of the local domain which Swift will identify itself as.
  59       *
  60       * This should be a fully-qualified domain name and should be truly the domain
  61       * you're using.
  62       *
  63       * If your server does not have a domain name, use the IP address. This will
  64       * automatically be wrapped in square brackets as described in RFC 5321,
  65       * section 4.1.3.
  66       *
  67       * @param string $domain
  68       *
  69       * @return $this
  70       */
  71      public function setLocalDomain($domain)
  72      {
  73          if ('[' !== substr($domain, 0, 1)) {
  74              if (filter_var($domain, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
  75                  $domain = '['.$domain.']';
  76              } elseif (filter_var($domain, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
  77                  $domain = '[IPv6:'.$domain.']';
  78              }
  79          }
  80  
  81          $this->domain = $domain;
  82  
  83          return $this;
  84      }
  85  
  86      /**
  87       * Get the name of the domain Swift will identify as.
  88       *
  89       * If an IP address was specified, this will be returned wrapped in square
  90       * brackets as described in RFC 5321, section 4.1.3.
  91       *
  92       * @return string
  93       */
  94      public function getLocalDomain()
  95      {
  96          return $this->domain;
  97      }
  98  
  99      /**
 100       * Sets the source IP.
 101       *
 102       * @param string $source
 103       */
 104      public function setSourceIp($source)
 105      {
 106          $this->sourceIp = $source;
 107      }
 108  
 109      /**
 110       * Returns the IP used to connect to the destination.
 111       *
 112       * @return string
 113       */
 114      public function getSourceIp()
 115      {
 116          return $this->sourceIp;
 117      }
 118  
 119      public function setAddressEncoder(Swift_AddressEncoder $addressEncoder)
 120      {
 121          $this->addressEncoder = $addressEncoder;
 122      }
 123  
 124      public function getAddressEncoder()
 125      {
 126          return $this->addressEncoder;
 127      }
 128  
 129      /**
 130       * Start the SMTP connection.
 131       */
 132      public function start()
 133      {
 134          if (!$this->started) {
 135              if ($evt = $this->eventDispatcher->createTransportChangeEvent($this)) {
 136                  $this->eventDispatcher->dispatchEvent($evt, 'beforeTransportStarted');
 137                  if ($evt->bubbleCancelled()) {
 138                      return;
 139                  }
 140              }
 141  
 142              try {
 143                  $this->buffer->initialize($this->getBufferParams());
 144              } catch (Swift_TransportException $e) {
 145                  $this->throwException($e);
 146              }
 147              $this->readGreeting();
 148              $this->doHeloCommand();
 149  
 150              if ($evt) {
 151                  $this->eventDispatcher->dispatchEvent($evt, 'transportStarted');
 152              }
 153  
 154              $this->started = true;
 155          }
 156      }
 157  
 158      /**
 159       * Test if an SMTP connection has been established.
 160       *
 161       * @return bool
 162       */
 163      public function isStarted()
 164      {
 165          return $this->started;
 166      }
 167  
 168      /**
 169       * Send the given Message.
 170       *
 171       * Recipient/sender data will be retrieved from the Message API.
 172       * The return value is the number of recipients who were accepted for delivery.
 173       *
 174       * @param string[] $failedRecipients An array of failures by-reference
 175       *
 176       * @return int
 177       */
 178      public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null)
 179      {
 180          if (!$this->isStarted()) {
 181              $this->start();
 182          }
 183  
 184          $sent = 0;
 185          $failedRecipients = (array) $failedRecipients;
 186  
 187          if ($evt = $this->eventDispatcher->createSendEvent($this, $message)) {
 188              $this->eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed');
 189              if ($evt->bubbleCancelled()) {
 190                  return 0;
 191              }
 192          }
 193  
 194          if (!$reversePath = $this->getReversePath($message)) {
 195              $this->throwException(new Swift_TransportException('Cannot send message without a sender address'));
 196          }
 197  
 198          $to = (array) $message->getTo();
 199          $cc = (array) $message->getCc();
 200          $tos = array_merge($to, $cc);
 201          $bcc = (array) $message->getBcc();
 202  
 203          $message->setBcc([]);
 204  
 205          try {
 206              $sent += $this->sendTo($message, $reversePath, $tos, $failedRecipients);
 207              $sent += $this->sendBcc($message, $reversePath, $bcc, $failedRecipients);
 208          } finally {
 209              $message->setBcc($bcc);
 210          }
 211  
 212          if ($evt) {
 213              if ($sent == count($to) + count($cc) + count($bcc)) {
 214                  $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS);
 215              } elseif ($sent > 0) {
 216                  $evt->setResult(Swift_Events_SendEvent::RESULT_TENTATIVE);
 217              } else {
 218                  $evt->setResult(Swift_Events_SendEvent::RESULT_FAILED);
 219              }
 220              $evt->setFailedRecipients($failedRecipients);
 221              $this->eventDispatcher->dispatchEvent($evt, 'sendPerformed');
 222          }
 223  
 224          $message->generateId(); //Make sure a new Message ID is used
 225  
 226          return $sent;
 227      }
 228  
 229      /**
 230       * Stop the SMTP connection.
 231       */
 232      public function stop()
 233      {
 234          if ($this->started) {
 235              if ($evt = $this->eventDispatcher->createTransportChangeEvent($this)) {
 236                  $this->eventDispatcher->dispatchEvent($evt, 'beforeTransportStopped');
 237                  if ($evt->bubbleCancelled()) {
 238                      return;
 239                  }
 240              }
 241  
 242              try {
 243                  $this->executeCommand("QUIT\r\n", [221]);
 244              } catch (Swift_TransportException $e) {
 245              }
 246  
 247              try {
 248                  $this->buffer->terminate();
 249  
 250                  if ($evt) {
 251                      $this->eventDispatcher->dispatchEvent($evt, 'transportStopped');
 252                  }
 253              } catch (Swift_TransportException $e) {
 254                  $this->throwException($e);
 255              }
 256          }
 257          $this->started = false;
 258      }
 259  
 260      /**
 261       * {@inheritdoc}
 262       */
 263      public function ping()
 264      {
 265          try {
 266              if (!$this->isStarted()) {
 267                  $this->start();
 268              }
 269  
 270              $this->executeCommand("NOOP\r\n", [250]);
 271          } catch (Swift_TransportException $e) {
 272              try {
 273                  $this->stop();
 274              } catch (Swift_TransportException $e) {
 275              }
 276  
 277              return false;
 278          }
 279  
 280          return true;
 281      }
 282  
 283      /**
 284       * Register a plugin.
 285       */
 286      public function registerPlugin(Swift_Events_EventListener $plugin)
 287      {
 288          $this->eventDispatcher->bindEventListener($plugin);
 289      }
 290  
 291      /**
 292       * Reset the current mail transaction.
 293       */
 294      public function reset()
 295      {
 296          $this->executeCommand("RSET\r\n", [250], $failures, true);
 297      }
 298  
 299      /**
 300       * Get the IoBuffer where read/writes are occurring.
 301       *
 302       * @return Swift_Transport_IoBuffer
 303       */
 304      public function getBuffer()
 305      {
 306          return $this->buffer;
 307      }
 308  
 309      /**
 310       * Run a command against the buffer, expecting the given response codes.
 311       *
 312       * If no response codes are given, the response will not be validated.
 313       * If codes are given, an exception will be thrown on an invalid response.
 314       * If the command is RCPT TO, and the pipeline is non-empty, no exception
 315       * will be thrown; instead the failing address is added to $failures.
 316       *
 317       * @param string   $command
 318       * @param int[]    $codes
 319       * @param string[] $failures An array of failures by-reference
 320       * @param bool     $pipeline Do not wait for response
 321       * @param string   $address  The address, if command is RCPT TO.
 322       *
 323       * @return string|null The server response, or null if pipelining is enabled
 324       */
 325      public function executeCommand($command, $codes = [], &$failures = null, $pipeline = false, $address = null)
 326      {
 327          $failures = (array) $failures;
 328          $seq = $this->buffer->write($command);
 329          if ($evt = $this->eventDispatcher->createCommandEvent($this, $command, $codes)) {
 330              $this->eventDispatcher->dispatchEvent($evt, 'commandSent');
 331          }
 332  
 333          $this->pipeline[] = [$command, $seq, $codes, $address];
 334  
 335          if ($pipeline && $this->pipelining) {
 336              return null;
 337          }
 338  
 339          $response = null;
 340  
 341          while ($this->pipeline) {
 342              list($command, $seq, $codes, $address) = array_shift($this->pipeline);
 343              $response = $this->getFullResponse($seq);
 344              try {
 345                  $this->assertResponseCode($response, $codes);
 346              } catch (Swift_TransportException $e) {
 347                  if ($this->pipeline && $address) {
 348                      $failures[] = $address;
 349                  } else {
 350                      $this->throwException($e);
 351                  }
 352              }
 353          }
 354  
 355          return $response;
 356      }
 357  
 358      /** Read the opening SMTP greeting */
 359      protected function readGreeting()
 360      {
 361          $this->assertResponseCode($this->getFullResponse(0), [220]);
 362      }
 363  
 364      /** Send the HELO welcome */
 365      protected function doHeloCommand()
 366      {
 367          $this->executeCommand(
 368              sprintf("HELO %s\r\n", $this->domain), [250]
 369              );
 370      }
 371  
 372      /** Send the MAIL FROM command */
 373      protected function doMailFromCommand($address)
 374      {
 375          $address = $this->addressEncoder->encodeString($address);
 376          $this->executeCommand(
 377              sprintf("MAIL FROM:<%s>\r\n", $address), [250], $failures, true
 378              );
 379      }
 380  
 381      /** Send the RCPT TO command */
 382      protected function doRcptToCommand($address)
 383      {
 384          $address = $this->addressEncoder->encodeString($address);
 385          $this->executeCommand(
 386              sprintf("RCPT TO:<%s>\r\n", $address), [250, 251, 252], $failures, true, $address
 387              );
 388      }
 389  
 390      /** Send the DATA command */
 391      protected function doDataCommand(&$failedRecipients)
 392      {
 393          $this->executeCommand("DATA\r\n", [354], $failedRecipients);
 394      }
 395  
 396      /** Stream the contents of the message over the buffer */
 397      protected function streamMessage(Swift_Mime_SimpleMessage $message)
 398      {
 399          $this->buffer->setWriteTranslations(["\r\n." => "\r\n.."]);
 400          try {
 401              $message->toByteStream($this->buffer);
 402              $this->buffer->flushBuffers();
 403          } catch (Swift_TransportException $e) {
 404              $this->throwException($e);
 405          }
 406          $this->buffer->setWriteTranslations([]);
 407          $this->executeCommand("\r\n.\r\n", [250]);
 408      }
 409  
 410      /** Determine the best-use reverse path for this message */
 411      protected function getReversePath(Swift_Mime_SimpleMessage $message)
 412      {
 413          $return = $message->getReturnPath();
 414          $sender = $message->getSender();
 415          $from = $message->getFrom();
 416          $path = null;
 417          if (!empty($return)) {
 418              $path = $return;
 419          } elseif (!empty($sender)) {
 420              // Don't use array_keys
 421              reset($sender); // Reset Pointer to first pos
 422              $path = key($sender); // Get key
 423          } elseif (!empty($from)) {
 424              reset($from); // Reset Pointer to first pos
 425              $path = key($from); // Get key
 426          }
 427  
 428          return $path;
 429      }
 430  
 431      /** Throw a TransportException, first sending it to any listeners */
 432      protected function throwException(Swift_TransportException $e)
 433      {
 434          if ($evt = $this->eventDispatcher->createTransportExceptionEvent($this, $e)) {
 435              $this->eventDispatcher->dispatchEvent($evt, 'exceptionThrown');
 436              if (!$evt->bubbleCancelled()) {
 437                  throw $e;
 438              }
 439          } else {
 440              throw $e;
 441          }
 442      }
 443  
 444      /** Throws an Exception if a response code is incorrect */
 445      protected function assertResponseCode($response, $wanted)
 446      {
 447          if (!$response) {
 448              $this->throwException(new Swift_TransportException('Expected response code '.implode('/', $wanted).' but got an empty response'));
 449          }
 450  
 451          list($code) = sscanf($response, '%3d');
 452          $valid = (empty($wanted) || in_array($code, $wanted));
 453  
 454          if ($evt = $this->eventDispatcher->createResponseEvent($this, $response,
 455              $valid)) {
 456              $this->eventDispatcher->dispatchEvent($evt, 'responseReceived');
 457          }
 458  
 459          if (!$valid) {
 460              $this->throwException(new Swift_TransportException('Expected response code '.implode('/', $wanted).' but got code "'.$code.'", with message "'.$response.'"', $code));
 461          }
 462      }
 463  
 464      /** Get an entire multi-line response using its sequence number */
 465      protected function getFullResponse($seq)
 466      {
 467          $response = '';
 468          try {
 469              do {
 470                  $line = $this->buffer->readLine($seq);
 471                  $response .= $line;
 472              } while (null !== $line && false !== $line && ' ' != $line[3]);
 473          } catch (Swift_TransportException $e) {
 474              $this->throwException($e);
 475          } catch (Swift_IoException $e) {
 476              $this->throwException(new Swift_TransportException($e->getMessage(), 0, $e));
 477          }
 478  
 479          return $response;
 480      }
 481  
 482      /** Send an email to the given recipients from the given reverse path */
 483      private function doMailTransaction($message, $reversePath, array $recipients, array &$failedRecipients)
 484      {
 485          $sent = 0;
 486          $this->doMailFromCommand($reversePath);
 487          foreach ($recipients as $forwardPath) {
 488              try {
 489                  $this->doRcptToCommand($forwardPath);
 490                  ++$sent;
 491              } catch (Swift_TransportException $e) {
 492                  $failedRecipients[] = $forwardPath;
 493              } catch (Swift_AddressEncoderException $e) {
 494                  $failedRecipients[] = $forwardPath;
 495              }
 496          }
 497  
 498          if (0 != $sent) {
 499              $sent += count($failedRecipients);
 500              $this->doDataCommand($failedRecipients);
 501              $sent -= count($failedRecipients);
 502  
 503              $this->streamMessage($message);
 504          } else {
 505              $this->reset();
 506          }
 507  
 508          return $sent;
 509      }
 510  
 511      /** Send a message to the given To: recipients */
 512      private function sendTo(Swift_Mime_SimpleMessage $message, $reversePath, array $to, array &$failedRecipients)
 513      {
 514          if (empty($to)) {
 515              return 0;
 516          }
 517  
 518          return $this->doMailTransaction($message, $reversePath, array_keys($to),
 519              $failedRecipients);
 520      }
 521  
 522      /** Send a message to all Bcc: recipients */
 523      private function sendBcc(Swift_Mime_SimpleMessage $message, $reversePath, array $bcc, array &$failedRecipients)
 524      {
 525          $sent = 0;
 526          foreach ($bcc as $forwardPath => $name) {
 527              $message->setBcc([$forwardPath => $name]);
 528              $sent += $this->doMailTransaction(
 529                  $message, $reversePath, [$forwardPath], $failedRecipients
 530                  );
 531          }
 532  
 533          return $sent;
 534      }
 535  
 536      /**
 537       * Destructor.
 538       */
 539      public function __destruct()
 540      {
 541          try {
 542              $this->stop();
 543          } catch (Exception $e) {
 544          }
 545      }
 546  }


Generated: Tue May 19 15:55:14 2020 Cross-referenced by PHPXref 0.7.1