setOptions($options); } /** * Set options * * @param SmtpOptions $options * @return Smtp */ public function setOptions(SmtpOptions $options) { $this->options = $options; return $this; } /** * Get options * * @return SmtpOptions */ public function getOptions() { return $this->options; } /** * Set plugin manager for obtaining SMTP protocol connection * * @param Protocol\SmtpPluginManager $plugins * @throws Exception\InvalidArgumentException * @return Smtp */ public function setPluginManager(Protocol\SmtpPluginManager $plugins) { $this->plugins = $plugins; return $this; } /** * Get plugin manager for loading SMTP protocol connection * * @return Protocol\SmtpPluginManager */ public function getPluginManager() { if (null === $this->plugins) { $this->setPluginManager(new Protocol\SmtpPluginManager()); } return $this->plugins; } /** * Set the automatic disconnection when destruct * * @param bool $flag * @return Smtp */ public function setAutoDisconnect($flag) { $this->autoDisconnect = (bool) $flag; return $this; } /** * Get the automatic disconnection value * * @return bool */ public function getAutoDisconnect() { return $this->autoDisconnect; } /** * Return an SMTP connection * * @param string $name * @param array|null $options * @return Protocol\Smtp */ public function plugin($name, array $options = null) { return $this->getPluginManager()->get($name, $options); } /** * Class destructor to ensure all open connections are closed */ public function __destruct() { if ($this->connection instanceof Protocol\Smtp) { try { $this->connection->quit(); } catch (ProtocolException\ExceptionInterface $e) { // ignore } if ($this->autoDisconnect) { $this->connection->disconnect(); } } } /** * Sets the connection protocol instance * * @param Protocol\AbstractProtocol $connection */ public function setConnection(Protocol\AbstractProtocol $connection) { $this->connection = $connection; } /** * Gets the connection protocol instance * * @return Protocol\Smtp */ public function getConnection() { return $this->connection; } /** * Disconnect the connection protocol instance * * @return void */ public function disconnect() { if (!empty($this->connection) && ($this->connection instanceof Protocol\Smtp)) { $this->connection->disconnect(); } } /** * Send an email via the SMTP connection protocol * * The connection via the protocol adapter is made just-in-time to allow a * developer to add a custom adapter if required before mail is sent. * * @param Message $message * @throws Exception\RuntimeException */ public function send(Message $message) { // If sending multiple messages per session use existing adapter $connection = $this->getConnection(); if (!($connection instanceof Protocol\Smtp) || !$connection->hasSession()) { $connection = $this->connect(); } else { // Reset connection to ensure reliable transaction $connection->rset(); } // Prepare message $from = $this->prepareFromAddress($message); $recipients = $this->prepareRecipients($message); $headers = $this->prepareHeaders($message); $body = $this->prepareBody($message); if ((count($recipients) == 0) && (!empty($headers) || !empty($body))) { throw new Exception\RuntimeException( // Per RFC 2821 3.3 (page 18) sprintf( '%s transport expects at least one recipient if the message has at least one header or body', __CLASS__ )); } // Set sender email address $connection->mail($from); // Set recipient forward paths foreach ($recipients as $recipient) { $connection->rcpt($recipient); } // Issue DATA command to client $connection->data($headers . Headers::EOL . $body); } /** * Retrieve email address for envelope FROM * * @param Message $message * @throws Exception\RuntimeException * @return string */ protected function prepareFromAddress(Message $message) { $sender = $message->getSender(); if ($sender instanceof Address\AddressInterface) { return $sender->getEmail(); } $from = $message->getFrom(); if (!count($from)) { // Per RFC 2822 3.6 throw new Exception\RuntimeException(sprintf( '%s transport expects either a Sender or at least one From address in the Message; none provided', __CLASS__ )); } $from->rewind(); $sender = $from->current(); return $sender->getEmail(); } /** * Prepare array of email address recipients * * @param Message $message * @return array */ protected function prepareRecipients(Message $message) { $recipients = array(); foreach ($message->getTo() as $address) { $recipients[] = $address->getEmail(); } foreach ($message->getCc() as $address) { $recipients[] = $address->getEmail(); } foreach ($message->getBcc() as $address) { $recipients[] = $address->getEmail(); } $recipients = array_unique($recipients); return $recipients; } /** * Prepare header string from message * * @param Message $message * @return string */ protected function prepareHeaders(Message $message) { $headers = clone $message->getHeaders(); $headers->removeHeader('Bcc'); return $headers->toString(); } /** * Prepare body string from message * * @param Message $message * @return string */ protected function prepareBody(Message $message) { return $message->getBodyText(); } /** * Lazy load the connection * * @return Protocol\Smtp */ protected function lazyLoadConnection() { // Check if authentication is required and determine required class $options = $this->getOptions(); $config = $options->getConnectionConfig(); $config['host'] = $options->getHost(); $config['port'] = $options->getPort(); $connection = $this->plugin($options->getConnectionClass(), $config); $this->connection = $connection; return $this->connect(); } /** * Connect the connection, and pass it helo * * @return Protocol\Smtp */ protected function connect() { if (!$this->connection instanceof Protocol\Smtp) { return $this->lazyLoadConnection(); } $this->connection->connect(); $this->connection->helo($this->getOptions()->getName()); return $this->connection; } }