3 * @see https://github.com/zendframework/zend-mail for the canonical source repository
4 * @copyright Copyright (c) 2005-2018 Zend Technologies USA Inc. (https://www.zend.com)
5 * @license https://github.com/zendframework/zend-mail/blob/master/LICENSE.md New BSD License
11 use Zend\Mail\Header\ContentType
;
12 use Zend\Mail\Header\Sender
;
18 * Content of the message
20 * @var string|object|Mime\Message
32 * Used to determine whether or not to encode headers; defaults to ASCII.
36 protected $encoding = 'ASCII';
39 * Is the message valid?
41 * If we don't any From addresses, we're invalid, according to RFC2822.
45 public function isValid()
47 $from = $this->getFrom();
48 if (! $from instanceof AddressList
) {
51 return (bool) count($from);
55 * Set the message encoding
57 * @param string $encoding
60 public function setEncoding($encoding)
62 $this->encoding
= $encoding;
63 $this->getHeaders()->setEncoding($encoding);
68 * Get the message encoding
72 public function getEncoding()
74 return $this->encoding
;
80 * @param Headers $headers
83 public function setHeaders(Headers
$headers)
85 $this->headers
= $headers;
86 $headers->setEncoding($this->getEncoding());
91 * Access headers collection
93 * Lazy-loads if not already attached.
97 public function getHeaders()
99 if (null === $this->headers
) {
100 $this->setHeaders(new Headers());
101 $date = Header\Date
::fromString('Date: ' . date('r'));
102 $this->headers
->addHeader($date);
104 return $this->headers
;
108 * Set (overwrite) From addresses
110 * @param string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressList
111 * @param string|null $name
114 public function setFrom($emailOrAddressList, $name = null)
116 $this->clearHeaderByName('from');
117 return $this->addFrom($emailOrAddressList, $name);
121 * Add a "From" address
123 * @param string|Address|array|AddressList|Traversable $emailOrAddressOrList
124 * @param string|null $name
127 public function addFrom($emailOrAddressOrList, $name = null)
129 $addressList = $this->getFrom();
130 $this->updateAddressList($addressList, $emailOrAddressOrList, $name, __METHOD__
);
135 * Retrieve list of From senders
137 * @return AddressList
139 public function getFrom()
141 return $this->getAddressListFromHeader('from', __NAMESPACE__
. '\Header\From');
145 * Overwrite the address list in the To recipients
147 * @param string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressList
148 * @param null|string $name
151 public function setTo($emailOrAddressList, $name = null)
153 $this->clearHeaderByName('to');
154 return $this->addTo($emailOrAddressList, $name);
158 * Add one or more addresses to the To recipients
160 * Appends to the list.
162 * @param string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressOrList
163 * @param null|string $name
166 public function addTo($emailOrAddressOrList, $name = null)
168 $addressList = $this->getTo();
169 $this->updateAddressList($addressList, $emailOrAddressOrList, $name, __METHOD__
);
174 * Access the address list of the To header
176 * @return AddressList
178 public function getTo()
180 return $this->getAddressListFromHeader('to', __NAMESPACE__
. '\Header\To');
184 * Set (overwrite) CC addresses
186 * @param string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressList
187 * @param string|null $name
190 public function setCc($emailOrAddressList, $name = null)
192 $this->clearHeaderByName('cc');
193 return $this->addCc($emailOrAddressList, $name);
199 * @param string|Address|array|AddressList|Traversable $emailOrAddressOrList
200 * @param string|null $name
203 public function addCc($emailOrAddressOrList, $name = null)
205 $addressList = $this->getCc();
206 $this->updateAddressList($addressList, $emailOrAddressOrList, $name, __METHOD__
);
211 * Retrieve list of CC recipients
213 * @return AddressList
215 public function getCc()
217 return $this->getAddressListFromHeader('cc', __NAMESPACE__
. '\Header\Cc');
221 * Set (overwrite) BCC addresses
223 * @param string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressList
224 * @param string|null $name
227 public function setBcc($emailOrAddressList, $name = null)
229 $this->clearHeaderByName('bcc');
230 return $this->addBcc($emailOrAddressList, $name);
234 * Add a "Bcc" address
236 * @param string|Address|array|AddressList|Traversable $emailOrAddressOrList
237 * @param string|null $name
240 public function addBcc($emailOrAddressOrList, $name = null)
242 $addressList = $this->getBcc();
243 $this->updateAddressList($addressList, $emailOrAddressOrList, $name, __METHOD__
);
248 * Retrieve list of BCC recipients
250 * @return AddressList
252 public function getBcc()
254 return $this->getAddressListFromHeader('bcc', __NAMESPACE__
. '\Header\Bcc');
258 * Overwrite the address list in the Reply-To recipients
260 * @param string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressList
261 * @param null|string $name
264 public function setReplyTo($emailOrAddressList, $name = null)
266 $this->clearHeaderByName('reply-to');
267 return $this->addReplyTo($emailOrAddressList, $name);
271 * Add one or more addresses to the Reply-To recipients
273 * Appends to the list.
275 * @param string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressOrList
276 * @param null|string $name
279 public function addReplyTo($emailOrAddressOrList, $name = null)
281 $addressList = $this->getReplyTo();
282 $this->updateAddressList($addressList, $emailOrAddressOrList, $name, __METHOD__
);
287 * Access the address list of the Reply-To header
289 * @return AddressList
291 public function getReplyTo()
293 return $this->getAddressListFromHeader('reply-to', __NAMESPACE__
. '\Header\ReplyTo');
299 * @param mixed $emailOrAddress
303 public function setSender($emailOrAddress, $name = null)
305 /** @var Sender $header */
306 $header = $this->getHeaderByName('sender', __NAMESPACE__
. '\Header\Sender');
307 $header->setAddress($emailOrAddress, $name);
312 * Retrieve the sender address, if any
314 * @return null|Address\AddressInterface
316 public function getSender()
318 $headers = $this->getHeaders();
319 if (! $headers->has('sender')) {
323 /** @var Sender $header */
324 $header = $this->getHeaderByName('sender', __NAMESPACE__
. '\Header\Sender');
325 return $header->getAddress();
329 * Set the message subject header value
331 * @param string $subject
334 public function setSubject($subject)
336 $headers = $this->getHeaders();
337 if (! $headers->has('subject')) {
338 $header = new Header\
Subject();
339 $headers->addHeader($header);
341 $header = $headers->get('subject');
343 $header->setSubject($subject);
348 * Get the message subject header value
350 * @return null|string
352 public function getSubject()
354 $headers = $this->getHeaders();
355 if (! $headers->has('subject')) {
358 $header = $headers->get('subject');
359 return $header->getFieldValue();
363 * Set the message body
365 * @param null|string|\Zend\Mime\Message|object $body
366 * @throws Exception\InvalidArgumentException
369 public function setBody($body)
371 if (! is_string($body) && $body !== null) {
372 if (! is_object($body)) {
373 throw new Exception\
InvalidArgumentException(sprintf(
374 '%s expects a string or object argument; received "%s"',
379 if (! $body instanceof Mime\Message
) {
380 if (! method_exists($body, '__toString')) {
381 throw new Exception\
InvalidArgumentException(sprintf(
382 '%s expects object arguments of type Zend\Mime\Message or implementing __toString();'
383 . ' object of type "%s" received',
392 if (! $this->body
instanceof Mime\Message
) {
396 // Get headers, and set Mime-Version header
397 $headers = $this->getHeaders();
398 $this->getHeaderByName('mime-version', __NAMESPACE__
. '\Header\MimeVersion');
400 // Multipart content headers
401 if ($this->body
->isMultiPart()) {
402 $mime = $this->body
->getMime();
404 /** @var ContentType $header */
405 $header = $this->getHeaderByName('content-type', __NAMESPACE__
. '\Header\ContentType');
406 $header->setType('multipart/mixed');
407 $header->addParameter('boundary', $mime->boundary());
411 // MIME single part headers
412 $parts = $this->body
->getParts();
413 if (! empty($parts)) {
414 $part = array_shift($parts);
415 $headers->addHeaders($part->getHeadersArray("\r\n"));
421 * Return the currently set message body
423 * @return object|string|Mime\Message
425 public function getBody()
431 * Get the string-serialized message body text
435 public function getBodyText()
437 if ($this->body
instanceof Mime\Message
) {
438 return $this->body
->generateMessage(Headers
::EOL
);
441 return (string) $this->body
;
445 * Retrieve a header by name
447 * If not found, instantiates one based on $headerClass.
449 * @param string $headerName
450 * @param string $headerClass
451 * @return Header\HeaderInterface|\ArrayIterator header instance or collection of headers
453 protected function getHeaderByName($headerName, $headerClass)
455 $headers = $this->getHeaders();
456 if ($headers->has($headerName)) {
457 $header = $headers->get($headerName);
459 $header = new $headerClass();
460 $headers->addHeader($header);
466 * Clear a header by name
468 * @param string $headerName
470 protected function clearHeaderByName($headerName)
472 $this->getHeaders()->removeHeader($headerName);
476 * Retrieve the AddressList from a named header
478 * Used with To, From, Cc, Bcc, and ReplyTo headers. If the header does not
479 * exist, instantiates it.
481 * @param string $headerName
482 * @param string $headerClass
483 * @throws Exception\DomainException
484 * @return AddressList
486 protected function getAddressListFromHeader($headerName, $headerClass)
488 $header = $this->getHeaderByName($headerName, $headerClass);
489 if (! $header instanceof Header\AbstractAddressList
) {
490 throw new Exception\
DomainException(sprintf(
491 'Cannot grab address list from header of type "%s"; not an AbstractAddressList implementation',
495 return $header->getAddressList();
499 * Update an address list
501 * Proxied to this from addFrom, addTo, addCc, addBcc, and addReplyTo.
503 * @param AddressList $addressList
504 * @param string|Address\AddressInterface|array|AddressList|Traversable $emailOrAddressOrList
505 * @param null|string $name
506 * @param string $callingMethod
507 * @throws Exception\InvalidArgumentException
509 protected function updateAddressList(AddressList
$addressList, $emailOrAddressOrList, $name, $callingMethod)
511 if ($emailOrAddressOrList instanceof Traversable
) {
512 foreach ($emailOrAddressOrList as $address) {
513 $addressList->add($address);
517 if (is_array($emailOrAddressOrList)) {
518 $addressList->addMany($emailOrAddressOrList);
521 if (! is_string($emailOrAddressOrList) && ! $emailOrAddressOrList instanceof Address\AddressInterface
) {
522 throw new Exception\
InvalidArgumentException(sprintf(
523 '%s expects a string, AddressInterface, array, AddressList, or Traversable as its first argument;'
526 (is_object($emailOrAddressOrList) ?
get_class($emailOrAddressOrList) : gettype($emailOrAddressOrList))
530 if (is_string($emailOrAddressOrList) && $name === null) {
531 $addressList->addFromString($emailOrAddressOrList);
535 $addressList->add($emailOrAddressOrList, $name);
539 * Serialize to string
543 public function toString()
545 $headers = $this->getHeaders();
546 return $headers->toString()
548 . $this->getBodyText();
552 * Instantiate from raw message string
554 * @todo Restore body to Mime\Message
555 * @param string $rawMessage
558 public static function fromString($rawMessage)
560 $message = new static();
562 /** @var Headers $headers */
565 Mime\Decode
::splitMessage($rawMessage, $headers, $content, Headers
::EOL
);
566 if ($headers->has('mime-version')) {
567 // todo - restore body to mime\message
569 $message->setHeaders($headers);
570 $message->setBody($content);