PK kQK8%
LICENSE.mdnu ٘ Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
- Neither the name of Laminas Foundation nor the names of its contributors may
be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
PK kQF[ [ COPYRIGHT.mdnu ٘ Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC. (https://getlaminas.org/)
PK kQr .travis.ymlnu ٘ language: php
cache:
directories:
- $HOME/.composer/cache
env:
global:
- COMPOSER_ARGS="--no-interaction"
- COVERAGE_DEPS="php-coveralls/php-coveralls"
matrix:
fast_finish: true
include:
- php: 7.1
env:
- DEPS=lowest
- php: 7.1
env:
- DEPS=latest
- CS_CHECK=true
- TEST_COVERAGE=true
- php: 7.2
env:
- DEPS=lowest
- php: 7.2
env:
- DEPS=latest
- php: 7.3
env:
- DEPS=latest
- php: 7.4
env:
- DEPS=latest
before_install:
- if [[ $TEST_COVERAGE != 'true' ]]; then phpenv config-rm xdebug.ini || return 0 ; fi
install:
- travis_retry composer install $COMPOSER_ARGS --ignore-platform-reqs
- if [[ $LEGACY_DEPS != '' ]]; then travis_retry composer update --with-dependencies $COMPOSER_ARGS $LEGACY_DEPS ; fi
- if [[ $DEPS == 'latest' ]]; then travis_retry composer update $COMPOSER_ARGS ; fi
- if [[ $DEPS == 'lowest' ]]; then travis_retry composer update --prefer-lowest --prefer-stable $COMPOSER_ARGS ; fi
- if [[ $TEST_COVERAGE == 'true' ]]; then travis_retry composer require --dev $COMPOSER_ARGS $COVERAGE_DEPS ; fi
- stty cols 120 && composer show
script:
- if [[ $TEST_COVERAGE == 'true' ]]; then composer test-coverage ; else composer test ; fi
- if [[ $CS_CHECK == 'true' ]]; then composer cs-check ; fi
after_script:
- if [[ $TEST_COVERAGE == 'true' ]]; then travis_retry php vendor/bin/php-coveralls -v ; fi
notifications:
email: false
PK kQx= = .coveralls.ymlnu ٘ coverage_clover: clover.xml
json_path: coveralls-upload.json
PK kQ= phpcs.xmlnu ٘
src
test
PK kQh~! ! README.mdnu ٘ # laminas-mail
[![Build Status](https://travis-ci.com/laminas/laminas-mail.svg?branch=master)](https://travis-ci.com/laminas/laminas-mail)
[![Coverage Status](https://coveralls.io/repos/github/laminas/laminas-mail/badge.svg?branch=master)](https://coveralls.io/github/laminas/laminas-mail?branch=master)
`Laminas\Mail` provides generalized functionality to compose and send both text and
MIME-compliant multipart email messages. Mail can be sent with `Laminas\Mail` via
the `Mail\Transport\Sendmail`, `Mail\Transport\Smtp` or the `Mail\Transport\File`
transport. Of course, you can also implement your own transport by implementing
the `Mail\Transport\TransportInterface`.
- File issues at https://github.com/laminas/laminas-mail/issues
- Documentation is at https://docs.laminas.dev/laminas-mail/
PK kQ9IG
.gitignorenu ٘ /clover.xml
/composer.lock
/coveralls-upload.json
/docs/html/
/laminas-mkdoc-theme.tgz
/laminas-mkdoc-theme/
/phpunit.xml
/vendor/
/test/_files/test.maildir/
PK kQ;hE E src/Headers.phpnu ٘ 2) {
throw new Exception\RuntimeException('Malformed header detected');
}
continue;
}
if ($emptyLine > 1) {
throw new Exception\RuntimeException('Malformed header detected');
}
// check if a header name is present
if (preg_match('/^[\x21-\x39\x3B-\x7E]+:.*$/', $line)) {
if ($currentLine) {
// a header name was present, then store the current complete line
$headers->addHeaderLine($currentLine);
}
$currentLine = trim($line);
continue;
}
// continuation: append to current line
// recover the whitespace that break the line (unfolding, rfc2822#section-2.2.3)
if (preg_match('/^\s+.*$/', $line)) {
$currentLine .= ' ' . trim($line);
continue;
}
// Line does not match header format!
throw new Exception\RuntimeException(sprintf(
'Line "%s" does not match header format!',
$line
));
}
if ($currentLine) {
$headers->addHeaderLine($currentLine);
}
return $headers;
}
/**
* Set an alternate PluginClassLocator implementation for loading header classes.
*
* @deprecated since 2.12.0
* @todo Remove for version 3.0.0
* @return $this
*/
public function setPluginClassLoader(PluginClassLocator $pluginClassLoader)
{
// Silenced; can be caught in custom error handlers.
@trigger_error(sprintf(
'Since laminas/laminas-mail 2.12.0: Usage of %s is deprecated; use %s::setHeaderLocator() instead',
__METHOD__,
__CLASS__
), E_USER_DEPRECATED);
$this->pluginClassLoader = $pluginClassLoader;
return $this;
}
/**
* Return a PluginClassLocator instance for customizing headers.
*
* Lazyloads a Header\HeaderLoader if necessary.
*
* @deprecated since 2.12.0
* @todo Remove for version 3.0.0
* @return PluginClassLocator
*/
public function getPluginClassLoader()
{
// Silenced; can be caught in custom error handlers.
@trigger_error(sprintf(
'Since laminas/laminas-mail 2.12.0: Usage of %s is deprecated; use %s::getHeaderLocator() instead',
__METHOD__,
__CLASS__
), E_USER_DEPRECATED);
if (! $this->pluginClassLoader) {
$this->pluginClassLoader = new Header\HeaderLoader();
}
return $this->pluginClassLoader;
}
/**
* Retrieve the header class locator for customizing headers.
*
* Lazyloads a Header\HeaderLocator instance if necessary.
*/
public function getHeaderLocator(): Header\HeaderLocatorInterface
{
if (! $this->headerLocator) {
$this->setHeaderLocator(new Header\HeaderLocator());
}
return $this->headerLocator;
}
/**
* @todo Return self when we update to 7.4 or later as minimum PHP version.
* @return $this
*/
public function setHeaderLocator(Header\HeaderLocatorInterface $headerLocator)
{
$this->headerLocator = $headerLocator;
return $this;
}
/**
* Set the header encoding
*
* @param string $encoding
* @return Headers
*/
public function setEncoding($encoding)
{
$this->encoding = $encoding;
foreach ($this as $header) {
$header->setEncoding($encoding);
}
return $this;
}
/**
* Get the header encoding
*
* @return string
*/
public function getEncoding()
{
return $this->encoding;
}
/**
* Add many headers at once
*
* Expects an array (or Traversable object) of type/value pairs.
*
* @param array|Traversable $headers
* @throws Exception\InvalidArgumentException
* @return Headers
*/
public function addHeaders($headers)
{
if (! is_array($headers) && ! $headers instanceof Traversable) {
throw new Exception\InvalidArgumentException(sprintf(
'Expected array or Traversable; received "%s"',
(is_object($headers) ? get_class($headers) : gettype($headers))
));
}
foreach ($headers as $name => $value) {
if (is_int($name)) {
if (is_string($value)) {
$this->addHeaderLine($value);
} elseif (is_array($value) && count($value) == 1) {
$this->addHeaderLine(key($value), current($value));
} elseif (is_array($value) && count($value) == 2) {
$this->addHeaderLine($value[0], $value[1]);
} elseif ($value instanceof Header\HeaderInterface) {
$this->addHeader($value);
}
} elseif (is_string($name)) {
$this->addHeaderLine($name, $value);
}
}
return $this;
}
/**
* Add a raw header line, either in name => value, or as a single string 'name: value'
*
* This method allows for lazy-loading in that the parsing and instantiation of HeaderInterface object
* will be delayed until they are retrieved by either get() or current()
*
* @throws Exception\InvalidArgumentException
* @param string $headerFieldNameOrLine
* @param string $fieldValue optional
* @return Headers
*/
public function addHeaderLine($headerFieldNameOrLine, $fieldValue = null)
{
if (! is_string($headerFieldNameOrLine)) {
throw new Exception\InvalidArgumentException(sprintf(
'%s expects its first argument to be a string; received "%s"',
__METHOD__,
(is_object($headerFieldNameOrLine)
? get_class($headerFieldNameOrLine)
: gettype($headerFieldNameOrLine))
));
}
if ($fieldValue === null) {
$headers = $this->loadHeader($headerFieldNameOrLine);
$headers = is_array($headers) ? $headers : [$headers];
foreach ($headers as $header) {
$this->addHeader($header);
}
} elseif (is_array($fieldValue)) {
foreach ($fieldValue as $i) {
$this->addHeader(Header\GenericMultiHeader::fromString($headerFieldNameOrLine . ':' . $i));
}
} else {
$this->addHeader(Header\GenericHeader::fromString($headerFieldNameOrLine . ':' . $fieldValue));
}
return $this;
}
/**
* Add a Header\Interface to this container, for raw values see {@link addHeaderLine()} and {@link addHeaders()}
*
* @param Header\HeaderInterface $header
* @return Headers
*/
public function addHeader(Header\HeaderInterface $header)
{
$key = $this->normalizeFieldName($header->getFieldName());
$this->headersKeys[] = $key;
$this->headers[] = $header;
if ($this->getEncoding() !== 'ASCII') {
$header->setEncoding($this->getEncoding());
}
return $this;
}
/**
* Remove a Header from the container
*
* @param string|Header\HeaderInterface field name or specific header instance to remove
* @return bool
*/
public function removeHeader($instanceOrFieldName)
{
if (! $instanceOrFieldName instanceof Header\HeaderInterface && ! is_string($instanceOrFieldName)) {
throw new Exception\InvalidArgumentException(sprintf(
'%s requires a string or %s instance; received %s',
__METHOD__,
Header\HeaderInterface::class,
is_object($instanceOrFieldName) ? get_class($instanceOrFieldName) : gettype($instanceOrFieldName)
));
}
if ($instanceOrFieldName instanceof Header\HeaderInterface) {
$indexes = array_keys($this->headers, $instanceOrFieldName, true);
}
if (is_string($instanceOrFieldName)) {
$key = $this->normalizeFieldName($instanceOrFieldName);
$indexes = array_keys($this->headersKeys, $key, true);
}
if (! empty($indexes)) {
foreach ($indexes as $index) {
unset($this->headersKeys[$index]);
unset($this->headers[$index]);
}
return true;
}
return false;
}
/**
* Clear all headers
*
* Removes all headers from queue
*
* @return Headers
*/
public function clearHeaders()
{
$this->headers = $this->headersKeys = [];
return $this;
}
/**
* Get all headers of a certain name/type
*
* @param string $name
* @return bool|ArrayIterator|Header\HeaderInterface Returns false if there is no headers with $name in this
* contain, an ArrayIterator if the header is a MultipleHeadersInterface instance and finally returns
* HeaderInterface for the rest of cases.
*/
public function get($name)
{
$key = $this->normalizeFieldName($name);
$results = [];
foreach (array_keys($this->headersKeys, $key) as $index) {
if ($this->headers[$index] instanceof Header\GenericHeader) {
$results[] = $this->lazyLoadHeader($index);
} else {
$results[] = $this->headers[$index];
}
}
switch (count($results)) {
case 0:
return false;
case 1:
if ($results[0] instanceof Header\MultipleHeadersInterface) {
return new ArrayIterator($results);
} else {
return $results[0];
}
//fall-trough
default:
return new ArrayIterator($results);
}
}
/**
* Test for existence of a type of header
*
* @param string $name
* @return bool
*/
public function has($name)
{
$name = $this->normalizeFieldName($name);
return in_array($name, $this->headersKeys);
}
/**
* Advance the pointer for this object as an iterator
*
*/
public function next()
{
next($this->headers);
}
/**
* Return the current key for this object as an iterator
*
* @return mixed
*/
public function key()
{
return key($this->headers);
}
/**
* Is this iterator still valid?
*
* @return bool
*/
public function valid()
{
return (current($this->headers) !== false);
}
/**
* Reset the internal pointer for this object as an iterator
*
*/
public function rewind()
{
reset($this->headers);
}
/**
* Return the current value for this iterator, lazy loading it if need be
*
* @return Header\HeaderInterface
*/
public function current()
{
$current = current($this->headers);
if ($current instanceof Header\GenericHeader) {
$current = $this->lazyLoadHeader(key($this->headers));
}
return $current;
}
/**
* Return the number of headers in this contain, if all headers have not been parsed, actual count could
* increase if MultipleHeader objects exist in the Request/Response. If you need an exact count, iterate
*
* @return int count of currently known headers
*/
public function count()
{
return count($this->headers);
}
/**
* Render all headers at once
*
* This method handles the normal iteration of headers; it is up to the
* concrete classes to prepend with the appropriate status/request line.
*
* @return string
*/
public function toString()
{
$headers = '';
foreach ($this as $header) {
if ($str = $header->toString()) {
$headers .= $str . self::EOL;
}
}
return $headers;
}
/**
* Return the headers container as an array
*
* @param bool $format Return the values in Mime::Encoded or in Raw format
* @return array
* @todo determine how to produce single line headers, if they are supported
*/
public function toArray($format = Header\HeaderInterface::FORMAT_RAW)
{
$headers = [];
/* @var $header Header\HeaderInterface */
foreach ($this->headers as $header) {
if ($header instanceof Header\MultipleHeadersInterface) {
$name = $header->getFieldName();
if (! isset($headers[$name])) {
$headers[$name] = [];
}
$headers[$name][] = $header->getFieldValue($format);
} else {
$headers[$header->getFieldName()] = $header->getFieldValue($format);
}
}
return $headers;
}
/**
* By calling this, it will force parsing and loading of all headers, after this count() will be accurate
*
* @return bool
*/
public function forceLoading()
{
foreach ($this as $item) {
// $item should now be loaded
}
return true;
}
/**
* Create Header object from header line
*
* @param string $headerLine
* @return Header\HeaderInterface|Header\HeaderInterface[]
*/
public function loadHeader($headerLine)
{
list($name, ) = Header\GenericHeader::splitHeaderLine($headerLine);
/** @var HeaderInterface $class */
$class = $this->resolveHeaderClass($name);
return $class::fromString($headerLine);
}
/**
* @param $index
* @return mixed
*/
protected function lazyLoadHeader($index)
{
$current = $this->headers[$index];
$key = $this->headersKeys[$index];
/** @var GenericHeader $class */
$class = $this->resolveHeaderClass($key);
$encoding = $current->getEncoding();
$headers = $class::fromString($current->toString());
if (is_array($headers)) {
$current = array_shift($headers);
$current->setEncoding($encoding);
$this->headers[$index] = $current;
foreach ($headers as $header) {
$header->setEncoding($encoding);
$this->headersKeys[] = $key;
$this->headers[] = $header;
}
return $current;
}
$current = $headers;
$current->setEncoding($encoding);
$this->headers[$index] = $current;
return $current;
}
/**
* Normalize a field name
*
* @param string $fieldName
* @return string
*/
protected function normalizeFieldName($fieldName)
{
return str_replace(['-', '_', ' ', '.'], '', strtolower($fieldName));
}
/**
* @param string $key
* @return string
*/
private function resolveHeaderClass($key)
{
if ($this->pluginClassLoader) {
return $this->pluginClassLoader->load($key) ?: Header\GenericHeader::class;
}
return $this->getHeaderLocator()->get($key, Header\GenericHeader::class);
}
}
PK kQ+ν " src/Exception/RuntimeException.phpnu ٘ .*)<(?P[^>]+)>|(?P.+))$/', $address, $matches)) {
throw new Exception\InvalidArgumentException('Invalid address format');
}
$name = null;
if (isset($matches['name'])) {
$name = trim($matches['name']);
}
if (empty($name)) {
$name = null;
}
if (isset($matches['namedEmail'])) {
$email = $matches['namedEmail'];
}
if (isset($matches['email'])) {
$email = $matches['email'];
}
$email = trim($email);
return new static($email, $name, $comment);
}
/**
* Constructor
*
* @param string $email
* @param null|string $name
* @param null|string $comment
* @throws Exception\InvalidArgumentException
*/
public function __construct($email, $name = null, $comment = null)
{
$emailAddressValidator = new EmailAddressValidator(Hostname::ALLOW_DNS | Hostname::ALLOW_LOCAL);
if (! is_string($email) || empty($email)) {
throw new Exception\InvalidArgumentException('Email must be a valid email address');
}
if (preg_match("/[\r\n]/", $email)) {
throw new Exception\InvalidArgumentException('CRLF injection detected');
}
if (! $emailAddressValidator->isValid($email)) {
$invalidMessages = $emailAddressValidator->getMessages();
throw new Exception\InvalidArgumentException(array_shift($invalidMessages));
}
if (null !== $name) {
if (! is_string($name)) {
throw new Exception\InvalidArgumentException('Name must be a string');
}
if (preg_match("/[\r\n]/", $name)) {
throw new Exception\InvalidArgumentException('CRLF injection detected');
}
$this->name = $name;
}
$this->email = $email;
if (null !== $comment) {
$this->comment = $comment;
}
}
/**
* Retrieve email
*
* @return string
*/
public function getEmail()
{
return $this->email;
}
/**
* Retrieve name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Retrieve comment, if any
*
* @return null|string
*/
public function getComment()
{
return $this->comment;
}
/**
* String representation of address
*
* @return string
*/
public function toString()
{
$string = sprintf('<%s>', $this->getEmail());
$name = $this->constructName();
if (null === $name) {
return $string;
}
return sprintf('%s %s', $name, $string);
}
/**
* Constructs the name string
*
* If a comment is present, appends the comment (commented using parens) to
* the name before returning it; otherwise, returns just the name.
*
* @return null|string
*/
private function constructName()
{
$name = $this->getName();
$comment = $this->getComment();
if ($comment === null || $comment === '') {
return $name;
}
$string = sprintf('%s (%s)', $name, $comment);
return trim($string);
}
}
PK kQ}cѷ src/AddressList.phpnu ٘ createAddress($emailOrAddress, $name);
}
if (! $emailOrAddress instanceof Address\AddressInterface) {
throw new Exception\InvalidArgumentException(sprintf(
'%s expects an email address or %s\Address object as its first argument; received "%s"',
__METHOD__,
__NAMESPACE__,
(is_object($emailOrAddress) ? get_class($emailOrAddress) : gettype($emailOrAddress))
));
}
$email = strtolower($emailOrAddress->getEmail());
if ($this->has($email)) {
return $this;
}
$this->addresses[$email] = $emailOrAddress;
return $this;
}
/**
* Add many addresses at once
*
* If an email key is provided, it will be used as the email, and the value
* as the name. Otherwise, the value is passed as the sole argument to add(),
* and, as such, can be either email strings or Address\AddressInterface objects.
*
* @param array $addresses
* @throws Exception\RuntimeException
* @return AddressList
*/
public function addMany(array $addresses)
{
foreach ($addresses as $key => $value) {
if (is_int($key) || is_numeric($key)) {
$this->add($value);
continue;
}
if (! is_string($key)) {
throw new Exception\RuntimeException(sprintf(
'Invalid key type in provided addresses array ("%s")',
(is_object($key) ? get_class($key) : var_export($key, 1))
));
}
$this->add($key, $value);
}
return $this;
}
/**
* Add an address to the list from any valid string format, such as
* - "Laminas Dev"
* - dev@laminas.com
*
* @param string $address
* @param null|string $comment Comment associated with the address, if any.
* @throws Exception\InvalidArgumentException
* @return AddressList
*/
public function addFromString($address, $comment = null)
{
$this->add(Address::fromString($address, $comment));
}
/**
* Merge another address list into this one
*
* @param AddressList $addressList
* @return AddressList
*/
public function merge(AddressList $addressList)
{
foreach ($addressList as $address) {
$this->add($address);
}
return $this;
}
/**
* Does the email exist in this list?
*
* @param string $email
* @return bool
*/
public function has($email)
{
$email = strtolower($email);
return isset($this->addresses[$email]);
}
/**
* Get an address by email
*
* @param string $email
* @return bool|Address\AddressInterface
*/
public function get($email)
{
$email = strtolower($email);
if (! isset($this->addresses[$email])) {
return false;
}
return $this->addresses[$email];
}
/**
* Delete an address from the list
*
* @param string $email
* @return bool
*/
public function delete($email)
{
$email = strtolower($email);
if (! isset($this->addresses[$email])) {
return false;
}
unset($this->addresses[$email]);
return true;
}
/**
* Return count of addresses
*
* @return int
*/
public function count()
{
return count($this->addresses);
}
/**
* Rewind iterator
*
* @return mixed the value of the first addresses element, or false if the addresses is
* empty.
* @see addresses
*/
public function rewind()
{
return reset($this->addresses);
}
/**
* Return current item in iteration
*
* @return Address
*/
public function current()
{
return current($this->addresses);
}
/**
* Return key of current item of iteration
*
* @return string
*/
public function key()
{
return key($this->addresses);
}
/**
* Move to next item
*
* @return mixed the addresses value in the next place that's pointed to by the
* internal array pointer, or false if there are no more elements.
* @see addresses
*/
public function next()
{
return next($this->addresses);
}
/**
* Is the current item of iteration valid?
*
* @return bool
*/
public function valid()
{
$key = key($this->addresses);
return ($key !== null && $key !== false);
}
/**
* Create an address object
*
* @param string $email
* @param string|null $name
* @return Address
*/
protected function createAddress($email, $name)
{
return new Address($email, $name);
}
}
PK kQ g src/Storage.phpnu ٘ from;
}
/**
* Set MAIL FROM
*
* @param string $from
*/
public function setFrom($from)
{
$this->from = (string) $from;
}
/**
* Get RCPT TO
*
* @return string|null
*/
public function getTo()
{
return $this->to;
}
/**
* Set RCPT TO
*
* @param string $to
*/
public function setTo($to)
{
$this->to = $to;
}
}
PK kQm , src/Transport/Exception/RuntimeException.phpnu ٘ setOptions($options);
}
/**
* @return FileOptions
*/
public function getOptions()
{
return $this->options;
}
/**
* Sets options
*
* @param FileOptions $options
*/
public function setOptions(FileOptions $options)
{
$this->options = $options;
}
/**
* Saves e-mail message to a file
*
* @param Message $message
* @throws Exception\RuntimeException on not writable target directory or
* on file_put_contents() failure
*/
public function send(Message $message)
{
$options = $this->options;
$filename = $options->getCallback()($this);
$file = $options->getPath() . DIRECTORY_SEPARATOR . $filename;
$email = $message->toString();
if (false === file_put_contents($file, $email)) {
throw new Exception\RuntimeException(sprintf(
'Unable to write mail to file (directory "%s")',
$options->getPath()
));
}
$this->lastFile = $file;
}
/**
* Get the name of the last file written to
*
* @return string
*/
public function getLastFile()
{
return $this->lastFile;
}
}
PK kQ+Di i src/Transport/FileOptions.phpnu ٘ path = $path;
return $this;
}
/**
* Get path
*
* If none is set, uses value from sys_get_temp_dir()
*
* @return string
*/
public function getPath()
{
if (null === $this->path) {
$this->setPath(sys_get_temp_dir());
}
return $this->path;
}
/**
* Set callback used to generate a file name
*
* @param callable $callback
* @throws \Laminas\Mail\Exception\InvalidArgumentException
* @return FileOptions
*/
public function setCallback($callback)
{
if (! is_callable($callback)) {
throw new Exception\InvalidArgumentException(sprintf(
'%s expects a valid callback; received "%s"',
__METHOD__,
(is_object($callback) ? get_class($callback) : gettype($callback))
));
}
$this->callback = $callback;
return $this;
}
/**
* Get callback used to generate a file name
*
* @return callable
*/
public function getCallback()
{
if (null === $this->callback) {
$this->setCallback(function () {
return 'LaminasMail_' . time() . '_' . mt_rand() . '.eml';
});
}
return $this->callback;
}
}
PK kQTc src/Transport/InMemory.phpnu ٘ lastMessage = $message;
}
/**
* Get the last message sent.
*
* @return null|Message
*/
public function getLastMessage()
{
return $this->lastMessage;
}
}
PK kQbVu
src/Transport/Factory.phpnu ٘ File::class,
'inmemory' => InMemory::class,
'memory' => InMemory::class,
'null' => InMemory::class,
'sendmail' => Sendmail::class,
'smtp' => Smtp::class,
];
/**
* @param array $spec
* @return TransportInterface
* @throws Exception\InvalidArgumentException
* @throws Exception\DomainException
*/
public static function create($spec = [])
{
if ($spec instanceof Traversable) {
$spec = ArrayUtils::iteratorToArray($spec);
}
if (! is_array($spec)) {
throw new Exception\InvalidArgumentException(sprintf(
'%s expects an array or Traversable argument; received "%s"',
__METHOD__,
(is_object($spec) ? get_class($spec) : gettype($spec))
));
}
$type = isset($spec['type']) ? $spec['type'] : 'sendmail';
$normalizedType = strtolower($type);
if (isset(static::$classMap[$normalizedType])) {
$type = static::$classMap[$normalizedType];
}
if (! class_exists($type)) {
throw new Exception\DomainException(sprintf(
'%s expects the "type" attribute to resolve to an existing class; received "%s"',
__METHOD__,
$type
));
}
$transport = new $type;
if (! $transport instanceof TransportInterface) {
throw new Exception\DomainException(sprintf(
'%s expects the "type" attribute to resolve to a valid %s instance; received "%s"',
__METHOD__,
TransportInterface::class,
$type
));
}
if ($transport instanceof Smtp && isset($spec['options'])) {
$transport->setOptions(new SmtpOptions($spec['options']));
}
if ($transport instanceof File && isset($spec['options'])) {
$transport->setOptions(new FileOptions($spec['options']));
}
return $transport;
}
}
PK kQmF src/Transport/SmtpOptions.phpnu ٘ name;
}
/**
* Set the local client hostname or IP
*
* @todo hostname/IP validation
* @param string $name
* @throws \Laminas\Mail\Exception\InvalidArgumentException
* @return SmtpOptions
*/
public function setName($name)
{
if (! is_string($name) && $name !== null) {
throw new Exception\InvalidArgumentException(sprintf(
'Name must be a string or null; argument of type "%s" provided',
(is_object($name) ? get_class($name) : gettype($name))
));
}
$this->name = $name;
return $this;
}
/**
* Get connection class
*
* This should be either the class Laminas\Mail\Protocol\Smtp or a class
* extending it -- typically a class in the Laminas\Mail\Protocol\Smtp\Auth
* namespace.
*
* @return string
*/
public function getConnectionClass()
{
return $this->connectionClass;
}
/**
* Set connection class
*
* @param string $connectionClass the value to be set
* @throws \Laminas\Mail\Exception\InvalidArgumentException
* @return SmtpOptions
*/
public function setConnectionClass($connectionClass)
{
if (! is_string($connectionClass) && $connectionClass !== null) {
throw new Exception\InvalidArgumentException(sprintf(
'Connection class must be a string or null; argument of type "%s" provided',
(is_object($connectionClass) ? get_class($connectionClass) : gettype($connectionClass))
));
}
$this->connectionClass = $connectionClass;
return $this;
}
/**
* Get connection configuration array
*
* @return array
*/
public function getConnectionConfig()
{
return $this->connectionConfig;
}
/**
* Set connection configuration array
*
* @param array $connectionConfig
* @return SmtpOptions
*/
public function setConnectionConfig(array $connectionConfig)
{
$this->connectionConfig = $connectionConfig;
return $this;
}
/**
* Get the host name
*
* @return string
*/
public function getHost()
{
return $this->host;
}
/**
* Set the SMTP host
*
* @todo hostname/IP validation
* @param string $host
* @return SmtpOptions
*/
public function setHost($host)
{
$this->host = (string) $host;
return $this;
}
/**
* Get the port the SMTP server runs on
*
* @return int
*/
public function getPort()
{
return $this->port;
}
/**
* Set the port the SMTP server runs on
*
* @param int $port
* @throws \Laminas\Mail\Exception\InvalidArgumentException
* @return SmtpOptions
*/
public function setPort($port)
{
$port = (int) $port;
if ($port < 1) {
throw new Exception\InvalidArgumentException(sprintf(
'Port must be greater than 1; received "%d"',
$port
));
}
$this->port = $port;
return $this;
}
/**
* @return int|null
*/
public function getConnectionTimeLimit()
{
return $this->connectionTimeLimit;
}
/**
* @param int|null $seconds
* @return self
*/
public function setConnectionTimeLimit($seconds)
{
$this->connectionTimeLimit = $seconds === null
? null
: (int) $seconds;
return $this;
}
}
PK kQso' ' src/Transport/Smtp.phpnu ٘ 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 options
*
* @param Envelope $envelope
*/
public function setEnvelope(Envelope $envelope)
{
$this->envelope = $envelope;
}
/**
* Get envelope
*
* @return Envelope|null
*/
public function getEnvelope()
{
return $this->envelope;
}
/**
* 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(new ServiceManager()));
}
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->getConnection() instanceof Protocol\Smtp) {
return;
}
try {
$this->getConnection()->quit();
} catch (ProtocolException\ExceptionInterface $e) {
// ignore
}
if ($this->autoDisconnect) {
$this->getConnection()->disconnect();
}
}
/**
* Sets the connection protocol instance
*
* @param Protocol\AbstractProtocol $connection
*/
public function setConnection(Protocol\AbstractProtocol $connection)
{
$this->connection = $connection;
if (($connection instanceof Protocol\Smtp)
&& ($this->getOptions()->getConnectionTimeLimit() !== null)
) {
$connection->setUseCompleteQuit(false);
}
}
/**
* Gets the connection protocol instance
*
* @return Protocol\Smtp
*/
public function getConnection()
{
$timeLimit = $this->getOptions()->getConnectionTimeLimit();
if ($timeLimit !== null
&& $this->connectedTime !== null
&& ((time() - $this->connectedTime) > $timeLimit)
) {
$this->connection = null;
}
return $this->connection;
}
/**
* Disconnect the connection protocol instance
*
* @return void
*/
public function disconnect()
{
if ($this->getConnection() instanceof Protocol\Smtp) {
$this->getConnection()->disconnect();
$this->connectedTime = null;
}
}
/**
* 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))) {
// Per RFC 2821 3.3 (page 18)
throw new Exception\RuntimeException(
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)
{
if ($this->getEnvelope() && $this->getEnvelope()->getFrom()) {
return $this->getEnvelope()->getFrom();
}
$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)
{
if ($this->getEnvelope() && $this->getEnvelope()->getTo()) {
return (array) $this->getEnvelope()->getTo();
}
$recipients = [];
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();
$this->setConnection($this->plugin($options->getConnectionClass(), $config));
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->connectedTime = time();
$this->connection->helo($this->getOptions()->getName());
return $this->connection;
}
}
PK kQ!-'&