See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 39 and 401]
1 <?php 2 /** 3 * Copyright 2007-2017 Horde LLC (http://www.horde.org/) 4 * 5 * See the enclosed file LICENSE for license information (LGPL). If you 6 * did not receive this file, see http://www.horde.org/licenses/lgpl21. 7 * 8 * @category Horde 9 * @copyright 2007-2017 Horde LLC 10 * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 11 * @package Mime 12 */ 13 14 /** 15 * The Horde_Mime_Mail:: class wraps around the various MIME library classes 16 * to provide a simple interface for creating and sending MIME messages. 17 * 18 * All content has to be passed UTF-8 encoded. The charset parameters is used 19 * for the generated message only. 20 * 21 * @author Jan Schneider <jan@horde.org> 22 * @category Horde 23 * @copyright 2007-2017 Horde LLC 24 * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 25 * @package Mime 26 */ 27 class Horde_Mime_Mail 28 { 29 /** 30 * The message headers. 31 * 32 * @var Horde_Mime_Headers 33 */ 34 protected $_headers; 35 36 /** 37 * The base MIME part. 38 * 39 * @var Horde_Mime_Part 40 */ 41 protected $_base; 42 43 /** 44 * The main body part. 45 * 46 * @var Horde_Mime_Part 47 */ 48 protected $_body; 49 50 /** 51 * The main HTML body part. 52 * 53 * @var Horde_Mime_Part 54 */ 55 protected $_htmlBody; 56 57 /** 58 * The message recipients. 59 * 60 * @var Horde_Mail_Rfc822_List 61 */ 62 protected $_recipients; 63 64 /** 65 * Bcc recipients. 66 * 67 * @var string 68 */ 69 protected $_bcc; 70 71 /** 72 * All MIME parts except the main body part. 73 * 74 * @var array 75 */ 76 protected $_parts = array(); 77 78 /** 79 * The Mail driver name. 80 * 81 * @link http://pear.php.net/Mail 82 * @var string 83 */ 84 protected $_mailer_driver = 'smtp'; 85 86 /** 87 * The charset to use for the message. 88 * 89 * @var string 90 */ 91 protected $_charset = 'UTF-8'; 92 93 /** 94 * The Mail driver parameters. 95 * 96 * @link http://pear.php.net/Mail 97 * @var array 98 */ 99 protected $_mailer_params = array(); 100 101 /** 102 * Constructor. 103 * 104 * @param array $params A hash with basic message information. 'charset' 105 * is the character set of the message. 'body' is 106 * the message body. All other parameters are 107 * assumed to be message headers. 108 * 109 * @throws Horde_Mime_Exception 110 */ 111 public function __construct($params = array()) 112 { 113 /* Set SERVER_NAME. */ 114 if (!isset($_SERVER['SERVER_NAME'])) { 115 $_SERVER['SERVER_NAME'] = php_uname('n'); 116 } 117 118 $this->_headers = new Horde_Mime_Headers(); 119 120 if (isset($params['charset'])) { 121 $this->_charset = $params['charset']; 122 unset($params['charset']); 123 } 124 125 if (isset($params['body'])) { 126 $this->setBody($params['body'], $this->_charset); 127 unset($params['body']); 128 } 129 130 $this->addHeaders($params); 131 132 $this->clearRecipients(); 133 } 134 135 /** 136 * Adds several message headers at once. 137 * 138 * @param array $header Hash with header names as keys and header 139 * contents as values. 140 * 141 * @throws Horde_Mime_Exception 142 */ 143 public function addHeaders($headers = array()) 144 { 145 foreach ($headers as $header => $value) { 146 $this->addHeader($header, $value); 147 } 148 } 149 150 /** 151 * Adds a message header. 152 * 153 * @param string $header The header name. 154 * @param string $value The header value. 155 * @param boolean $overwrite If true, an existing header of the same name 156 * is being overwritten; if false, multiple 157 * headers are added; if null, the correct 158 * behaviour is automatically chosen depending 159 * on the header name. 160 * 161 * @throws Horde_Mime_Exception 162 */ 163 public function addHeader($header, $value, $overwrite = null) 164 { 165 $lc_header = Horde_String::lower($header); 166 167 if (is_null($overwrite) && 168 in_array($lc_header, $this->_headers->singleFields(true))) { 169 $overwrite = true; 170 } 171 172 if ($overwrite) { 173 $this->_headers->removeHeader($header); 174 } 175 176 if ($lc_header === 'bcc') { 177 $this->_bcc = $value; 178 } else { 179 $this->_headers->addHeader($header, $value); 180 } 181 } 182 183 /** 184 * Add a Horde_Mime_Headers_Element object to the current header list. 185 * 186 * @since 2.5.0 187 * 188 * @param Horde_Mime_Headers_Element $ob Header object to add. 189 * 190 * @throws InvalidArgumentException 191 */ 192 public function addHeaderOb(Horde_Mime_Headers_Element $ob) 193 { 194 $this->_headers->addHeaderOb($ob, true); 195 } 196 197 /** 198 * Removes a message header. 199 * 200 * @param string $header The header name. 201 */ 202 public function removeHeader($header) 203 { 204 if (Horde_String::lower($header) === 'bcc') { 205 unset($this->_bcc); 206 } else { 207 $this->_headers->removeHeader($header); 208 } 209 } 210 211 /** 212 * Sets the message body text. 213 * 214 * @param string $body The message content. 215 * @param string $charset The character set of the message. 216 * @param boolean|integer $wrap If true, wrap the message at column 76; 217 * If an integer wrap the message at that 218 * column. Don't use wrapping if sending 219 * flowed messages. 220 */ 221 public function setBody($body, $charset = null, $wrap = false) 222 { 223 if (!$charset) { 224 $charset = $this->_charset; 225 } 226 $body = Horde_String::convertCharset($body, 'UTF-8', $charset); 227 if ($wrap) { 228 $body = Horde_String::wrap($body, $wrap === true ? 76 : $wrap); 229 } 230 $this->_body = new Horde_Mime_Part(); 231 $this->_body->setType('text/plain'); 232 $this->_body->setCharset($charset); 233 $this->_body->setContents($body); 234 $this->_base = null; 235 } 236 237 /** 238 * Sets the HTML message body text. 239 * 240 * @param string $body The message content. 241 * @param string $charset The character set of the message. 242 * @param boolean $alternative If true, a multipart/alternative message is 243 * created and the text/plain part is 244 * generated automatically. If false, a 245 * text/html message is generated. 246 */ 247 public function setHtmlBody($body, $charset = null, $alternative = true) 248 { 249 if (!$charset) { 250 $charset = $this->_charset; 251 } 252 $this->_htmlBody = new Horde_Mime_Part(); 253 $this->_htmlBody->setType('text/html'); 254 $this->_htmlBody->setCharset($charset); 255 $this->_htmlBody->setContents($body); 256 if ($alternative) { 257 $this->setBody(Horde_Text_Filter::filter($body, 'Html2text', array('charset' => $charset, 'wrap' => false)), $charset); 258 } 259 $this->_base = null; 260 } 261 262 /** 263 * Adds a message part. 264 * 265 * @param string $mime_type The content type of the part. 266 * @param string $content The content of the part. 267 * @param string $charset The character set of the part. 268 * @param string $disposition The content disposition of the part. 269 * 270 * @return integer The part number. 271 */ 272 public function addPart($mime_type, $content, $charset = 'us-ascii', 273 $disposition = null) 274 { 275 $part = new Horde_Mime_Part(); 276 $part->setType($mime_type); 277 $part->setCharset($charset); 278 $part->setDisposition($disposition); 279 $part->setContents($content); 280 return $this->addMimePart($part); 281 } 282 283 /** 284 * Adds a MIME message part. 285 * 286 * @param Horde_Mime_Part $part A Horde_Mime_Part object. 287 * 288 * @return integer The part number. 289 */ 290 public function addMimePart($part) 291 { 292 $this->_parts[] = $part; 293 return count($this->_parts) - 1; 294 } 295 296 /** 297 * Sets the base MIME part. 298 * 299 * If the base part is set, any text bodies will be ignored when building 300 * the message. 301 * 302 * @param Horde_Mime_Part $part A Horde_Mime_Part object. 303 */ 304 public function setBasePart($part) 305 { 306 $this->_base = $part; 307 } 308 309 /** 310 * Adds an attachment. 311 * 312 * @param string $file The path to the file. 313 * @param string $name The file name to use for the attachment. 314 * @param string $type The content type of the file. 315 * @param string $charset The character set of the part (only relevant for 316 * text parts. 317 * 318 * @return integer The part number. 319 */ 320 public function addAttachment($file, $name = null, $type = null, 321 $charset = 'us-ascii') 322 { 323 if (empty($name)) { 324 $name = basename($file); 325 } 326 327 if (empty($type)) { 328 $type = Horde_Mime_Magic::filenameToMime($file, false); 329 } 330 331 $num = $this->addPart($type, file_get_contents($file), $charset, 'attachment'); 332 $this->_parts[$num]->setName($name); 333 return $num; 334 } 335 336 /** 337 * Removes a message part. 338 * 339 * @param integer $part The part number. 340 */ 341 public function removePart($part) 342 { 343 if (isset($this->_parts[$part])) { 344 unset($this->_parts[$part]); 345 } 346 } 347 348 /** 349 * Removes all (additional) message parts but leaves the body parts 350 * untouched. 351 */ 352 public function clearParts() 353 { 354 $this->_parts = array(); 355 } 356 357 /** 358 * Adds message recipients. 359 * 360 * Recipients specified by To:, Cc:, or Bcc: headers are added 361 * automatically. 362 * 363 * @param string|array List of recipients, either as a comma separated 364 * list or as an array of email addresses. 365 * 366 * @throws Horde_Mime_Exception 367 */ 368 public function addRecipients($recipients) 369 { 370 $this->_recipients->add($recipients); 371 } 372 373 /** 374 * Removes message recipients. 375 * 376 * @param string|array List of recipients, either as a comma separated 377 * list or as an array of email addresses. 378 * 379 * @throws Horde_Mime_Exception 380 */ 381 public function removeRecipients($recipients) 382 { 383 $this->_recipients->remove($recipients); 384 } 385 386 /** 387 * Removes all message recipients. 388 */ 389 public function clearRecipients() 390 { 391 $this->_recipients = new Horde_Mail_Rfc822_List(); 392 } 393 394 /** 395 * Sends this message. 396 * 397 * @param Horde_Mail_Transport $mailer A Horde_Mail_Transport object. 398 * @param boolean $resend If true, the message id and date are re-used; 399 * If false, they will be updated. 400 * @param boolean $flowed Send message in flowed text format. 401 * 402 * @throws Horde_Mime_Exception 403 */ 404 public function send($mailer, $resend = false, $flowed = true) 405 { 406 /* Add mandatory headers if missing. */ 407 if (!$resend || !isset($this->_headers['Message-ID'])) { 408 $this->_headers->addHeaderOb( 409 Horde_Mime_Headers_MessageId::create() 410 ); 411 } 412 if (!isset($this->_headers['User-Agent'])) { 413 $this->_headers->addHeaderOb( 414 Horde_Mime_Headers_UserAgent::create() 415 ); 416 } 417 if (!$resend || !isset($this->_headers['Date'])) { 418 $this->_headers->addHeaderOb(Horde_Mime_Headers_Date::create()); 419 } 420 421 if (isset($this->_base)) { 422 $basepart = $this->_base; 423 } else { 424 /* Send in flowed format. */ 425 if ($flowed && !empty($this->_body)) { 426 $flowed = new Horde_Text_Flowed($this->_body->getContents(), $this->_body->getCharset()); 427 $flowed->setDelSp(true); 428 $this->_body->setContentTypeParameter('format', 'flowed'); 429 $this->_body->setContentTypeParameter('DelSp', 'Yes'); 430 $this->_body->setContents($flowed->toFlowed()); 431 } 432 433 /* Build mime message. */ 434 $body = new Horde_Mime_Part(); 435 if (!empty($this->_body) && !empty($this->_htmlBody)) { 436 $body->setType('multipart/alternative'); 437 $this->_body->setDescription(Horde_Mime_Translation::t("Plaintext Version of Message")); 438 $body[] = $this->_body; 439 $this->_htmlBody->setDescription(Horde_Mime_Translation::t("HTML Version of Message")); 440 $body[] = $this->_htmlBody; 441 } elseif (!empty($this->_htmlBody)) { 442 $body = $this->_htmlBody; 443 } elseif (!empty($this->_body)) { 444 $body = $this->_body; 445 } 446 if (count($this->_parts)) { 447 $basepart = new Horde_Mime_Part(); 448 $basepart->setType('multipart/mixed'); 449 $basepart->isBasePart(true); 450 if ($body) { 451 $basepart[] = $body; 452 } 453 foreach ($this->_parts as $mime_part) { 454 $basepart[] = $mime_part; 455 } 456 } else { 457 $basepart = $body; 458 $basepart->isBasePart(true); 459 } 460 } 461 $basepart->setHeaderCharset($this->_charset); 462 463 /* Build recipients. */ 464 $recipients = clone $this->_recipients; 465 foreach (array('to', 'cc') as $header) { 466 if ($h = $this->_headers[$header]) { 467 $recipients->add($h->getAddressList()); 468 } 469 } 470 if ($this->_bcc) { 471 $recipients->add($this->_bcc); 472 } 473 474 /* Trick Horde_Mime_Part into re-generating the message headers. */ 475 $this->_headers->removeHeader('MIME-Version'); 476 477 /* Send message. */ 478 $recipients->unique(); 479 $basepart->send($recipients->writeAddress(), $this->_headers, $mailer); 480 481 /* Remember the basepart */ 482 $this->_base = $basepart; 483 } 484 485 /** 486 * Get the raw email data sent by this object. 487 * 488 * @param boolean $stream If true, return a stream resource, otherwise 489 * a string is returned. 490 * 491 * @return resource|string The raw email data. 492 * @since 2.4.0 493 */ 494 public function getRaw($stream = true) 495 { 496 if ($stream) { 497 $hdr = new Horde_Stream(); 498 $hdr->add($this->_headers->toString(), true); 499 return Horde_Stream_Wrapper_Combine::getStream( 500 array($hdr->stream, 501 $this->getBasePart()->toString( 502 array('stream' => true, 'encode' => Horde_Mime_Part::ENCODE_7BIT | Horde_Mime_Part::ENCODE_8BIT | Horde_Mime_Part::ENCODE_BINARY)) 503 ) 504 ); 505 } 506 507 return $this->_headers->toString() . $this->getBasePart()->toString(); 508 } 509 510 /** 511 * Return the base MIME part. 512 * 513 * @return Horde_Mime_Part 514 */ 515 public function getBasePart() 516 { 517 if (empty($this->_base)) { 518 throw new Horde_Mail_Exception('No base part set.'); 519 } 520 521 return $this->_base; 522 } 523 524 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body