CakePHP
  • Documentation
    • Book
    • API
    • Videos
    • Reporting Security Issues
    • Privacy Policy
    • Logos & Trademarks
  • Business Solutions
  • Swag
  • Road Trip
  • Team
  • Community
    • Community
    • Get Involved
    • Issues (GitHub)
    • Bakery
    • Featured Resources
    • Training
    • Meetups
    • My CakePHP
    • CakeFest
    • Newsletter
    • Linkedin
    • YouTube
    • Facebook
    • Twitter
    • Mastodon
    • Help & Support
    • Forum
    • Stack Overflow
    • Slack
    • Paid Support
CakePHP

C CakePHP 2.2 API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 2.2
      • 4.2
      • 4.1
      • 4.0
      • 3.9
      • 3.8
      • 3.7
      • 3.6
      • 3.5
      • 3.4
      • 3.3
      • 3.2
      • 3.1
      • 3.0
      • 2.10
      • 2.9
      • 2.8
      • 2.7
      • 2.6
      • 2.5
      • 2.4
      • 2.3
      • 2.2
      • 2.1
      • 2.0
      • 1.3
      • 1.2

Packages

  • Cake
    • Cache
      • Engine
    • Configure
    • Console
      • Command
        • Task
    • Controller
      • Component
        • Acl
        • Auth
    • Core
    • Error
    • Event
    • I18n
    • Log
      • Engine
    • Model
      • Behavior
      • Datasource
        • Database
        • Session
      • Validator
    • Network
      • Email
      • Http
    • Routing
      • Filter
      • Route
    • TestSuite
      • Coverage
      • Fixture
      • Reporter
    • Utility
    • View
      • Helper

Classes

  • AbstractTransport
  • CakeEmail
  • DebugTransport
  • MailTransport
  • SmtpTransport
   1: <?php
   2: /**
   3:  * Cake E-Mail
   4:  *
   5:  * PHP 5
   6:  *
   7:  * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
   8:  * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
   9:  *
  10:  * Licensed under The MIT License
  11:  * Redistributions of files must retain the above copyright notice.
  12:  *
  13:  * @copyright     Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
  14:  * @link          http://cakephp.org CakePHP(tm) Project
  15:  * @package       Cake.Network.Email
  16:  * @since         CakePHP(tm) v 2.0.0
  17:  * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
  18:  */
  19: 
  20: App::uses('Validation', 'Utility');
  21: App::uses('Multibyte', 'I18n');
  22: App::uses('AbstractTransport', 'Network/Email');
  23: App::uses('String', 'Utility');
  24: App::uses('View', 'View');
  25: App::import('I18n', 'Multibyte');
  26: 
  27: /**
  28:  * Cake e-mail class.
  29:  *
  30:  * This class is used for handling Internet Message Format based
  31:  * based on the standard outlined in http://www.rfc-editor.org/rfc/rfc2822.txt
  32:  *
  33:  * @package       Cake.Network.Email
  34:  */
  35: class CakeEmail {
  36: /**
  37:  * Default X-Mailer
  38:  *
  39:  * @constant EMAIL_CLIENT
  40:  */
  41:     const EMAIL_CLIENT = 'CakePHP Email';
  42: 
  43: /**
  44:  * Line length - no should more - RFC 2822 - 2.1.1
  45:  *
  46:  * @constant LINE_LENGTH_SHOULD
  47:  */
  48:     const LINE_LENGTH_SHOULD = 78;
  49: 
  50: /**
  51:  * Line length - no must more - RFC 2822 - 2.1.1
  52:  *
  53:  * @constant LINE_LENGTH_MUST
  54:  */
  55:     const LINE_LENGTH_MUST = 998;
  56: 
  57: /**
  58:  * Type of message - HTML
  59:  *
  60:  * @constant MESSAGE_HTML
  61:  */
  62:     const MESSAGE_HTML = 'html';
  63: 
  64: /**
  65:  * Type of message - TEXT
  66:  *
  67:  * @constant MESSAGE_TEXT
  68:  */
  69:     const MESSAGE_TEXT = 'text';
  70: 
  71: /**
  72:  * Recipient of the email
  73:  *
  74:  * @var array
  75:  */
  76:     protected $_to = array();
  77: 
  78: /**
  79:  * The mail which the email is sent from
  80:  *
  81:  * @var array
  82:  */
  83:     protected $_from = array();
  84: 
  85: /**
  86:  * The sender email
  87:  *
  88:  * @var array();
  89:  */
  90:     protected $_sender = array();
  91: 
  92: /**
  93:  * The email the recipient will reply to
  94:  *
  95:  * @var array
  96:  */
  97:     protected $_replyTo = array();
  98: 
  99: /**
 100:  * The read receipt email
 101:  *
 102:  * @var array
 103:  */
 104:     protected $_readReceipt = array();
 105: 
 106: /**
 107:  * The mail that will be used in case of any errors like
 108:  * - Remote mailserver down
 109:  * - Remote user has exceeded his quota
 110:  * - Unknown user
 111:  *
 112:  * @var array
 113:  */
 114:     protected $_returnPath = array();
 115: 
 116: /**
 117:  * Carbon Copy
 118:  *
 119:  * List of email's that should receive a copy of the email.
 120:  * The Recipient WILL be able to see this list
 121:  *
 122:  * @var array
 123:  */
 124:     protected $_cc = array();
 125: 
 126: /**
 127:  * Blind Carbon Copy
 128:  *
 129:  * List of email's that should receive a copy of the email.
 130:  * The Recipient WILL NOT be able to see this list
 131:  *
 132:  * @var array
 133:  */
 134:     protected $_bcc = array();
 135: 
 136: /**
 137:  * Message ID
 138:  *
 139:  * @var boolean|string True to generate, False to ignore, String with value
 140:  */
 141:     protected $_messageId = true;
 142: 
 143: /**
 144:  * Domain for messageId generation.
 145:  * Needs to be manually set for CLI mailing as env('HTTP_HOST') is empty
 146:  *
 147:  * @var string
 148:  */
 149:     protected $_domain = null;
 150: 
 151: /**
 152:  * The subject of the email
 153:  *
 154:  * @var string
 155:  */
 156:     protected $_subject = '';
 157: 
 158: /**
 159:  * Associative array of a user defined headers
 160:  * Keys will be prefixed 'X-' as per RFC2822 Section 4.7.5
 161:  *
 162:  * @var array
 163:  */
 164:     protected $_headers = array();
 165: 
 166: /**
 167:  * Layout for the View
 168:  *
 169:  * @var string
 170:  */
 171:     protected $_layout = 'default';
 172: 
 173: /**
 174:  * Template for the view
 175:  *
 176:  * @var string
 177:  */
 178:     protected $_template = '';
 179: 
 180: /**
 181:  * View for render
 182:  *
 183:  * @var string
 184:  */
 185:     protected $_viewRender = 'View';
 186: 
 187: /**
 188:  * Vars to sent to render
 189:  *
 190:  * @var array
 191:  */
 192:     protected $_viewVars = array();
 193: 
 194: /**
 195:  * Theme for the View
 196:  *
 197:  * @var array
 198:  */
 199:     protected $_theme = null;
 200: 
 201: /**
 202:  * Helpers to be used in the render
 203:  *
 204:  * @var array
 205:  */
 206:     protected $_helpers = array('Html');
 207: 
 208: /**
 209:  * Text message
 210:  *
 211:  * @var string
 212:  */
 213:     protected $_textMessage = '';
 214: 
 215: /**
 216:  * Html message
 217:  *
 218:  * @var string
 219:  */
 220:     protected $_htmlMessage = '';
 221: 
 222: /**
 223:  * Final message to send
 224:  *
 225:  * @var array
 226:  */
 227:     protected $_message = array();
 228: 
 229: /**
 230:  * Available formats to be sent.
 231:  *
 232:  * @var array
 233:  */
 234:     protected $_emailFormatAvailable = array('text', 'html', 'both');
 235: 
 236: /**
 237:  * What format should the email be sent in
 238:  *
 239:  * @var string
 240:  */
 241:     protected $_emailFormat = 'text';
 242: 
 243: /**
 244:  * What method should the email be sent
 245:  *
 246:  * @var string
 247:  */
 248:     protected $_transportName = 'Mail';
 249: 
 250: /**
 251:  * Instance of transport class
 252:  *
 253:  * @var AbstractTransport
 254:  */
 255:     protected $_transportClass = null;
 256: 
 257: /**
 258:  * Charset the email body is sent in
 259:  *
 260:  * @var string
 261:  */
 262:     public $charset = 'utf-8';
 263: 
 264: /**
 265:  * Charset the email header is sent in
 266:  * If null, the $charset property will be used as default
 267:  *
 268:  * @var string
 269:  */
 270:     public $headerCharset = null;
 271: 
 272: /**
 273:  * The application wide charset, used to encode headers and body
 274:  *
 275:  * @var string
 276:  */
 277:     protected $_appCharset = null;
 278: 
 279: /**
 280:  * List of files that should be attached to the email.
 281:  *
 282:  * Only absolute paths
 283:  *
 284:  * @var array
 285:  */
 286:     protected $_attachments = array();
 287: 
 288: /**
 289:  * If set, boundary to use for multipart mime messages
 290:  *
 291:  * @var string
 292:  */
 293:     protected $_boundary = null;
 294: 
 295: /**
 296:  * Configuration to transport
 297:  *
 298:  * @var string|array
 299:  */
 300:     protected $_config = array();
 301: 
 302: /**
 303:  * 8Bit character sets
 304:  *
 305:  * @var array
 306:  */
 307:     protected $_charset8bit = array('UTF-8', 'SHIFT_JIS');
 308: 
 309: /**
 310:  * Define Content-Type charset name
 311:  *
 312:  * @var array
 313:  */
 314:     protected $_contentTypeCharset = array(
 315:         'ISO-2022-JP-MS' => 'ISO-2022-JP'
 316:     );
 317: 
 318: /**
 319:  * Constructor
 320:  * @param array|string $config Array of configs, or string to load configs from email.php
 321:  *
 322:  */
 323:     public function __construct($config = null) {
 324:         $this->_appCharset = Configure::read('App.encoding');
 325:         if ($this->_appCharset !== null) {
 326:             $this->charset = $this->_appCharset;
 327:         }
 328:         $this->_domain = preg_replace('/\:\d+$/', '', env('HTTP_HOST'));
 329:         if (empty($this->_domain)) {
 330:             $this->_domain = php_uname('n');
 331:         }
 332: 
 333:         if ($config) {
 334:             $this->config($config);
 335:         }
 336:         if (empty($this->headerCharset)) {
 337:             $this->headerCharset = $this->charset;
 338:         }
 339:     }
 340: 
 341: /**
 342:  * From
 343:  *
 344:  * @param string|array $email
 345:  * @param string $name
 346:  * @return array|CakeEmail
 347:  * @throws SocketException
 348:  */
 349:     public function from($email = null, $name = null) {
 350:         if ($email === null) {
 351:             return $this->_from;
 352:         }
 353:         return $this->_setEmailSingle('_from', $email, $name, __d('cake_dev', 'From requires only 1 email address.'));
 354:     }
 355: 
 356: /**
 357:  * Sender
 358:  *
 359:  * @param string|array $email
 360:  * @param string $name
 361:  * @return array|CakeEmail
 362:  * @throws SocketException
 363:  */
 364:     public function sender($email = null, $name = null) {
 365:         if ($email === null) {
 366:             return $this->_sender;
 367:         }
 368:         return $this->_setEmailSingle('_sender', $email, $name, __d('cake_dev', 'Sender requires only 1 email address.'));
 369:     }
 370: 
 371: /**
 372:  * Reply-To
 373:  *
 374:  * @param string|array $email
 375:  * @param string $name
 376:  * @return array|CakeEmail
 377:  * @throws SocketException
 378:  */
 379:     public function replyTo($email = null, $name = null) {
 380:         if ($email === null) {
 381:             return $this->_replyTo;
 382:         }
 383:         return $this->_setEmailSingle('_replyTo', $email, $name, __d('cake_dev', 'Reply-To requires only 1 email address.'));
 384:     }
 385: 
 386: /**
 387:  * Read Receipt (Disposition-Notification-To header)
 388:  *
 389:  * @param string|array $email
 390:  * @param string $name
 391:  * @return array|CakeEmail
 392:  * @throws SocketException
 393:  */
 394:     public function readReceipt($email = null, $name = null) {
 395:         if ($email === null) {
 396:             return $this->_readReceipt;
 397:         }
 398:         return $this->_setEmailSingle('_readReceipt', $email, $name, __d('cake_dev', 'Disposition-Notification-To requires only 1 email address.'));
 399:     }
 400: 
 401: /**
 402:  * Return Path
 403:  *
 404:  * @param string|array $email
 405:  * @param string $name
 406:  * @return array|CakeEmail
 407:  * @throws SocketException
 408:  */
 409:     public function returnPath($email = null, $name = null) {
 410:         if ($email === null) {
 411:             return $this->_returnPath;
 412:         }
 413:         return $this->_setEmailSingle('_returnPath', $email, $name, __d('cake_dev', 'Return-Path requires only 1 email address.'));
 414:     }
 415: 
 416: /**
 417:  * To
 418:  *
 419:  * @param string|array $email Null to get, String with email, Array with email as key, name as value or email as value (without name)
 420:  * @param string $name
 421:  * @return array|CakeEmail
 422:  */
 423:     public function to($email = null, $name = null) {
 424:         if ($email === null) {
 425:             return $this->_to;
 426:         }
 427:         return $this->_setEmail('_to', $email, $name);
 428:     }
 429: 
 430: /**
 431:  * Add To
 432:  *
 433:  * @param string|array $email String with email, Array with email as key, name as value or email as value (without name)
 434:  * @param string $name
 435:  * @return CakeEmail $this
 436:  */
 437:     public function addTo($email, $name = null) {
 438:         return $this->_addEmail('_to', $email, $name);
 439:     }
 440: 
 441: /**
 442:  * Cc
 443:  *
 444:  * @param string|array $email String with email, Array with email as key, name as value or email as value (without name)
 445:  * @param string $name
 446:  * @return array|CakeEmail
 447:  */
 448:     public function cc($email = null, $name = null) {
 449:         if ($email === null) {
 450:             return $this->_cc;
 451:         }
 452:         return $this->_setEmail('_cc', $email, $name);
 453:     }
 454: 
 455: /**
 456:  * Add Cc
 457:  *
 458:  * @param string|array $email String with email, Array with email as key, name as value or email as value (without name)
 459:  * @param string $name
 460:  * @return CakeEmail $this
 461:  */
 462:     public function addCc($email, $name = null) {
 463:         return $this->_addEmail('_cc', $email, $name);
 464:     }
 465: 
 466: /**
 467:  * Bcc
 468:  *
 469:  * @param string|array $email String with email, Array with email as key, name as value or email as value (without name)
 470:  * @param string $name
 471:  * @return array|CakeEmail
 472:  */
 473:     public function bcc($email = null, $name = null) {
 474:         if ($email === null) {
 475:             return $this->_bcc;
 476:         }
 477:         return $this->_setEmail('_bcc', $email, $name);
 478:     }
 479: 
 480: /**
 481:  * Add Bcc
 482:  *
 483:  * @param string|array $email String with email, Array with email as key, name as value or email as value (without name)
 484:  * @param string $name
 485:  * @return CakeEmail $this
 486:  */
 487:     public function addBcc($email, $name = null) {
 488:         return $this->_addEmail('_bcc', $email, $name);
 489:     }
 490: 
 491: /**
 492:  * Charset setter/getter
 493:  *
 494:  * @param string $charset
 495:  * @return string $this->charset
 496:  */
 497:     public function charset($charset = null) {
 498:         if ($charset === null) {
 499:             return $this->charset;
 500:         }
 501:         $this->charset = $charset;
 502:         if (empty($this->headerCharset)) {
 503:             $this->headerCharset = $charset;
 504:         }
 505:         return $this->charset;
 506:     }
 507: 
 508: /**
 509:  * HeaderCharset setter/getter
 510:  *
 511:  * @param string $charset
 512:  * @return string $this->charset
 513:  */
 514:     public function headerCharset($charset = null) {
 515:         if ($charset === null) {
 516:             return $this->headerCharset;
 517:         }
 518:         return $this->headerCharset = $charset;
 519:     }
 520: 
 521: /**
 522:  * Set email
 523:  *
 524:  * @param string $varName
 525:  * @param string|array $email
 526:  * @param string $name
 527:  * @return CakeEmail $this
 528:  * @throws SocketException
 529:  */
 530:     protected function _setEmail($varName, $email, $name) {
 531:         if (!is_array($email)) {
 532:             if (!Validation::email($email)) {
 533:                 throw new SocketException(__d('cake_dev', 'Invalid email: "%s"', $email));
 534:             }
 535:             if ($name === null) {
 536:                 $name = $email;
 537:             }
 538:             $this->{$varName} = array($email => $name);
 539:             return $this;
 540:         }
 541:         $list = array();
 542:         foreach ($email as $key => $value) {
 543:             if (is_int($key)) {
 544:                 $key = $value;
 545:             }
 546:             if (!Validation::email($key)) {
 547:                 throw new SocketException(__d('cake_dev', 'Invalid email: "%s"', $key));
 548:             }
 549:             $list[$key] = $value;
 550:         }
 551:         $this->{$varName} = $list;
 552:         return $this;
 553:     }
 554: 
 555: /**
 556:  * Set only 1 email
 557:  *
 558:  * @param string $varName
 559:  * @param string|array $email
 560:  * @param string $name
 561:  * @param string $throwMessage
 562:  * @return CakeEmail $this
 563:  * @throws SocketException
 564:  */
 565:     protected function _setEmailSingle($varName, $email, $name, $throwMessage) {
 566:         $current = $this->{$varName};
 567:         $this->_setEmail($varName, $email, $name);
 568:         if (count($this->{$varName}) !== 1) {
 569:             $this->{$varName} = $current;
 570:             throw new SocketException($throwMessage);
 571:         }
 572:         return $this;
 573:     }
 574: 
 575: /**
 576:  * Add email
 577:  *
 578:  * @param string $varName
 579:  * @param string|array $email
 580:  * @param string $name
 581:  * @return CakeEmail $this
 582:  * @throws SocketException
 583:  */
 584:     protected function _addEmail($varName, $email, $name) {
 585:         if (!is_array($email)) {
 586:             if (!Validation::email($email)) {
 587:                 throw new SocketException(__d('cake_dev', 'Invalid email: "%s"', $email));
 588:             }
 589:             if ($name === null) {
 590:                 $name = $email;
 591:             }
 592:             $this->{$varName}[$email] = $name;
 593:             return $this;
 594:         }
 595:         $list = array();
 596:         foreach ($email as $key => $value) {
 597:             if (is_int($key)) {
 598:                 $key = $value;
 599:             }
 600:             if (!Validation::email($key)) {
 601:                 throw new SocketException(__d('cake_dev', 'Invalid email: "%s"', $key));
 602:             }
 603:             $list[$key] = $value;
 604:         }
 605:         $this->{$varName} = array_merge($this->{$varName}, $list);
 606:         return $this;
 607:     }
 608: 
 609: /**
 610:  * Get/Set Subject.
 611:  *
 612:  * @param string $subject
 613:  * @return string|CakeEmail
 614:  */
 615:     public function subject($subject = null) {
 616:         if ($subject === null) {
 617:             return $this->_subject;
 618:         }
 619:         $this->_subject = $this->_encode((string)$subject);
 620:         return $this;
 621:     }
 622: 
 623: /**
 624:  * Sets headers for the message
 625:  *
 626:  * @param array $headers Associative array containing headers to be set.
 627:  * @return CakeEmail $this
 628:  * @throws SocketException
 629:  */
 630:     public function setHeaders($headers) {
 631:         if (!is_array($headers)) {
 632:             throw new SocketException(__d('cake_dev', '$headers should be an array.'));
 633:         }
 634:         $this->_headers = $headers;
 635:         return $this;
 636:     }
 637: 
 638: /**
 639:  * Add header for the message
 640:  *
 641:  * @param array $headers
 642:  * @return object $this
 643:  * @throws SocketException
 644:  */
 645:     public function addHeaders($headers) {
 646:         if (!is_array($headers)) {
 647:             throw new SocketException(__d('cake_dev', '$headers should be an array.'));
 648:         }
 649:         $this->_headers = array_merge($this->_headers, $headers);
 650:         return $this;
 651:     }
 652: 
 653: /**
 654:  * Get list of headers
 655:  *
 656:  * ### Includes:
 657:  *
 658:  * - `from`
 659:  * - `replyTo`
 660:  * - `readReceipt`
 661:  * - `returnPath`
 662:  * - `to`
 663:  * - `cc`
 664:  * - `bcc`
 665:  * - `subject`
 666:  *
 667:  * @param array $include
 668:  * @return array
 669:  */
 670:     public function getHeaders($include = array()) {
 671:         if ($include == array_values($include)) {
 672:             $include = array_fill_keys($include, true);
 673:         }
 674:         $defaults = array_fill_keys(array('from', 'sender', 'replyTo', 'readReceipt', 'returnPath', 'to', 'cc', 'bcc', 'subject'), false);
 675:         $include += $defaults;
 676: 
 677:         $headers = array();
 678:         $relation = array(
 679:             'from' => 'From',
 680:             'replyTo' => 'Reply-To',
 681:             'readReceipt' => 'Disposition-Notification-To',
 682:             'returnPath' => 'Return-Path'
 683:         );
 684:         foreach ($relation as $var => $header) {
 685:             if ($include[$var]) {
 686:                 $var = '_' . $var;
 687:                 $headers[$header] = current($this->_formatAddress($this->{$var}));
 688:             }
 689:         }
 690:         if ($include['sender']) {
 691:             if (key($this->_sender) === key($this->_from)) {
 692:                 $headers['Sender'] = '';
 693:             } else {
 694:                 $headers['Sender'] = current($this->_formatAddress($this->_sender));
 695:             }
 696:         }
 697: 
 698:         foreach (array('to', 'cc', 'bcc') as $var) {
 699:             if ($include[$var]) {
 700:                 $classVar = '_' . $var;
 701:                 $headers[ucfirst($var)] = implode(', ', $this->_formatAddress($this->{$classVar}));
 702:             }
 703:         }
 704: 
 705:         $headers += $this->_headers;
 706:         if (!isset($headers['X-Mailer'])) {
 707:             $headers['X-Mailer'] = self::EMAIL_CLIENT;
 708:         }
 709:         if (!isset($headers['Date'])) {
 710:             $headers['Date'] = date(DATE_RFC2822);
 711:         }
 712:         if ($this->_messageId !== false) {
 713:             if ($this->_messageId === true) {
 714:                 $headers['Message-ID'] = '<' . str_replace('-', '', String::UUID()) . '@' . $this->_domain . '>';
 715:             } else {
 716:                 $headers['Message-ID'] = $this->_messageId;
 717:             }
 718:         }
 719: 
 720:         if ($include['subject']) {
 721:             $headers['Subject'] = $this->_subject;
 722:         }
 723: 
 724:         $headers['MIME-Version'] = '1.0';
 725:         if (!empty($this->_attachments) || $this->_emailFormat === 'both') {
 726:             $headers['Content-Type'] = 'multipart/mixed; boundary="' . $this->_boundary . '"';
 727:         } elseif ($this->_emailFormat === 'text') {
 728:             $headers['Content-Type'] = 'text/plain; charset=' . $this->_getContentTypeCharset();
 729:         } elseif ($this->_emailFormat === 'html') {
 730:             $headers['Content-Type'] = 'text/html; charset=' . $this->_getContentTypeCharset();
 731:         }
 732:         $headers['Content-Transfer-Encoding'] = $this->_getContentTransferEncoding();
 733: 
 734:         return $headers;
 735:     }
 736: 
 737: /**
 738:  * Format addresses
 739:  *
 740:  * @param array $address
 741:  * @return array
 742:  */
 743:     protected function _formatAddress($address) {
 744:         $return = array();
 745:         foreach ($address as $email => $alias) {
 746:             if ($email === $alias) {
 747:                 $return[] = $email;
 748:             } else {
 749:                 if (strpos($alias, ',') !== false) {
 750:                     $alias = '"' . $alias . '"';
 751:                 }
 752:                 $return[] = sprintf('%s <%s>', $this->_encode($alias), $email);
 753:             }
 754:         }
 755:         return $return;
 756:     }
 757: 
 758: /**
 759:  * Template and layout
 760:  *
 761:  * @param boolean|string $template Template name or null to not use
 762:  * @param boolean|string $layout Layout name or null to not use
 763:  * @return array|CakeEmail
 764:  */
 765:     public function template($template = false, $layout = false) {
 766:         if ($template === false) {
 767:             return array(
 768:                 'template' => $this->_template,
 769:                 'layout' => $this->_layout
 770:             );
 771:         }
 772:         $this->_template = $template;
 773:         if ($layout !== false) {
 774:             $this->_layout = $layout;
 775:         }
 776:         return $this;
 777:     }
 778: 
 779: /**
 780:  * View class for render
 781:  *
 782:  * @param string $viewClass
 783:  * @return string|CakeEmail
 784:  */
 785:     public function viewRender($viewClass = null) {
 786:         if ($viewClass === null) {
 787:             return $this->_viewRender;
 788:         }
 789:         $this->_viewRender = $viewClass;
 790:         return $this;
 791:     }
 792: 
 793: /**
 794:  * Variables to be set on render
 795:  *
 796:  * @param array $viewVars
 797:  * @return array|CakeEmail
 798:  */
 799:     public function viewVars($viewVars = null) {
 800:         if ($viewVars === null) {
 801:             return $this->_viewVars;
 802:         }
 803:         $this->_viewVars = array_merge($this->_viewVars, (array)$viewVars);
 804:         return $this;
 805:     }
 806: 
 807: /**
 808:  * Theme to use when rendering
 809:  *
 810:  * @param string $theme
 811:  * @return string|CakeEmail
 812:  */
 813:     public function theme($theme = null) {
 814:         if ($theme === null) {
 815:             return $this->_theme;
 816:         }
 817:         $this->_theme = $theme;
 818:         return $this;
 819:     }
 820: 
 821: /**
 822:  * Helpers to be used in render
 823:  *
 824:  * @param array $helpers
 825:  * @return array|CakeEmail
 826:  */
 827:     public function helpers($helpers = null) {
 828:         if ($helpers === null) {
 829:             return $this->_helpers;
 830:         }
 831:         $this->_helpers = (array)$helpers;
 832:         return $this;
 833:     }
 834: 
 835: /**
 836:  * Email format
 837:  *
 838:  * @param string $format
 839:  * @return string|CakeEmail
 840:  * @throws SocketException
 841:  */
 842:     public function emailFormat($format = null) {
 843:         if ($format === null) {
 844:             return $this->_emailFormat;
 845:         }
 846:         if (!in_array($format, $this->_emailFormatAvailable)) {
 847:             throw new SocketException(__d('cake_dev', 'Format not available.'));
 848:         }
 849:         $this->_emailFormat = $format;
 850:         return $this;
 851:     }
 852: 
 853: /**
 854:  * Transport name
 855:  *
 856:  * @param string $name
 857:  * @return string|CakeEmail
 858:  */
 859:     public function transport($name = null) {
 860:         if ($name === null) {
 861:             return $this->_transportName;
 862:         }
 863:         $this->_transportName = (string)$name;
 864:         $this->_transportClass = null;
 865:         return $this;
 866:     }
 867: 
 868: /**
 869:  * Return the transport class
 870:  *
 871:  * @return CakeEmail
 872:  * @throws SocketException
 873:  */
 874:     public function transportClass() {
 875:         if ($this->_transportClass) {
 876:             return $this->_transportClass;
 877:         }
 878:         list($plugin, $transportClassname) = pluginSplit($this->_transportName, true);
 879:         $transportClassname .= 'Transport';
 880:         App::uses($transportClassname, $plugin . 'Network/Email');
 881:         if (!class_exists($transportClassname)) {
 882:             throw new SocketException(__d('cake_dev', 'Class "%s" not found.', $transportClassname));
 883:         } elseif (!method_exists($transportClassname, 'send')) {
 884:             throw new SocketException(__d('cake_dev', 'The "%s" do not have send method.', $transportClassname));
 885:         }
 886: 
 887:         return $this->_transportClass = new $transportClassname();
 888:     }
 889: 
 890: /**
 891:  * Message-ID
 892:  *
 893:  * @param boolean|string $message True to generate a new Message-ID, False to ignore (not send in email), String to set as Message-ID
 894:  * @return boolean|string|CakeEmail
 895:  * @throws SocketException
 896:  */
 897:     public function messageId($message = null) {
 898:         if ($message === null) {
 899:             return $this->_messageId;
 900:         }
 901:         if (is_bool($message)) {
 902:             $this->_messageId = $message;
 903:         } else {
 904:             if (!preg_match('/^\<.+@.+\>$/', $message)) {
 905:                 throw new SocketException(__d('cake_dev', 'Invalid format for Message-ID. The text should be something like "<[email protected]>"'));
 906:             }
 907:             $this->_messageId = $message;
 908:         }
 909:         return $this;
 910:     }
 911: 
 912: /**
 913:  * Domain as top level (the part after @)
 914:  *
 915:  * @param string $domain Manually set the domain for CLI mailing
 916:  * @return string|CakeEmail
 917:  */
 918:     public function domain($domain = null) {
 919:         if ($domain === null) {
 920:             return $this->_domain;
 921:         }
 922:         $this->_domain = $domain;
 923:         return $this;
 924:     }
 925: 
 926: /**
 927:  * Add attachments to the email message
 928:  *
 929:  * Attachments can be defined in a few forms depending on how much control you need:
 930:  *
 931:  * Attach a single file:
 932:  *
 933:  * {{{
 934:  * $email->attachments('path/to/file');
 935:  * }}}
 936:  *
 937:  * Attach a file with a different filename:
 938:  *
 939:  * {{{
 940:  * $email->attachments(array('custom_name.txt' => 'path/to/file.txt'));
 941:  * }}}
 942:  *
 943:  * Attach a file and specify additional properties:
 944:  *
 945:  * {{{
 946:  * $email->attachments(array('custom_name.png' => array(
 947:  *      'file' => 'path/to/file',
 948:  *      'mimetype' => 'image/png',
 949:  *      'contentId' => 'abc123'
 950:  * ));
 951:  * }}}
 952:  *
 953:  * The `contentId` key allows you to specify an inline attachment. In your email text, you
 954:  * can use `<img src="cid:abc123" />` to display the image inline.
 955:  *
 956:  * @param string|array $attachments String with the filename or array with filenames
 957:  * @return array|CakeEmail Either the array of attachments when getting or $this when setting.
 958:  * @throws SocketException
 959:  */
 960:     public function attachments($attachments = null) {
 961:         if ($attachments === null) {
 962:             return $this->_attachments;
 963:         }
 964:         $attach = array();
 965:         foreach ((array)$attachments as $name => $fileInfo) {
 966:             if (!is_array($fileInfo)) {
 967:                 $fileInfo = array('file' => $fileInfo);
 968:             }
 969:             if (!isset($fileInfo['file'])) {
 970:                 throw new SocketException(__d('cake_dev', 'File not specified.'));
 971:             }
 972:             $fileInfo['file'] = realpath($fileInfo['file']);
 973:             if ($fileInfo['file'] === false || !file_exists($fileInfo['file'])) {
 974:                 throw new SocketException(__d('cake_dev', 'File not found: "%s"', $fileInfo['file']));
 975:             }
 976:             if (is_int($name)) {
 977:                 $name = basename($fileInfo['file']);
 978:             }
 979:             if (!isset($fileInfo['mimetype'])) {
 980:                 $fileInfo['mimetype'] = 'application/octet-stream';
 981:             }
 982:             $attach[$name] = $fileInfo;
 983:         }
 984:         $this->_attachments = $attach;
 985:         return $this;
 986:     }
 987: 
 988: /**
 989:  * Add attachments
 990:  *
 991:  * @param string|array $attachments String with the filename or array with filenames
 992:  * @return CakeEmail $this
 993:  * @throws SocketException
 994:  */
 995:     public function addAttachments($attachments) {
 996:         $current = $this->_attachments;
 997:         $this->attachments($attachments);
 998:         $this->_attachments = array_merge($current, $this->_attachments);
 999:         return $this;
1000:     }
1001: 
1002: /**
1003:  * Get generated message (used by transport classes)
1004:  *
1005:  * @param string $type Use MESSAGE_* constants or null to return the full message as array
1006:  * @return string|array String if have type, array if type is null
1007:  */
1008:     public function message($type = null) {
1009:         switch ($type) {
1010:             case self::MESSAGE_HTML:
1011:                 return $this->_htmlMessage;
1012:             case self::MESSAGE_TEXT:
1013:                 return $this->_textMessage;
1014:         }
1015:         return $this->_message;
1016:     }
1017: 
1018: /**
1019:  * Configuration to use when send email
1020:  *
1021:  * @param string|array $config String with configuration name (from email.php), array with config or null to return current config
1022:  * @return string|array|CakeEmail
1023:  */
1024:     public function config($config = null) {
1025:         if ($config === null) {
1026:             return $this->_config;
1027:         }
1028:         if (!is_array($config)) {
1029:             $config = (string)$config;
1030:         }
1031: 
1032:         $this->_applyConfig($config);
1033:         return $this;
1034:     }
1035: 
1036: /**
1037:  * Send an email using the specified content, template and layout
1038:  *
1039:  * @param string|array $content String with message or array with messages
1040:  * @return array
1041:  * @throws SocketException
1042:  */
1043:     public function send($content = null) {
1044:         if (empty($this->_from)) {
1045:             throw new SocketException(__d('cake_dev', 'From is not specified.'));
1046:         }
1047:         if (empty($this->_to) && empty($this->_cc) && empty($this->_bcc)) {
1048:             throw new SocketException(__d('cake_dev', 'You need to specify at least one destination for to, cc or bcc.'));
1049:         }
1050: 
1051:         if (is_array($content)) {
1052:             $content = implode("\n", $content) . "\n";
1053:         }
1054: 
1055:         $this->_textMessage = $this->_htmlMessage = '';
1056:         $this->_createBoundary();
1057:         $this->_message = $this->_render($this->_wrap($content));
1058: 
1059:         $contents = $this->transportClass()->send($this);
1060:         if (!empty($this->_config['log'])) {
1061:             $level = LOG_DEBUG;
1062:             if ($this->_config['log'] !== true) {
1063:                 $level = $this->_config['log'];
1064:             }
1065:             CakeLog::write($level, PHP_EOL . $contents['headers'] . PHP_EOL . $contents['message']);
1066:         }
1067:         return $contents;
1068:     }
1069: 
1070: /**
1071:  * Static method to fast create an instance of CakeEmail
1072:  *
1073:  * @param string|array $to Address to send (see CakeEmail::to()). If null, will try to use 'to' from transport config
1074:  * @param string $subject String of subject or null to use 'subject' from transport config
1075:  * @param string|array $message String with message or array with variables to be used in render
1076:  * @param string|array $transportConfig String to use config from EmailConfig or array with configs
1077:  * @param boolean $send Send the email or just return the instance pre-configured
1078:  * @return CakeEmail Instance of CakeEmail
1079:  * @throws SocketException
1080:  */
1081:     public static function deliver($to = null, $subject = null, $message = null, $transportConfig = 'fast', $send = true) {
1082:         $class = __CLASS__;
1083:         $instance = new $class($transportConfig);
1084:         if ($to !== null) {
1085:             $instance->to($to);
1086:         }
1087:         if ($subject !== null) {
1088:             $instance->subject($subject);
1089:         }
1090:         if (is_array($message)) {
1091:             $instance->viewVars($message);
1092:             $message = null;
1093:         } elseif ($message === null && array_key_exists('message', $config = $instance->config())) {
1094:             $message = $config['message'];
1095:         }
1096: 
1097:         if ($send === true) {
1098:             $instance->send($message);
1099:         }
1100: 
1101:         return $instance;
1102:     }
1103: 
1104: /**
1105:  * Apply the config to an instance
1106:  *
1107:  * @param CakeEmail $obj CakeEmail
1108:  * @param array $config
1109:  * @return void
1110:  * @throws ConfigureException When configuration file cannot be found, or is missing
1111:  *   the named config.
1112:  */
1113:     protected function _applyConfig($config) {
1114:         if (is_string($config)) {
1115:             if (!class_exists('EmailConfig') && !config('email')) {
1116:                 throw new ConfigureException(__d('cake_dev', '%s not found.', APP . 'Config' . DS . 'email.php'));
1117:             }
1118:             $configs = new EmailConfig();
1119:             if (!isset($configs->{$config})) {
1120:                 throw new ConfigureException(__d('cake_dev', 'Unknown email configuration "%s".', $config));
1121:             }
1122:             $config = $configs->{$config};
1123:         }
1124:         $this->_config += $config;
1125:         if (!empty($config['charset'])) {
1126:             $this->charset = $config['charset'];
1127:         }
1128:         if (!empty($config['headerCharset'])) {
1129:             $this->headerCharset = $config['headerCharset'];
1130:         }
1131:         if (empty($this->headerCharset)) {
1132:             $this->headerCharset = $this->charset;
1133:         }
1134:         $simpleMethods = array(
1135:             'from', 'sender', 'to', 'replyTo', 'readReceipt', 'returnPath', 'cc', 'bcc',
1136:             'messageId', 'domain', 'subject', 'viewRender', 'viewVars', 'attachments',
1137:             'transport', 'emailFormat', 'theme', 'helpers'
1138:         );
1139:         foreach ($simpleMethods as $method) {
1140:             if (isset($config[$method])) {
1141:                 $this->$method($config[$method]);
1142:                 unset($config[$method]);
1143:             }
1144:         }
1145:         if (isset($config['headers'])) {
1146:             $this->setHeaders($config['headers']);
1147:             unset($config['headers']);
1148:         }
1149:         if (array_key_exists('template', $config)) {
1150:             $layout = false;
1151:             if (array_key_exists('layout', $config)) {
1152:                 $layout = $config['layout'];
1153:                 unset($config['layout']);
1154:             }
1155:             $this->template($config['template'], $layout);
1156:             unset($config['template']);
1157:         }
1158:         $this->transportClass()->config($config);
1159:     }
1160: 
1161: /**
1162:  * Reset all EmailComponent internal variables to be able to send out a new email.
1163:  *
1164:  * @return CakeEmail $this
1165:  */
1166:     public function reset() {
1167:         $this->_to = array();
1168:         $this->_from = array();
1169:         $this->_sender = array();
1170:         $this->_replyTo = array();
1171:         $this->_readReceipt = array();
1172:         $this->_returnPath = array();
1173:         $this->_cc = array();
1174:         $this->_bcc = array();
1175:         $this->_messageId = true;
1176:         $this->_subject = '';
1177:         $this->_headers = array();
1178:         $this->_layout = 'default';
1179:         $this->_template = '';
1180:         $this->_viewRender = 'View';
1181:         $this->_viewVars = array();
1182:         $this->_theme = null;
1183:         $this->_helpers = array('Html');
1184:         $this->_textMessage = '';
1185:         $this->_htmlMessage = '';
1186:         $this->_message = '';
1187:         $this->_emailFormat = 'text';
1188:         $this->_transportName = 'Mail';
1189:         $this->_transportClass = null;
1190:         $this->charset = 'utf-8';
1191:         $this->headerCharset = null;
1192:         $this->_attachments = array();
1193:         $this->_config = array();
1194:         return $this;
1195:     }
1196: 
1197: /**
1198:  * Encode the specified string using the current charset
1199:  *
1200:  * @param string $text String to encode
1201:  * @return string Encoded string
1202:  */
1203:     protected function _encode($text) {
1204:         $internalEncoding = function_exists('mb_internal_encoding');
1205:         if ($internalEncoding) {
1206:             $restore = mb_internal_encoding();
1207:             mb_internal_encoding($this->_appCharset);
1208:         }
1209:         if (empty($this->headerCharset)) {
1210:             $this->headerCharset = $this->charset;
1211:         }
1212:         $return = mb_encode_mimeheader($text, $this->headerCharset, 'B');
1213:         if ($internalEncoding) {
1214:             mb_internal_encoding($restore);
1215:         }
1216:         return $return;
1217:     }
1218: 
1219: /**
1220:  * Translates a string for one charset to another if the App.encoding value
1221:  * differs and the mb_convert_encoding function exists
1222:  *
1223:  * @param string $text The text to be converted
1224:  * @param string $charset the target encoding
1225:  * @return string
1226:  */
1227:     protected function _encodeString($text, $charset) {
1228:         if ($this->_appCharset === $charset || !function_exists('mb_convert_encoding')) {
1229:             return $text;
1230:         }
1231:         return mb_convert_encoding($text, $charset, $this->_appCharset);
1232:     }
1233: 
1234: /**
1235:  * Wrap the message to follow the RFC 2822 - 2.1.1
1236:  *
1237:  * @param string $message Message to wrap
1238:  * @return array Wrapped message
1239:  */
1240:     protected function _wrap($message, $wrapLength = CakeEmail::LINE_LENGTH_MUST) {
1241:         $message = str_replace(array("\r\n", "\r"), "\n", $message);
1242:         $lines = explode("\n", $message);
1243:         $formatted = array();
1244: 
1245:         foreach ($lines as $line) {
1246:             if (empty($line)) {
1247:                 $formatted[] = '';
1248:                 continue;
1249:             }
1250:             if (!preg_match('/\<[a-z]/i', $line)) {
1251:                 $formatted = array_merge(
1252:                     $formatted,
1253:                     explode("\n", wordwrap($line, $wrapLength, "\n"))
1254:                 );
1255:                 continue;
1256:             }
1257: 
1258:             $tagOpen = false;
1259:             $tmpLine = $tag = '';
1260:             $tmpLineLength = 0;
1261:             for ($i = 0, $count = strlen($line); $i < $count; $i++) {
1262:                 $char = $line[$i];
1263:                 if ($tagOpen) {
1264:                     $tag .= $char;
1265:                     if ($char === '>') {
1266:                         $tagLength = strlen($tag);
1267:                         if ($tagLength + $tmpLineLength < $wrapLength) {
1268:                             $tmpLine .= $tag;
1269:                             $tmpLineLength += $tagLength;
1270:                         } else {
1271:                             if ($tmpLineLength > 0) {
1272:                                 $formatted[] = trim($tmpLine);
1273:                                 $tmpLine = '';
1274:                                 $tmpLineLength = 0;
1275:                             }
1276:                             if ($tagLength > $wrapLength) {
1277:                                 $formatted[] = $tag;
1278:                             } else {
1279:                                 $tmpLine = $tag;
1280:                                 $tmpLineLength = $tagLength;
1281:                             }
1282:                         }
1283:                         $tag = '';
1284:                         $tagOpen = false;
1285:                     }
1286:                     continue;
1287:                 }
1288:                 if ($char === '<') {
1289:                     $tagOpen = true;
1290:                     $tag = '<';
1291:                     continue;
1292:                 }
1293:                 if ($char === ' ' && $tmpLineLength >= $wrapLength) {
1294:                     $formatted[] = $tmpLine;
1295:                     $tmpLineLength = 0;
1296:                     continue;
1297:                 }
1298:                 $tmpLine .= $char;
1299:                 $tmpLineLength++;
1300:                 if ($tmpLineLength === $wrapLength) {
1301:                     $nextChar = $line[$i + 1];
1302:                     if ($nextChar === ' ' || $nextChar === '<') {
1303:                         $formatted[] = trim($tmpLine);
1304:                         $tmpLine = '';
1305:                         $tmpLineLength = 0;
1306:                         if ($nextChar === ' ') {
1307:                             $i++;
1308:                         }
1309:                     } else {
1310:                         $lastSpace = strrpos($tmpLine, ' ');
1311:                         if ($lastSpace === false) {
1312:                             continue;
1313:                         }
1314:                         $formatted[] = trim(substr($tmpLine, 0, $lastSpace));
1315:                         $tmpLine = substr($tmpLine, $lastSpace + 1);
1316: 
1317:                         $tmpLineLength = strlen($tmpLine);
1318:                     }
1319:                 }
1320:             }
1321:             if (!empty($tmpLine)) {
1322:                 $formatted[] = $tmpLine;
1323:             }
1324:         }
1325:         $formatted[] = '';
1326:         return $formatted;
1327:     }
1328: 
1329: /**
1330:  * Create unique boundary identifier
1331:  *
1332:  * @return void
1333:  */
1334:     protected function _createBoundary() {
1335:         if (!empty($this->_attachments) || $this->_emailFormat === 'both') {
1336:             $this->_boundary = md5(uniqid(time()));
1337:         }
1338:     }
1339: 
1340: /**
1341:  * Attach non-embedded files by adding file contents inside boundaries.
1342:  *
1343:  * @param string $boundary Boundary to use. If null, will default to $this->_boundary
1344:  * @return array An array of lines to add to the message
1345:  */
1346:     protected function _attachFiles($boundary = null) {
1347:         if ($boundary === null) {
1348:             $boundary = $this->_boundary;
1349:         }
1350: 
1351:         $msg = array();
1352:         foreach ($this->_attachments as $filename => $fileInfo) {
1353:             if (!empty($fileInfo['contentId'])) {
1354:                 continue;
1355:             }
1356:             $data = $this->_readFile($fileInfo['file']);
1357: 
1358:             $msg[] = '--' . $boundary;
1359:             $msg[] = 'Content-Type: ' . $fileInfo['mimetype'];
1360:             $msg[] = 'Content-Transfer-Encoding: base64';
1361:             $msg[] = 'Content-Disposition: attachment; filename="' . $filename . '"';
1362:             $msg[] = '';
1363:             $msg[] = $data;
1364:             $msg[] = '';
1365:         }
1366:         return $msg;
1367:     }
1368: 
1369: /**
1370:  * Read the file contents and return a base64 version of the file contents.
1371:  *
1372:  * @param string $file The file to read.
1373:  * @return string File contents in base64 encoding
1374:  */
1375:     protected function _readFile($file) {
1376:         $handle = fopen($file, 'rb');
1377:         $data = fread($handle, filesize($file));
1378:         $data = chunk_split(base64_encode($data));
1379:         fclose($handle);
1380:         return $data;
1381:     }
1382: 
1383: /**
1384:  * Attach inline/embedded files to the message.
1385:  *
1386:  * @param string $boundary Boundary to use. If null, will default to $this->_boundary
1387:  * @return array An array of lines to add to the message
1388:  */
1389:     protected function _attachInlineFiles($boundary = null) {
1390:         if ($boundary === null) {
1391:             $boundary = $this->_boundary;
1392:         }
1393: 
1394:         $msg = array();
1395:         foreach ($this->_attachments as $filename => $fileInfo) {
1396:             if (empty($fileInfo['contentId'])) {
1397:                 continue;
1398:             }
1399:             $data = $this->_readFile($fileInfo['file']);
1400: 
1401:             $msg[] = '--' . $boundary;
1402:             $msg[] = 'Content-Type: ' . $fileInfo['mimetype'];
1403:             $msg[] = 'Content-Transfer-Encoding: base64';
1404:             $msg[] = 'Content-ID: <' . $fileInfo['contentId'] . '>';
1405:             $msg[] = 'Content-Disposition: inline; filename="' . $filename . '"';
1406:             $msg[] = '';
1407:             $msg[] = $data;
1408:             $msg[] = '';
1409:         }
1410:         return $msg;
1411:     }
1412: 
1413: /**
1414:  * Render the body of the email.
1415:  *
1416:  * @param string $content Content to render
1417:  * @return array Email body ready to be sent
1418:  */
1419:     protected function _render($content) {
1420:         $content = implode("\n", $content);
1421:         $rendered = $this->_renderTemplates($content);
1422: 
1423:         $msg = array();
1424: 
1425:         $contentIds = array_filter((array)Hash::extract($this->_attachments, '{s}.contentId'));
1426:         $hasInlineAttachments = count($contentIds) > 0;
1427:         $hasAttachments = !empty($this->_attachments);
1428:         $hasMultipleTypes = count($rendered) > 1;
1429: 
1430:         $boundary = $relBoundary = $textBoundary = $this->_boundary;
1431: 
1432:         if ($hasInlineAttachments) {
1433:             $msg[] = '--' . $boundary;
1434:             $msg[] = 'Content-Type: multipart/related; boundary="rel-' . $boundary . '"';
1435:             $msg[] = '';
1436:             $relBoundary = $textBoundary = 'rel-' . $boundary;
1437:         }
1438: 
1439:         if ($hasMultipleTypes) {
1440:             $msg[] = '--' . $relBoundary;
1441:             $msg[] = 'Content-Type: multipart/alternative; boundary="alt-' . $boundary . '"';
1442:             $msg[] = '';
1443:             $textBoundary = 'alt-' . $boundary;
1444:         }
1445: 
1446:         if (isset($rendered['text'])) {
1447:             if ($textBoundary !== $boundary || $hasAttachments) {
1448:                 $msg[] = '--' . $textBoundary;
1449:                 $msg[] = 'Content-Type: text/plain; charset=' . $this->_getContentTypeCharset();
1450:                 $msg[] = 'Content-Transfer-Encoding: ' . $this->_getContentTransferEncoding();
1451:                 $msg[] = '';
1452:             }
1453:             $this->_textMessage = $rendered['text'];
1454:             $content = explode("\n", $this->_textMessage);
1455:             $msg = array_merge($msg, $content);
1456:             $msg[] = '';
1457:         }
1458: 
1459:         if (isset($rendered['html'])) {
1460:             if ($textBoundary !== $boundary || $hasAttachments) {
1461:                 $msg[] = '--' . $textBoundary;
1462:                 $msg[] = 'Content-Type: text/html; charset=' . $this->_getContentTypeCharset();
1463:                 $msg[] = 'Content-Transfer-Encoding: ' . $this->_getContentTransferEncoding();
1464:                 $msg[] = '';
1465:             }
1466:             $this->_htmlMessage = $rendered['html'];
1467:             $content = explode("\n", $this->_htmlMessage);
1468:             $msg = array_merge($msg, $content);
1469:             $msg[] = '';
1470:         }
1471: 
1472:         if ($hasMultipleTypes) {
1473:             $msg[] = '--' . $textBoundary . '--';
1474:             $msg[] = '';
1475:         }
1476: 
1477:         if ($hasInlineAttachments) {
1478:             $attachments = $this->_attachInlineFiles($relBoundary);
1479:             $msg = array_merge($msg, $attachments);
1480:             $msg[] = '';
1481:             $msg[] = '--' . $relBoundary . '--';
1482:             $msg[] = '';
1483:         }
1484: 
1485:         if ($hasAttachments) {
1486:             $attachments = $this->_attachFiles($boundary);
1487:             $msg = array_merge($msg, $attachments);
1488:         }
1489:         if ($hasAttachments || $hasMultipleTypes) {
1490:             $msg[] = '';
1491:             $msg[] = '--' . $boundary . '--';
1492:             $msg[] = '';
1493:         }
1494:         return $msg;
1495:     }
1496: 
1497: /**
1498:  * Gets the text body types that are in this email message
1499:  *
1500:  * @return array Array of types.  Valid types are 'text' and 'html'
1501:  */
1502:     protected function _getTypes() {
1503:         $types = array($this->_emailFormat);
1504:         if ($this->_emailFormat == 'both') {
1505:             $types = array('html', 'text');
1506:         }
1507:         return $types;
1508:     }
1509: 
1510: /**
1511:  * Build and set all the view properties needed to render the templated emails.
1512:  * If there is no template set, the $content will be returned in a hash
1513:  * of the text content types for the email.
1514:  *
1515:  * @param string $content The content passed in from send() in most cases.
1516:  * @return array The rendered content with html and text keys.
1517:  */
1518:     protected function _renderTemplates($content) {
1519:         $types = $this->_getTypes();
1520:         $rendered = array();
1521:         if (empty($this->_template)) {
1522:             foreach ($types as $type) {
1523:                 $rendered[$type] = $this->_encodeString($content, $this->charset);
1524:             }
1525:             return $rendered;
1526:         }
1527:         $viewClass = $this->_viewRender;
1528:         if ($viewClass !== 'View') {
1529:             list($plugin, $viewClass) = pluginSplit($viewClass, true);
1530:             $viewClass .= 'View';
1531:             App::uses($viewClass, $plugin . 'View');
1532:         }
1533: 
1534:         $View = new $viewClass(null);
1535:         $View->viewVars = $this->_viewVars;
1536:         $View->helpers = $this->_helpers;
1537: 
1538:         list($templatePlugin, $template) = pluginSplit($this->_template);
1539:         list($layoutPlugin, $layout) = pluginSplit($this->_layout);
1540:         if ($templatePlugin) {
1541:             $View->plugin = $templatePlugin;
1542:         } elseif ($layoutPlugin) {
1543:             $View->plugin = $layoutPlugin;
1544:         }
1545:         if ($this->_theme) {
1546:             $View->theme = $this->_theme;
1547:         }
1548: 
1549:         foreach ($types as $type) {
1550:             $View->set('content', $content);
1551:             $View->hasRendered = false;
1552:             $View->viewPath = $View->layoutPath = 'Emails' . DS . $type;
1553: 
1554:             $render = $View->render($template, $layout);
1555:             $render = str_replace(array("\r\n", "\r"), "\n", $render);
1556:             $rendered[$type] = $this->_encodeString($render, $this->charset);
1557:         }
1558:         return $rendered;
1559:     }
1560: 
1561: /**
1562:  * Return the Content-Transfer Encoding value based on the set charset
1563:  *
1564:  * @return void
1565:  */
1566:     protected function _getContentTransferEncoding() {
1567:         $charset = strtoupper($this->charset);
1568:         if (in_array($charset, $this->_charset8bit)) {
1569:             return '8bit';
1570:         }
1571:         return '7bit';
1572:     }
1573: 
1574: /**
1575:  * Return charset value for Content-Type.
1576:  *
1577:  * Checks fallback/compatibility types which include workarounds
1578:  * for legacy japanese character sets.
1579:  *
1580:  * @return string
1581:  */
1582:     protected function _getContentTypeCharset() {
1583:         $charset = strtoupper($this->charset);
1584:         if (array_key_exists($charset, $this->_contentTypeCharset)) {
1585:             return strtoupper($this->_contentTypeCharset[$charset]);
1586:         } else {
1587:             return strtoupper($this->charset);
1588:         }
1589:     }
1590: 
1591: }
1592: 
OpenHub
Rackspace
Rackspace
  • Business Solutions
  • Showcase
  • Documentation
  • Book
  • API
  • Videos
  • Reporting Security Issues
  • Privacy Policy
  • Logos & Trademarks
  • Community
  • Get Involved
  • Issues (GitHub)
  • Bakery
  • Featured Resources
  • Training
  • Meetups
  • My CakePHP
  • CakeFest
  • Newsletter
  • Linkedin
  • YouTube
  • Facebook
  • Twitter
  • Mastodon
  • Help & Support
  • Forum
  • Stack Overflow
  • Slack
  • Paid Support

Generated using CakePHP API Docs