GAzie PHP Cross Reference Customer Relationship Management

Source: /library/phpmailer/class.phpmailer.php - 2320 lines - 74526 bytes - Summary - Text - Print

Description: PHPMailer - PHP email transport class NOTE: Requires PHP version 5 or later

   1  <?php
   2  /*~ class.phpmailer.php
   3  .---------------------------------------------------------------------------.
   4  |  Software: PHPMailer - PHP email class                                    |
   5  |   Version: 5.1                                                            |
   6  |   Contact: via sourceforge.net support pages (also www.worxware.com)      |
   7  |      Info: http://phpmailer.sourceforge.net                               |
   8  |   Support: http://sourceforge.net/projects/phpmailer/                     |
   9  | ------------------------------------------------------------------------- |
  10  |     Admin: Andy Prevost (project admininistrator)                         |
  11  |   Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
  12  |          : Marcus Bointon (coolbru) coolbru@users.sourceforge.net         |
  13  |   Founder: Brent R. Matzelle (original founder)                           |
  14  | Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved.               |
  15  | Copyright (c) 2001-2003, Brent R. Matzelle                                |
  16  | ------------------------------------------------------------------------- |
  17  |   License: Distributed under the Lesser General Public License (LGPL)     |
  18  |            http://www.gnu.org/copyleft/lesser.html                        |
  19  | This program is distributed in the hope that it will be useful - WITHOUT  |
  20  | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or     |
  21  | FITNESS FOR A PARTICULAR PURPOSE.                                         |
  22  | ------------------------------------------------------------------------- |
  23  | We offer a number of paid services (www.worxware.com):                    |
  24  | - Web Hosting on highly optimized fast and secure servers                 |
  25  | - Technology Consulting                                                   |
  26  | - Oursourcing (highly qualified programmers and graphic designers)        |
  27  '---------------------------------------------------------------------------'
  28  */
  29  
  30  /**
  31   * PHPMailer - PHP email transport class
  32   * NOTE: Requires PHP version 5 or later
  33   * @package PHPMailer
  34   * @author Andy Prevost
  35   * @author Marcus Bointon
  36   * @copyright 2004 - 2009 Andy Prevost
  37   * @version $Id: class.phpmailer.php 447 2009-05-25 01:36:38Z codeworxtech $
  38   * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  39   */
  40  
  41  if (version_compare(PHP_VERSION, '5.0.0', '<') ) exit("Sorry, this version of PHPMailer will only run on PHP version 5 or greater!\n");
  42  
  43  class PHPMailer {
  44  
  45    /////////////////////////////////////////////////
  46    // PROPERTIES, PUBLIC
  47    /////////////////////////////////////////////////
  48  
  49    /**
  50     * Email priority (1 = High, 3 = Normal, 5 = low).
  51     * @var int
  52     */
  53    public $Priority          = 3;
  54  
  55    /**
  56     * Sets the CharSet of the message.
  57     * @var string
  58     */
  59    public $CharSet           = 'iso-8859-1';
  60  
  61    /**
  62     * Sets the Content-type of the message.
  63     * @var string
  64     */
  65    public $ContentType       = 'text/plain';
  66  
  67    /**
  68     * Sets the Encoding of the message. Options for this are
  69     *  "8bit", "7bit", "binary", "base64", and "quoted-printable".
  70     * @var string
  71     */
  72    public $Encoding          = '8bit';
  73  
  74    /**
  75     * Holds the most recent mailer error message.
  76     * @var string
  77     */
  78    public $ErrorInfo         = '';
  79  
  80    /**
  81     * Sets the From email address for the message.
  82     * @var string
  83     */
  84    public $From              = 'root@localhost';
  85  
  86    /**
  87     * Sets the From name of the message.
  88     * @var string
  89     */
  90    public $FromName          = 'Root User';
  91  
  92    /**
  93     * Sets the Sender email (Return-Path) of the message.  If not empty,
  94     * will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
  95     * @var string
  96     */
  97    public $Sender            = '';
  98  
  99    /**
 100     * Sets the Subject of the message.
 101     * @var string
 102     */
 103    public $Subject           = '';
 104  
 105    /**
 106     * Sets the Body of the message.  This can be either an HTML or text body.
 107     * If HTML then run IsHTML(true).
 108     * @var string
 109     */
 110    public $Body              = '';
 111  
 112    /**
 113     * Sets the text-only body of the message.  This automatically sets the
 114     * email to multipart/alternative.  This body can be read by mail
 115     * clients that do not have HTML email capability such as mutt. Clients
 116     * that can read HTML will view the normal Body.
 117     * @var string
 118     */
 119    public $AltBody           = '';
 120  
 121    /**
 122     * Sets word wrapping on the body of the message to a given number of
 123     * characters.
 124     * @var int
 125     */
 126    public $WordWrap          = 0;
 127  
 128    /**
 129     * Method to send mail: ("mail", "sendmail", or "smtp").
 130     * @var string
 131     */
 132    public $Mailer            = 'mail';
 133  
 134    /**
 135     * Sets the path of the sendmail program.
 136     * @var string
 137     */
 138    public $Sendmail          = '/usr/sbin/sendmail';
 139  
 140    /**
 141     * Path to PHPMailer plugins.  Useful if the SMTP class
 142     * is in a different directory than the PHP include path.
 143     * @var string
 144     */
 145    public $PluginDir         = '';
 146  
 147    /**
 148     * Sets the email address that a reading confirmation will be sent.
 149     * @var string
 150     */
 151    public $ConfirmReadingTo  = '';
 152  
 153    /**
 154     * Sets the hostname to use in Message-Id and Received headers
 155     * and as default HELO string. If empty, the value returned
 156     * by SERVER_NAME is used or 'localhost.localdomain'.
 157     * @var string
 158     */
 159    public $Hostname          = '';
 160  
 161    /**
 162     * Sets the message ID to be used in the Message-Id header.
 163     * If empty, a unique id will be generated.
 164     * @var string
 165     */
 166    public $MessageID         = '';
 167  
 168    /////////////////////////////////////////////////
 169    // PROPERTIES FOR SMTP
 170    /////////////////////////////////////////////////
 171  
 172    /**
 173     * Sets the SMTP hosts.  All hosts must be separated by a
 174     * semicolon.  You can also specify a different port
 175     * for each host by using this format: [hostname:port]
 176     * (e.g. "smtp1.example.com:25;smtp2.example.com").
 177     * Hosts will be tried in order.
 178     * @var string
 179     */
 180    public $Host          = 'localhost';
 181  
 182    /**
 183     * Sets the default SMTP server port.
 184     * @var int
 185     */
 186    public $Port          = 25;
 187  
 188    /**
 189     * Sets the SMTP HELO of the message (Default is $Hostname).
 190     * @var string
 191     */
 192    public $Helo          = '';
 193  
 194    /**
 195     * Sets connection prefix.
 196     * Options are "", "ssl" or "tls"
 197     * @var string
 198     */
 199    public $SMTPSecure    = '';
 200  
 201    /**
 202     * Sets SMTP authentication. Utilizes the Username and Password variables.
 203     * @var bool
 204     */
 205    public $SMTPAuth      = false;
 206  
 207    /**
 208     * Sets SMTP username.
 209     * @var string
 210     */
 211    public $Username      = '';
 212  
 213    /**
 214     * Sets SMTP password.
 215     * @var string
 216     */
 217    public $Password      = '';
 218  
 219    /**
 220     * Sets the SMTP server timeout in seconds.
 221     * This function will not work with the win32 version.
 222     * @var int
 223     */
 224    public $Timeout       = 10;
 225  
 226    /**
 227     * Sets SMTP class debugging on or off.
 228     * @var bool
 229     */
 230    public $SMTPDebug     = false;
 231  
 232    /**
 233     * Prevents the SMTP connection from being closed after each mail
 234     * sending.  If this is set to true then to close the connection
 235     * requires an explicit call to SmtpClose().
 236     * @var bool
 237     */
 238    public $SMTPKeepAlive = false;
 239  
 240    /**
 241     * Provides the ability to have the TO field process individual
 242     * emails, instead of sending to entire TO addresses
 243     * @var bool
 244     */
 245    public $SingleTo      = false;
 246  
 247     /**
 248     * If SingleTo is true, this provides the array to hold the email addresses
 249     * @var bool
 250     */
 251    public $SingleToArray = array();
 252  
 253   /**
 254     * Provides the ability to change the line ending
 255     * @var string
 256     */
 257    public $LE              = "\n";
 258  
 259    /**
 260     * Used with DKIM DNS Resource Record
 261     * @var string
 262     */
 263    public $DKIM_selector   = 'phpmailer';
 264  
 265    /**
 266     * Used with DKIM DNS Resource Record
 267     * optional, in format of email address 'you@yourdomain.com'
 268     * @var string
 269     */
 270    public $DKIM_identity   = '';
 271  
 272    /**
 273     * Used with DKIM DNS Resource Record
 274     * optional, in format of email address 'you@yourdomain.com'
 275     * @var string
 276     */
 277    public $DKIM_domain     = '';
 278  
 279    /**
 280     * Used with DKIM DNS Resource Record
 281     * optional, in format of email address 'you@yourdomain.com'
 282     * @var string
 283     */
 284    public $DKIM_private    = '';
 285  
 286    /**
 287     * Callback Action function name
 288     * the function that handles the result of the send email action. Parameters:
 289     *   bool    $result        result of the send action
 290     *   string  $to            email address of the recipient
 291     *   string  $cc            cc email addresses
 292     *   string  $bcc           bcc email addresses
 293     *   string  $subject       the subject
 294     *   string  $body          the email body
 295     * @var string
 296     */
 297    public $action_function = ''; //'callbackAction';
 298  
 299    /**
 300     * Sets the PHPMailer Version number
 301     * @var string
 302     */
 303    public $Version         = '5.1';
 304  
 305    /////////////////////////////////////////////////
 306    // PROPERTIES, PRIVATE AND PROTECTED
 307    /////////////////////////////////////////////////
 308  
 309    private   $smtp           = NULL;
 310    private   $to             = array();
 311    private   $cc             = array();
 312    private   $bcc            = array();
 313    private   $ReplyTo        = array();
 314    private   $all_recipients = array();
 315    private   $attachment     = array();
 316    private   $CustomHeader   = array();
 317    private   $message_type   = '';
 318    private   $boundary       = array();
 319    protected $language       = array();
 320    private   $error_count    = 0;
 321    private   $sign_cert_file = "";
 322    private   $sign_key_file  = "";
 323    private   $sign_key_pass  = "";
 324    private   $exceptions     = false;
 325  
 326    /////////////////////////////////////////////////
 327    // CONSTANTS
 328    /////////////////////////////////////////////////
 329  
 330    const STOP_MESSAGE  = 0; // message only, continue processing
 331    const STOP_CONTINUE = 1; // message?, likely ok to continue processing
 332    const STOP_CRITICAL = 2; // message, plus full stop, critical error reached
 333  
 334    /////////////////////////////////////////////////
 335    // METHODS, VARIABLES
 336    /////////////////////////////////////////////////
 337  
 338    /**
 339     * Constructor
 340     * @param boolean $exceptions Should we throw external exceptions?
 341     */
 342    public function __construct($exceptions = false) {
 343      $this->exceptions = ($exceptions == true);
 344    }
 345  
 346    /**
 347     * Sets message type to HTML.
 348     * @param bool $ishtml
 349     * @return void
 350     */
 351    public function IsHTML($ishtml = true) {
 352      if ($ishtml) {
 353        $this->ContentType = 'text/html';
 354      } else {
 355        $this->ContentType = 'text/plain';
 356      }
 357    }
 358  
 359    /**
 360     * Sets Mailer to send message using SMTP.
 361     * @return void
 362     */
 363    public function IsSMTP() {
 364      $this->Mailer = 'smtp';
 365    }
 366  
 367    /**
 368     * Sets Mailer to send message using PHP mail() function.
 369     * @return void
 370     */
 371    public function IsMail() {
 372      $this->Mailer = 'mail';
 373    }
 374  
 375    /**
 376     * Sets Mailer to send message using the $Sendmail program.
 377     * @return void
 378     */
 379    public function IsSendmail() {
 380      if (!stristr(ini_get('sendmail_path'), 'sendmail')) {
 381        $this->Sendmail = '/var/qmail/bin/sendmail';
 382      }
 383      $this->Mailer = 'sendmail';
 384    }
 385  
 386    /**
 387     * Sets Mailer to send message using the qmail MTA.
 388     * @return void
 389     */
 390    public function IsQmail() {
 391      if (stristr(ini_get('sendmail_path'), 'qmail')) {
 392        $this->Sendmail = '/var/qmail/bin/sendmail';
 393      }
 394      $this->Mailer = 'sendmail';
 395    }
 396  
 397    /////////////////////////////////////////////////
 398    // METHODS, RECIPIENTS
 399    /////////////////////////////////////////////////
 400  
 401    /**
 402     * Adds a "To" address.
 403     * @param string $address
 404     * @param string $name
 405     * @return boolean true on success, false if address already used
 406     */
 407    public function AddAddress($address, $name = '') {
 408      return $this->AddAnAddress('to', $address, $name);
 409    }
 410  
 411    /**
 412     * Adds a "Cc" address.
 413     * Note: this function works with the SMTP mailer on win32, not with the "mail" mailer.
 414     * @param string $address
 415     * @param string $name
 416     * @return boolean true on success, false if address already used
 417     */
 418    public function AddCC($address, $name = '') {
 419      return $this->AddAnAddress('cc', $address, $name);
 420    }
 421  
 422    /**
 423     * Adds a "Bcc" address.
 424     * Note: this function works with the SMTP mailer on win32, not with the "mail" mailer.
 425     * @param string $address
 426     * @param string $name
 427     * @return boolean true on success, false if address already used
 428     */
 429    public function AddBCC($address, $name = '') {
 430      return $this->AddAnAddress('bcc', $address, $name);
 431    }
 432  
 433    /**
 434     * Adds a "Reply-to" address.
 435     * @param string $address
 436     * @param string $name
 437     * @return boolean
 438     */
 439    public function AddReplyTo($address, $name = '') {
 440      return $this->AddAnAddress('ReplyTo', $address, $name);
 441    }
 442  
 443    /**
 444     * Adds an address to one of the recipient arrays
 445     * Addresses that have been added already return false, but do not throw exceptions
 446     * @param string $kind One of 'to', 'cc', 'bcc', 'ReplyTo'
 447     * @param string $address The email address to send to
 448     * @param string $name
 449     * @return boolean true on success, false if address already used or invalid in some way
 450     * @access private
 451     */
 452    private function AddAnAddress($kind, $address, $name = '') {
 453      if (!preg_match('/^(to|cc|bcc|ReplyTo)$/', $kind)) {
 454        echo 'Invalid recipient array: ' . kind;
 455        return false;
 456      }
 457      $address = trim($address);
 458      $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
 459      if (!self::ValidateAddress($address)) {
 460        $this->SetError($this->Lang('invalid_address').': '. $address);
 461        if ($this->exceptions) {
 462          throw new phpmailerException($this->Lang('invalid_address').': '.$address);
 463        }
 464        echo $this->Lang('invalid_address').': '.$address;
 465        return false;
 466      }
 467      if ($kind != 'ReplyTo') {
 468        if (!isset($this->all_recipients[strtolower($address)])) {
 469          array_push($this->$kind, array($address, $name));
 470          $this->all_recipients[strtolower($address)] = true;
 471          return true;
 472        }
 473      } else {
 474        if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
 475          $this->ReplyTo[strtolower($address)] = array($address, $name);
 476        return true;
 477      }
 478    }
 479    return false;
 480  }
 481  
 482  /**
 483   * Set the From and FromName properties
 484   * @param string $address
 485   * @param string $name
 486   * @return boolean
 487   */
 488    public function SetFrom($address, $name = '',$auto=1) {
 489      $address = trim($address);
 490      $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
 491      if (!self::ValidateAddress($address)) {
 492        $this->SetError($this->Lang('invalid_address').': '. $address);
 493        if ($this->exceptions) {
 494          throw new phpmailerException($this->Lang('invalid_address').': '.$address);
 495        }
 496        echo $this->Lang('invalid_address').': '.$address;
 497        return false;
 498      }
 499      $this->From = $address;
 500      $this->FromName = $name;
 501      if ($auto) {
 502        if (empty($this->ReplyTo)) {
 503          $this->AddAnAddress('ReplyTo', $address, $name);
 504        }
 505        if (empty($this->Sender)) {
 506          $this->Sender = $address;
 507        }
 508      }
 509      return true;
 510    }
 511  
 512    /**
 513     * Check that a string looks roughly like an email address should
 514     * Static so it can be used without instantiation
 515     * Tries to use PHP built-in validator in the filter extension (from PHP 5.2), falls back to a reasonably competent regex validator
 516     * Conforms approximately to RFC2822
 517     * @link http://www.hexillion.com/samples/#Regex Original pattern found here
 518     * @param string $address The email address to check
 519     * @return boolean
 520     * @static
 521     * @access public
 522     */
 523    public static function ValidateAddress($address) {
 524      if (function_exists('filter_var')) { //Introduced in PHP 5.2
 525        if(filter_var($address, FILTER_VALIDATE_EMAIL) === FALSE) {
 526          return false;
 527        } else {
 528          return true;
 529        }
 530      } else {
 531        return preg_match('/^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!\.)){0,61}[a-zA-Z0-9_-]?\.)+[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!$)){0,61}[a-zA-Z0-9_]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/', $address);
 532      }
 533    }
 534  
 535    /////////////////////////////////////////////////
 536    // METHODS, MAIL SENDING
 537    /////////////////////////////////////////////////
 538  
 539    /**
 540     * Creates message and assigns Mailer. If the message is
 541     * not sent successfully then it returns false.  Use the ErrorInfo
 542     * variable to view description of the error.
 543     * @return bool
 544     */
 545    public function Send() {
 546      try {
 547        if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
 548          throw new phpmailerException($this->Lang('provide_address'), self::STOP_CRITICAL);
 549        }
 550  
 551        // Set whether the message is multipart/alternative
 552        if(!empty($this->AltBody)) {
 553          $this->ContentType = 'multipart/alternative';
 554        }
 555  
 556        $this->error_count = 0; // reset errors
 557        $this->SetMessageType();
 558        $header = $this->CreateHeader();
 559        $body = $this->CreateBody();
 560  
 561        if (empty($this->Body)) {
 562          throw new phpmailerException($this->Lang('empty_message'), self::STOP_CRITICAL);
 563        }
 564  
 565        // digitally sign with DKIM if enabled
 566        if ($this->DKIM_domain && $this->DKIM_private) {
 567          $header_dkim = $this->DKIM_Add($header,$this->Subject,$body);
 568          $header = str_replace("\r\n","\n",$header_dkim) . $header;
 569        }
 570  
 571        // Choose the mailer and send through it
 572        switch($this->Mailer) {
 573          case 'sendmail':
 574            return $this->SendmailSend($header, $body);
 575          case 'smtp':
 576            return $this->SmtpSend($header, $body);
 577          default:
 578            return $this->MailSend($header, $body);
 579        }
 580  
 581      } catch (phpmailerException $e) {
 582        $this->SetError($e->getMessage());
 583        if ($this->exceptions) {
 584          throw $e;
 585        }
 586        echo $e->getMessage()."\n";
 587        return false;
 588      }
 589    }
 590  
 591    /**
 592     * Sends mail using the $Sendmail program.
 593     * @param string $header The message headers
 594     * @param string $body The message body
 595     * @access protected
 596     * @return bool
 597     */
 598    protected function SendmailSend($header, $body) {
 599      if ($this->Sender != '') {
 600        $sendmail = sprintf("%s -oi -f %s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
 601      } else {
 602        $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail));
 603      }
 604      if ($this->SingleTo === true) {
 605        foreach ($this->SingleToArray as $key => $val) {
 606          if(!@$mail = popen($sendmail, 'w')) {
 607            throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
 608          }
 609          fputs($mail, "To: " . $val . "\n");
 610          fputs($mail, $header);
 611          fputs($mail, $body);
 612          $result = pclose($mail);
 613          // implement call back function if it exists
 614          $isSent = ($result == 0) ? 1 : 0;
 615          $this->doCallback($isSent,$val,$this->cc,$this->bcc,$this->Subject,$body);
 616          if($result != 0) {
 617            throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
 618          }
 619        }
 620      } else {
 621        if(!@$mail = popen($sendmail, 'w')) {
 622          throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
 623        }
 624        fputs($mail, $header);
 625        fputs($mail, $body);
 626        $result = pclose($mail);
 627        // implement call back function if it exists
 628        $isSent = ($result == 0) ? 1 : 0;
 629        $this->doCallback($isSent,$this->to,$this->cc,$this->bcc,$this->Subject,$body);
 630        if($result != 0) {
 631          throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
 632        }
 633      }
 634      return true;
 635    }
 636  
 637    /**
 638     * Sends mail using the PHP mail() function.
 639     * @param string $header The message headers
 640     * @param string $body The message body
 641     * @access protected
 642     * @return bool
 643     */
 644    protected function MailSend($header, $body) {
 645      $toArr = array();
 646      foreach($this->to as $t) {
 647        $toArr[] = $this->AddrFormat($t);
 648      }
 649      $to = implode(', ', $toArr);
 650  
 651      $params = sprintf("-oi -f %s", $this->Sender);
 652      if ($this->Sender != '' && strlen(ini_get('safe_mode'))< 1) {
 653        $old_from = ini_get('sendmail_from');
 654        ini_set('sendmail_from', $this->Sender);
 655        if ($this->SingleTo === true && count($toArr) > 1) {
 656          foreach ($toArr as $key => $val) {
 657            $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
 658            // implement call back function if it exists
 659            $isSent = ($rt == 1) ? 1 : 0;
 660            $this->doCallback($isSent,$val,$this->cc,$this->bcc,$this->Subject,$body);
 661          }
 662        } else {
 663          $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
 664          // implement call back function if it exists
 665          $isSent = ($rt == 1) ? 1 : 0;
 666          $this->doCallback($isSent,$to,$this->cc,$this->bcc,$this->Subject,$body);
 667        }
 668      } else {
 669        if ($this->SingleTo === true && count($toArr) > 1) {
 670          foreach ($toArr as $key => $val) {
 671            $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
 672            // implement call back function if it exists
 673            $isSent = ($rt == 1) ? 1 : 0;
 674            $this->doCallback($isSent,$val,$this->cc,$this->bcc,$this->Subject,$body);
 675          }
 676        } else {
 677          $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header);
 678          // implement call back function if it exists
 679          $isSent = ($rt == 1) ? 1 : 0;
 680          $this->doCallback($isSent,$to,$this->cc,$this->bcc,$this->Subject,$body);
 681        }
 682      }
 683      if (isset($old_from)) {
 684        ini_set('sendmail_from', $old_from);
 685      }
 686      if(!$rt) {
 687        throw new phpmailerException($this->Lang('instantiate'), self::STOP_CRITICAL);
 688      }
 689      return true;
 690    }
 691  
 692    /**
 693     * Sends mail via SMTP using PhpSMTP
 694     * Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
 695     * @param string $header The message headers
 696     * @param string $body The message body
 697     * @uses SMTP
 698     * @access protected
 699     * @return bool
 700     */
 701    protected function SmtpSend($header, $body) {
 702      require_once $this->PluginDir . 'class.smtp.php';
 703      $bad_rcpt = array();
 704  
 705      if(!$this->SmtpConnect()) {
 706        throw new phpmailerException($this->Lang('smtp_connect_failed'), self::STOP_CRITICAL);
 707      }
 708      $smtp_from = ($this->Sender == '') ? $this->From : $this->Sender;
 709      if(!$this->smtp->Mail($smtp_from)) {
 710        throw new phpmailerException($this->Lang('from_failed') . $smtp_from, self::STOP_CRITICAL);
 711      }
 712  
 713      // Attempt to send attach all recipients
 714      foreach($this->to as $to) {
 715        if (!$this->smtp->Recipient($to[0])) {
 716          $bad_rcpt[] = $to[0];
 717          // implement call back function if it exists
 718          $isSent = 0;
 719          $this->doCallback($isSent,$to[0],'','',$this->Subject,$body);
 720        } else {
 721          // implement call back function if it exists
 722          $isSent = 1;
 723          $this->doCallback($isSent,$to[0],'','',$this->Subject,$body);
 724        }
 725      }
 726      foreach($this->cc as $cc) {
 727        if (!$this->smtp->Recipient($cc[0])) {
 728          $bad_rcpt[] = $cc[0];
 729          // implement call back function if it exists
 730          $isSent = 0;
 731          $this->doCallback($isSent,'',$cc[0],'',$this->Subject,$body);
 732        } else {
 733          // implement call back function if it exists
 734          $isSent = 1;
 735          $this->doCallback($isSent,'',$cc[0],'',$this->Subject,$body);
 736        }
 737      }
 738      foreach($this->bcc as $bcc) {
 739        if (!$this->smtp->Recipient($bcc[0])) {
 740          $bad_rcpt[] = $bcc[0];
 741          // implement call back function if it exists
 742          $isSent = 0;
 743          $this->doCallback($isSent,'','',$bcc[0],$this->Subject,$body);
 744        } else {
 745          // implement call back function if it exists
 746          $isSent = 1;
 747          $this->doCallback($isSent,'','',$bcc[0],$this->Subject,$body);
 748        }
 749      }
 750  
 751  
 752      if (count($bad_rcpt) > 0 ) { //Create error message for any bad addresses
 753        $badaddresses = implode(', ', $bad_rcpt);
 754        throw new phpmailerException($this->Lang('recipients_failed') . $badaddresses);
 755      }
 756      if(!$this->smtp->Data($header . $body)) {
 757        throw new phpmailerException($this->Lang('data_not_accepted'), self::STOP_CRITICAL);
 758      }
 759      if($this->SMTPKeepAlive == true) {
 760        $this->smtp->Reset();
 761      }
 762      return true;
 763    }
 764  
 765    /**
 766     * Initiates a connection to an SMTP server.
 767     * Returns false if the operation failed.
 768     * @uses SMTP
 769     * @access public
 770     * @return bool
 771     */
 772    public function SmtpConnect() {
 773      if(is_null($this->smtp)) {
 774        $this->smtp = new SMTP();
 775      }
 776  
 777      $this->smtp->do_debug = $this->SMTPDebug;
 778      $hosts = explode(';', $this->Host);
 779      $index = 0;
 780      $connection = $this->smtp->Connected();
 781  
 782      // Retry while there is no connection
 783      try {
 784        while($index < count($hosts) && !$connection) {
 785          $hostinfo = array();
 786          if (preg_match('/^(.+):([0-9]+)$/', $hosts[$index], $hostinfo)) {
 787            $host = $hostinfo[1];
 788            $port = $hostinfo[2];
 789          } else {
 790            $host = $hosts[$index];
 791            $port = $this->Port;
 792          }
 793  
 794          $tls = ($this->SMTPSecure == 'tls');
 795          $ssl = ($this->SMTPSecure == 'ssl');
 796  
 797          if ($this->smtp->Connect(($ssl ? 'ssl://':'').$host, $port, $this->Timeout)) {
 798  
 799            $hello = ($this->Helo != '' ? $this->Helo : $this->ServerHostname());
 800            $this->smtp->Hello($hello);
 801  
 802            if ($tls) {
 803              if (!$this->smtp->StartTLS()) {
 804                throw new phpmailerException($this->Lang('tls'));
 805              }
 806  
 807              //We must resend HELO after tls negotiation
 808              $this->smtp->Hello($hello);
 809            }
 810  
 811            $connection = true;
 812            if ($this->SMTPAuth) {
 813              if (!$this->smtp->Authenticate($this->Username, $this->Password)) {
 814                throw new phpmailerException($this->Lang('authenticate'));
 815              }
 816            }
 817          }
 818          $index++;
 819          if (!$connection) {
 820            throw new phpmailerException($this->Lang('connect_host'));
 821          }
 822        }
 823      } catch (phpmailerException $e) {
 824        $this->smtp->Reset();
 825        throw $e;
 826      }
 827      return true;
 828    }
 829  
 830    /**
 831     * Closes the active SMTP session if one exists.
 832     * @return void
 833     */
 834    public function SmtpClose() {
 835      if(!is_null($this->smtp)) {
 836        if($this->smtp->Connected()) {
 837          $this->smtp->Quit();
 838          $this->smtp->Close();
 839        }
 840      }
 841    }
 842  
 843    /**
 844    * Sets the language for all class error messages.
 845    * Returns false if it cannot load the language file.  The default language is English.
 846    * @param string $langcode ISO 639-1 2-character language code (e.g. Portuguese: "br")
 847    * @param string $lang_path Path to the language file directory
 848    * @access public
 849    */
 850    function SetLanguage($langcode = 'en', $lang_path = 'language/') {
 851      //Define full set of translatable strings
 852      $PHPMAILER_LANG = array(
 853        'provide_address' => 'You must provide at least one recipient email address.',
 854        'mailer_not_supported' => ' mailer is not supported.',
 855        'execute' => 'Could not execute: ',
 856        'instantiate' => 'Could not instantiate mail function.',
 857        'authenticate' => 'SMTP Error: Could not authenticate.',
 858        'from_failed' => 'The following From address failed: ',
 859        'recipients_failed' => 'SMTP Error: The following recipients failed: ',
 860        'data_not_accepted' => 'SMTP Error: Data not accepted.',
 861        'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
 862        'file_access' => 'Could not access file: ',
 863        'file_open' => 'File Error: Could not open file: ',
 864        'encoding' => 'Unknown encoding: ',
 865        'signing' => 'Signing Error: ',
 866        'smtp_error' => 'SMTP server error: ',
 867        'empty_message' => 'Message body empty',
 868        'invalid_address' => 'Invalid address',
 869        'variable_set' => 'Cannot set or reset variable: '
 870      );
 871      //Overwrite language-specific strings. This way we'll never have missing translations - no more "language string failed to load"!
 872      $l = true;
 873      if ($langcode != 'en') { //There is no English translation file
 874        $l = @include $lang_path.'phpmailer.lang-'.$langcode.'.php';
 875      }
 876      $this->language = $PHPMAILER_LANG;
 877      return ($l == true); //Returns false if language not found
 878    }
 879  
 880    /**
 881    * Return the current array of language strings
 882    * @return array
 883    */
 884    public function GetTranslations() {
 885      return $this->language;
 886    }
 887  
 888    /////////////////////////////////////////////////
 889    // METHODS, MESSAGE CREATION
 890    /////////////////////////////////////////////////
 891  
 892    /**
 893     * Creates recipient headers.
 894     * @access public
 895     * @return string
 896     */
 897    public function AddrAppend($type, $addr) {
 898      $addr_str = $type . ': ';
 899      $addresses = array();
 900      foreach ($addr as $a) {
 901        $addresses[] = $this->AddrFormat($a);
 902      }
 903      $addr_str .= implode(', ', $addresses);
 904      $addr_str .= $this->LE;
 905  
 906      return $addr_str;
 907    }
 908  
 909    /**
 910     * Formats an address correctly.
 911     * @access public
 912     * @return string
 913     */
 914    public function AddrFormat($addr) {
 915      if (empty($addr[1])) {
 916        return $this->SecureHeader($addr[0]);
 917      } else {
 918        return $this->EncodeHeader($this->SecureHeader($addr[1]), 'phrase') . " <" . $this->SecureHeader($addr[0]) . ">";
 919      }
 920    }
 921  
 922    /**
 923     * Wraps message for use with mailers that do not
 924     * automatically perform wrapping and for quoted-printable.
 925     * Original written by philippe.
 926     * @param string $message The message to wrap
 927     * @param integer $length The line length to wrap to
 928     * @param boolean $qp_mode Whether to run in Quoted-Printable mode
 929     * @access public
 930     * @return string
 931     */
 932    public function WrapText($message, $length, $qp_mode = false) {
 933      $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE;
 934      // If utf-8 encoding is used, we will need to make sure we don't
 935      // split multibyte characters when we wrap
 936      $is_utf8 = (strtolower($this->CharSet) == "utf-8");
 937  
 938      $message = $this->FixEOL($message);
 939      if (substr($message, -1) == $this->LE) {
 940        $message = substr($message, 0, -1);
 941      }
 942  
 943      $line = explode($this->LE, $message);
 944      $message = '';
 945      for ($i=0 ;$i < count($line); $i++) {
 946        $line_part = explode(' ', $line[$i]);
 947        $buf = '';
 948        for ($e = 0; $e<count($line_part); $e++) {
 949          $word = $line_part[$e];
 950          if ($qp_mode and (strlen($word) > $length)) {
 951            $space_left = $length - strlen($buf) - 1;
 952            if ($e != 0) {
 953              if ($space_left > 20) {
 954                $len = $space_left;
 955                if ($is_utf8) {
 956                  $len = $this->UTF8CharBoundary($word, $len);
 957                } elseif (substr($word, $len - 1, 1) == "=") {
 958                  $len--;
 959                } elseif (substr($word, $len - 2, 1) == "=") {
 960                  $len -= 2;
 961                }
 962                $part = substr($word, 0, $len);
 963                $word = substr($word, $len);
 964                $buf .= ' ' . $part;
 965                $message .= $buf . sprintf("=%s", $this->LE);
 966              } else {
 967                $message .= $buf . $soft_break;
 968              }
 969              $buf = '';
 970            }
 971            while (strlen($word) > 0) {
 972              $len = $length;
 973              if ($is_utf8) {
 974                $len = $this->UTF8CharBoundary($word, $len);
 975              } elseif (substr($word, $len - 1, 1) == "=") {
 976                $len--;
 977              } elseif (substr($word, $len - 2, 1) == "=") {
 978                $len -= 2;
 979              }
 980              $part = substr($word, 0, $len);
 981              $word = substr($word, $len);
 982  
 983              if (strlen($word) > 0) {
 984                $message .= $part . sprintf("=%s", $this->LE);
 985              } else {
 986                $buf = $part;
 987              }
 988            }
 989          } else {
 990            $buf_o = $buf;
 991            $buf .= ($e == 0) ? $word : (' ' . $word);
 992  
 993            if (strlen($buf) > $length and $buf_o != '') {
 994              $message .= $buf_o . $soft_break;
 995              $buf = $word;
 996            }
 997          }
 998        }
 999        $message .= $buf . $this->LE;
1000      }
1001  
1002      return $message;
1003    }
1004  
1005    /**
1006     * Finds last character boundary prior to maxLength in a utf-8
1007     * quoted (printable) encoded string.
1008     * Original written by Colin Brown.
1009     * @access public
1010     * @param string $encodedText utf-8 QP text
1011     * @param int    $maxLength   find last character boundary prior to this length
1012     * @return int
1013     */
1014    public function UTF8CharBoundary($encodedText, $maxLength) {
1015      $foundSplitPos = false;
1016      $lookBack = 3;
1017      while (!$foundSplitPos) {
1018        $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
1019        $encodedCharPos = strpos($lastChunk, "=");
1020        if ($encodedCharPos !== false) {
1021          // Found start of encoded character byte within $lookBack block.
1022          // Check the encoded byte value (the 2 chars after the '=')
1023          $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
1024          $dec = hexdec($hex);
1025          if ($dec < 128) { // Single byte character.
1026            // If the encoded char was found at pos 0, it will fit
1027            // otherwise reduce maxLength to start of the encoded char
1028            $maxLength = ($encodedCharPos == 0) ? $maxLength :
1029            $maxLength - ($lookBack - $encodedCharPos);
1030            $foundSplitPos = true;
1031          } elseif ($dec >= 192) { // First byte of a multi byte character
1032            // Reduce maxLength to split at start of character
1033            $maxLength = $maxLength - ($lookBack - $encodedCharPos);
1034            $foundSplitPos = true;
1035          } elseif ($dec < 192) { // Middle byte of a multi byte character, look further back
1036            $lookBack += 3;
1037          }
1038        } else {
1039          // No encoded character found
1040          $foundSplitPos = true;
1041        }
1042      }
1043      return $maxLength;
1044    }
1045  
1046  
1047    /**
1048     * Set the body wrapping.
1049     * @access public
1050     * @return void
1051     */
1052    public function SetWordWrap() {
1053      if($this->WordWrap < 1) {
1054        return;
1055      }
1056  
1057      switch($this->message_type) {
1058        case 'alt':
1059        case 'alt_attachments':
1060          $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap);
1061          break;
1062        default:
1063          $this->Body = $this->WrapText($this->Body, $this->WordWrap);
1064          break;
1065      }
1066    }
1067  
1068    /**
1069     * Assembles message header.
1070     * @access public
1071     * @return string The assembled header
1072     */
1073    public function CreateHeader() {
1074      $result = '';
1075  
1076      // Set the boundaries
1077      $uniq_id = md5(uniqid(time()));
1078      $this->boundary[1] = 'b1_' . $uniq_id;
1079      $this->boundary[2] = 'b2_' . $uniq_id;
1080  
1081      $result .= $this->HeaderLine('Date', self::RFCDate());
1082      if($this->Sender == '') {
1083        $result .= $this->HeaderLine('Return-Path', trim($this->From));
1084      } else {
1085        $result .= $this->HeaderLine('Return-Path', trim($this->Sender));
1086      }
1087  
1088      // To be created automatically by mail()
1089      if($this->Mailer != 'mail') {
1090        if ($this->SingleTo === true) {
1091          foreach($this->to as $t) {
1092            $this->SingleToArray[] = $this->AddrFormat($t);
1093          }
1094        } else {
1095          if(count($this->to) > 0) {
1096            $result .= $this->AddrAppend('To', $this->to);
1097          } elseif (count($this->cc) == 0) {
1098            $result .= $this->HeaderLine('To', 'undisclosed-recipients:;');
1099          }
1100        }
1101      }
1102  
1103      $from = array();
1104      $from[0][0] = trim($this->From);
1105      $from[0][1] = $this->FromName;
1106      $result .= $this->AddrAppend('From', $from);
1107  
1108      // sendmail and mail() extract Cc from the header before sending
1109      if(count($this->cc) > 0) {
1110        $result .= $this->AddrAppend('Cc', $this->cc);
1111      }
1112  
1113      // sendmail and mail() extract Bcc from the header before sending
1114      if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->bcc) > 0)) {
1115        $result .= $this->AddrAppend('Bcc', $this->bcc);
1116      }
1117  
1118      if(count($this->ReplyTo) > 0) {
1119        $result .= $this->AddrAppend('Reply-to', $this->ReplyTo);
1120      }
1121  
1122      // mail() sets the subject itself
1123      if($this->Mailer != 'mail') {
1124        $result .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader($this->Subject)));
1125      }
1126  
1127      if($this->MessageID != '') {
1128        $result .= $this->HeaderLine('Message-ID',$this->MessageID);
1129      } else {
1130        $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE);
1131      }
1132      $result .= $this->HeaderLine('X-Priority', $this->Priority);
1133      $result .= $this->HeaderLine('X-Mailer', 'PHPMailer '.$this->Version.' (phpmailer.sourceforge.net)');
1134  
1135      if($this->ConfirmReadingTo != '') {
1136        $result .= $this->HeaderLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>');
1137      }
1138  
1139      // Add custom headers
1140      for($index = 0; $index < count($this->CustomHeader); $index++) {
1141        $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), $this->EncodeHeader(trim($this->CustomHeader[$index][1])));
1142      }
1143      if (!$this->sign_key_file) {
1144        $result .= $this->HeaderLine('MIME-Version', '1.0');
1145        $result .= $this->GetMailMIME();
1146      }
1147  
1148      return $result;
1149    }
1150  
1151    /**
1152     * Returns the message MIME.
1153     * @access public
1154     * @return string
1155     */
1156    public function GetMailMIME() {
1157      $result = '';
1158      switch($this->message_type) {
1159        case 'plain':
1160          $result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding);
1161          $result .= sprintf("Content-Type: %s; charset=\"%s\"", $this->ContentType, $this->CharSet);
1162          break;
1163        case 'attachments':
1164        case 'alt_attachments':
1165          if($this->InlineImageExists()){
1166            $result .= sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s", 'multipart/related', $this->LE, $this->LE, $this->boundary[1], $this->LE);
1167          } else {
1168            $result .= $this->HeaderLine('Content-Type', 'multipart/mixed;');
1169            $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
1170          }
1171          break;
1172        case 'alt':
1173          $result .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
1174          $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
1175          break;
1176      }
1177  
1178      if($this->Mailer != 'mail') {
1179        $result .= $this->LE.$this->LE;
1180      }
1181  
1182      return $result;
1183    }
1184  
1185    /**
1186     * Assembles the message body.  Returns an empty string on failure.
1187     * @access public
1188     * @return string The assembled message body
1189     */
1190    public function CreateBody() {
1191      $body = '';
1192  
1193      if ($this->sign_key_file) {
1194        $body .= $this->GetMailMIME();
1195      }
1196  
1197      $this->SetWordWrap();
1198  
1199      switch($this->message_type) {
1200        case 'alt':
1201          $body .= $this->GetBoundary($this->boundary[1], '', 'text/plain', '');
1202          $body .= $this->EncodeString($this->AltBody, $this->Encoding);
1203          $body .= $this->LE.$this->LE;
1204          $body .= $this->GetBoundary($this->boundary[1], '', 'text/html', '');
1205          $body .= $this->EncodeString($this->Body, $this->Encoding);
1206          $body .= $this->LE.$this->LE;
1207          $body .= $this->EndBoundary($this->boundary[1]);
1208          break;
1209        case 'plain':
1210          $body .= $this->EncodeString($this->Body, $this->Encoding);
1211          break;
1212        case 'attachments':
1213          $body .= $this->GetBoundary($this->boundary[1], '', '', '');
1214          $body .= $this->EncodeString($this->Body, $this->Encoding);
1215          $body .= $this->LE;
1216          $body .= $this->AttachAll();
1217          break;
1218        case 'alt_attachments':
1219          $body .= sprintf("--%s%s", $this->boundary[1], $this->LE);
1220          $body .= sprintf("Content-Type: %s;%s" . "\tboundary=\"%s\"%s", 'multipart/alternative', $this->LE, $this->boundary[2], $this->LE.$this->LE);
1221          $body .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '') . $this->LE; // Create text body
1222          $body .= $this->EncodeString($this->AltBody, $this->Encoding);
1223          $body .= $this->LE.$this->LE;
1224          $body .= $this->GetBoundary($this->boundary[2], '', 'text/html', '') . $this->LE; // Create the HTML body
1225          $body .= $this->EncodeString($this->Body, $this->Encoding);
1226          $body .= $this->LE.$this->LE;
1227          $body .= $this->EndBoundary($this->boundary[2]);
1228          $body .= $this->AttachAll();
1229          break;
1230      }
1231  
1232      if ($this->IsError()) {
1233        $body = '';
1234      } elseif ($this->sign_key_file) {
1235        try {
1236          $file = tempnam('', 'mail');
1237          file_put_contents($file, $body); //TODO check this worked
1238          $signed = tempnam("", "signed");
1239          if (@openssl_pkcs7_sign($file, $signed, "file://".$this->sign_cert_file, array("file://".$this->sign_key_file, $this->sign_key_pass), NULL)) {
1240            @unlink($file);
1241            @unlink($signed);
1242            $body = file_get_contents($signed);
1243          } else {
1244            @unlink($file);
1245            @unlink($signed);
1246            throw new phpmailerException($this->Lang("signing").openssl_error_string());
1247          }
1248        } catch (phpmailerException $e) {
1249          $body = '';
1250          if ($this->exceptions) {
1251            throw $e;
1252          }
1253        }
1254      }
1255  
1256      return $body;
1257    }
1258  
1259    /**
1260     * Returns the start of a message boundary.
1261     * @access private
1262     */
1263    private function GetBoundary($boundary, $charSet, $contentType, $encoding) {
1264      $result = '';
1265      if($charSet == '') {
1266        $charSet = $this->CharSet;
1267      }
1268      if($contentType == '') {
1269        $contentType = $this->ContentType;
1270      }
1271      if($encoding == '') {
1272        $encoding = $this->Encoding;
1273      }
1274      $result .= $this->TextLine('--' . $boundary);
1275      $result .= sprintf("Content-Type: %s; charset = \"%s\"", $contentType, $charSet);
1276      $result .= $this->LE;
1277      $result .= $this->HeaderLine('Content-Transfer-Encoding', $encoding);
1278      $result .= $this->LE;
1279  
1280      return $result;
1281    }
1282  
1283    /**
1284     * Returns the end of a message boundary.
1285     * @access private
1286     */
1287    private function EndBoundary($boundary) {
1288      return $this->LE . '--' . $boundary . '--' . $this->LE;
1289    }
1290  
1291    /**
1292     * Sets the message type.
1293     * @access private
1294     * @return void
1295     */
1296    private function SetMessageType() {
1297      if(count($this->attachment) < 1 && strlen($this->AltBody) < 1) {
1298        $this->message_type = 'plain';
1299      } else {
1300        if(count($this->attachment) > 0) {
1301          $this->message_type = 'attachments';
1302        }
1303        if(strlen($this->AltBody) > 0 && count($this->attachment) < 1) {
1304          $this->message_type = 'alt';
1305        }
1306        if(strlen($this->AltBody) > 0 && count($this->attachment) > 0) {
1307          $this->message_type = 'alt_attachments';
1308        }
1309      }
1310    }
1311  
1312    /**
1313     *  Returns a formatted header line.
1314     * @access public
1315     * @return string
1316     */
1317    public function HeaderLine($name, $value) {
1318      return $name . ': ' . $value . $this->LE;
1319    }
1320  
1321    /**
1322     * Returns a formatted mail line.
1323     * @access public
1324     * @return string
1325     */
1326    public function TextLine($value) {
1327      return $value . $this->LE;
1328    }
1329  
1330    /////////////////////////////////////////////////
1331    // CLASS METHODS, ATTACHMENTS
1332    /////////////////////////////////////////////////
1333  
1334    /**
1335     * Adds an attachment from a path on the filesystem.
1336     * Returns false if the file could not be found
1337     * or accessed.
1338     * @param string $path Path to the attachment.
1339     * @param string $name Overrides the attachment name.
1340     * @param string $encoding File encoding (see $Encoding).
1341     * @param string $type File extension (MIME) type.
1342     * @return bool
1343     */
1344    public function AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
1345      try {
1346        if ( !@is_file($path) ) {
1347          throw new phpmailerException($this->Lang('file_access') . $path, self::STOP_CONTINUE);
1348        }
1349        $filename = basename($path);
1350        if ( $name == '' ) {
1351          $name = $filename;
1352        }
1353  
1354        $this->attachment[] = array(
1355          0 => $path,
1356          1 => $filename,
1357          2 => $name,
1358          3 => $encoding,
1359          4 => $type,
1360          5 => false,  // isStringAttachment
1361          6 => 'attachment',
1362          7 => 0
1363        );
1364  
1365      } catch (phpmailerException $e) {
1366        $this->SetError($e->getMessage());
1367        if ($this->exceptions) {
1368          throw $e;
1369        }
1370        echo $e->getMessage()."\n";
1371        if ( $e->getCode() == self::STOP_CRITICAL ) {
1372          return false;
1373        }
1374      }
1375      return true;
1376    }
1377  
1378    /**
1379    * Return the current array of attachments
1380    * @return array
1381    */
1382    public function GetAttachments() {
1383      return $this->attachment;
1384    }
1385  
1386    /**
1387     * Attaches all fs, string, and binary attachments to the message.
1388     * Returns an empty string on failure.
1389     * @access private
1390     * @return string
1391     */
1392    private function AttachAll() {
1393      // Return text of body
1394      $mime = array();
1395      $cidUniq = array();
1396      $incl = array();
1397  
1398      // Add all attachments
1399      foreach ($this->attachment as $attachment) {
1400        // Check for string attachment
1401        $bString = $attachment[5];
1402        if ($bString) {
1403          $string = $attachment[0];
1404        } else {
1405          $path = $attachment[0];
1406        }
1407  
1408        if (in_array($attachment[0], $incl)) { continue; }
1409        $filename    = $attachment[1];
1410        $name        = $attachment[2];
1411        $encoding    = $attachment[3];
1412        $type        = $attachment[4];
1413        $disposition = $attachment[6];
1414        $cid         = $attachment[7];
1415        $incl[]      = $attachment[0];
1416        if ( $disposition == 'inline' && isset($cidUniq[$cid]) ) { continue; }
1417        $cidUniq[$cid] = true;
1418  
1419        $mime[] = sprintf("--%s%s", $this->boundary[1], $this->LE);
1420        $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $this->EncodeHeader($this->SecureHeader($name)), $this->LE);
1421        $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE);
1422  
1423        if($disposition == 'inline') {
1424          $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE);
1425        }
1426  
1427        $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", $disposition, $this->EncodeHeader($this->SecureHeader($name)), $this->LE.$this->LE);
1428  
1429        // Encode as string attachment
1430        if($bString) {
1431          $mime[] = $this->EncodeString($string, $encoding);
1432          if($this->IsError()) {
1433            return '';
1434          }
1435          $mime[] = $this->LE.$this->LE;
1436        } else {
1437          $mime[] = $this->EncodeFile($path, $encoding);
1438          if($this->IsError()) {
1439            return '';
1440          }
1441          $mime[] = $this->LE.$this->LE;
1442        }
1443      }
1444  
1445      $mime[] = sprintf("--%s--%s", $this->boundary[1], $this->LE);
1446  
1447      return join('', $mime);
1448    }
1449  
1450    /**
1451     * Encodes attachment in requested format.
1452     * Returns an empty string on failure.
1453     * @param string $path The full path to the file
1454     * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
1455     * @see EncodeFile()
1456     * @access private
1457     * @return string
1458     */
1459    private function EncodeFile($path, $encoding = 'base64') {
1460      try {
1461        if (!is_readable($path)) {
1462          throw new phpmailerException($this->Lang('file_open') . $path, self::STOP_CONTINUE);
1463        }
1464        if (function_exists('get_magic_quotes')) {
1465          function get_magic_quotes() {
1466            return false;
1467          }
1468        }
1469        if (PHP_VERSION < 6) {
1470          $magic_quotes = get_magic_quotes_runtime();
1471          set_magic_quotes_runtime(0);
1472        }
1473        $file_buffer  = file_get_contents($path);
1474        $file_buffer  = $this->EncodeString($file_buffer, $encoding);
1475        if (PHP_VERSION < 6) { set_magic_quotes_runtime($magic_quotes); }
1476        return $file_buffer;
1477      } catch (Exception $e) {
1478        $this->SetError($e->getMessage());
1479        return '';
1480      }
1481    }
1482  
1483    /**
1484     * Encodes string to requested format.
1485     * Returns an empty string on failure.
1486     * @param string $str The text to encode
1487     * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
1488     * @access public
1489     * @return string
1490     */
1491    public function EncodeString ($str, $encoding = 'base64') {
1492      $encoded = '';
1493      switch(strtolower($encoding)) {
1494        case 'base64':
1495          $encoded = chunk_split(base64_encode($str), 76, $this->LE);
1496          break;
1497        case '7bit':
1498        case '8bit':
1499          $encoded = $this->FixEOL($str);
1500          //Make sure it ends with a line break
1501          if (substr($encoded, -(strlen($this->LE))) != $this->LE)
1502            $encoded .= $this->LE;
1503          break;
1504        case 'binary':
1505          $encoded = $str;
1506          break;
1507        case 'quoted-printable':
1508          $encoded = $this->EncodeQP($str);
1509          break;
1510        default:
1511          $this->SetError($this->Lang('encoding') . $encoding);
1512          break;
1513      }
1514      return $encoded;
1515    }
1516  
1517    /**
1518     * Encode a header string to best (shortest) of Q, B, quoted or none.
1519     * @access public
1520     * @return string
1521     */
1522    public function EncodeHeader($str, $position = 'text') {
1523      $x = 0;
1524  
1525      switch (strtolower($position)) {
1526        case 'phrase':
1527          if (!preg_match('/[\200-\377]/', $str)) {
1528            // Can't use addslashes as we don't know what value has magic_quotes_sybase
1529            $encoded = addcslashes($str, "\0..\37\177\\\"");
1530            if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
1531              return ($encoded);
1532            } else {
1533              return ("\"$encoded\"");
1534            }
1535          }
1536          $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
1537          break;
1538        case 'comment':
1539          $x = preg_match_all('/[()"]/', $str, $matches);
1540          // Fall-through
1541        case 'text':
1542        default:
1543          $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
1544          break;
1545      }
1546  
1547      if ($x == 0) {
1548        return ($str);
1549      }
1550  
1551      $maxlen = 75 - 7 - strlen($this->CharSet);
1552      // Try to select the encoding which should produce the shortest output
1553      if (strlen($str)/3 < $x) {
1554        $encoding = 'B';
1555        if (function_exists('mb_strlen') && $this->HasMultiBytes($str)) {
1556          // Use a custom function which correctly encodes and wraps long
1557          // multibyte strings without breaking lines within a character
1558          $encoded = $this->Base64EncodeWrapMB($str);
1559        } else {
1560          $encoded = base64_encode($str);
1561          $maxlen -= $maxlen % 4;
1562          $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
1563        }
1564      } else {
1565        $encoding = 'Q';
1566        $encoded = $this->EncodeQ($str, $position);
1567        $encoded = $this->WrapText($encoded, $maxlen, true);
1568        $encoded = str_replace('='.$this->LE, "\n", trim($encoded));
1569      }
1570  
1571      $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded);
1572      $encoded = trim(str_replace("\n", $this->LE, $encoded));
1573  
1574      return $encoded;
1575    }
1576  
1577    /**
1578     * Checks if a string contains multibyte characters.
1579     * @access public
1580     * @param string $str multi-byte text to wrap encode
1581     * @return bool
1582     */
1583    public function HasMultiBytes($str) {
1584      if (function_exists('mb_strlen')) {
1585        return (strlen($str) > mb_strlen($str, $this->CharSet));
1586      } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
1587        return false;
1588      }
1589    }
1590  
1591    /**
1592     * Correctly encodes and wraps long multibyte strings for mail headers
1593     * without breaking lines within a character.
1594     * Adapted from a function by paravoid at http://uk.php.net/manual/en/function.mb-encode-mimeheader.php
1595     * @access public
1596     * @param string $str multi-byte text to wrap encode
1597     * @return string
1598     */
1599    public function Base64EncodeWrapMB($str) {
1600      $start = "=?".$this->CharSet."?B?";
1601      $end = "?=";
1602      $encoded = "";
1603  
1604      $mb_length = mb_strlen($str, $this->CharSet);
1605      // Each line must have length <= 75, including $start and $end
1606      $length = 75 - strlen($start) - strlen($end);
1607      // Average multi-byte ratio
1608      $ratio = $mb_length / strlen($str);
1609      // Base64 has a 4:3 ratio
1610      $offset = $avgLength = floor($length * $ratio * .75);
1611  
1612      for ($i = 0; $i < $mb_length; $i += $offset) {
1613        $lookBack = 0;
1614  
1615        do {
1616          $offset = $avgLength - $lookBack;
1617          $chunk = mb_substr($str, $i, $offset, $this->CharSet);
1618          $chunk = base64_encode($chunk);
1619          $lookBack++;
1620        }
1621        while (strlen($chunk) > $length);
1622  
1623        $encoded .= $chunk . $this->LE;
1624      }
1625  
1626      // Chomp the last linefeed
1627      $encoded = substr($encoded, 0, -strlen($this->LE));
1628      return $encoded;
1629    }
1630  
1631    /**
1632    * Encode string to quoted-printable.
1633    * Only uses standard PHP, slow, but will always work
1634    * @access public
1635    * @param string $string the text to encode
1636    * @param integer $line_max Number of chars allowed on a line before wrapping
1637    * @return string
1638    */
1639    public function EncodeQPphp( $input = '', $line_max = 76, $space_conv = false) {
1640      $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
1641      $lines = preg_split('/(?:\r\n|\r|\n)/', $input);
1642      $eol = "\r\n";
1643      $escape = '=';
1644      $output = '';
1645      while( list(, $line) = each($lines) ) {
1646        $linlen = strlen($line);
1647        $newline = '';
1648        for($i = 0; $i < $linlen; $i++) {
1649          $c = substr( $line, $i, 1 );
1650          $dec = ord( $c );
1651          if ( ( $i == 0 ) && ( $dec == 46 ) ) { // convert first point in the line into =2E
1652            $c = '=2E';
1653          }
1654          if ( $dec == 32 ) {
1655            if ( $i == ( $linlen - 1 ) ) { // convert space at eol only
1656              $c = '=20';
1657            } else if ( $space_conv ) {
1658              $c = '=20';
1659            }
1660          } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required
1661            $h2 = floor($dec/16);
1662            $h1 = floor($dec%16);
1663            $c = $escape.$hex[$h2].$hex[$h1];
1664          }
1665          if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted
1666            $output .= $newline.$escape.$eol; //  soft line break; " =\r\n" is okay
1667            $newline = '';
1668            // check if newline first character will be point or not
1669            if ( $dec == 46 ) {
1670              $c = '=2E';
1671            }
1672          }
1673          $newline .= $c;
1674        } // end of for
1675        $output .= $newline.$eol;
1676      } // end of while
1677      return $output;
1678    }
1679  
1680    /**
1681    * Encode string to RFC2045 (6.7) quoted-printable format
1682    * Uses a PHP5 stream filter to do the encoding about 64x faster than the old version
1683    * Also results in same content as you started with after decoding
1684    * @see EncodeQPphp()
1685    * @access public
1686    * @param string $string the text to encode
1687    * @param integer $line_max Number of chars allowed on a line before wrapping
1688    * @param boolean $space_conv Dummy param for compatibility with existing EncodeQP function
1689    * @return string
1690    * @author Marcus Bointon
1691    */
1692    public function EncodeQP($string, $line_max = 76, $space_conv = false) {
1693      if (function_exists('quoted_printable_encode')) { //Use native function if it's available (>= PHP5.3)
1694        return quoted_printable_encode($string);
1695      }
1696      $filters = stream_get_filters();
1697      if (!in_array('convert.*', $filters)) { //Got convert stream filter?
1698        return $this->EncodeQPphp($string, $line_max, $space_conv); //Fall back to old implementation
1699      }
1700      $fp = fopen('php://temp/', 'r+');
1701      $string = preg_replace('/\r\n?/', $this->LE, $string); //Normalise line breaks
1702      $params = array('line-length' => $line_max, 'line-break-chars' => $this->LE);
1703      $s = stream_filter_append($fp, 'convert.quoted-printable-encode', STREAM_FILTER_READ, $params);
1704      fputs($fp, $string);
1705      rewind($fp);
1706      $out = stream_get_contents($fp);
1707      stream_filter_remove($s);
1708      $out = preg_replace('/^\./m', '=2E', $out); //Encode . if it is first char on a line, workaround for bug in Exchange
1709      fclose($fp);
1710      return $out;
1711    }
1712  
1713    /**
1714     * Encode string to q encoding.
1715     * @link http://tools.ietf.org/html/rfc2047
1716     * @param string $str the text to encode
1717     * @param string $position Where the text is going to be used, see the RFC for what that means
1718     * @access public
1719     * @return string
1720     */
1721    public function EncodeQ ($str, $position = 'text') {
1722      // There should not be any EOL in the string
1723      $encoded = preg_replace('/[\r\n]*/', '', $str);
1724  
1725      switch (strtolower($position)) {
1726        case 'phrase':
1727          $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
1728          break;
1729        case 'comment':
1730          $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
1731        case 'text':
1732        default:
1733          // Replace every high ascii, control =, ? and _ characters
1734          //TODO using /e (equivalent to eval()) is probably not a good idea
1735          $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e',
1736                "'='.sprintf('%02X', ord('\\1'))", $encoded);
1737          break;
1738      }
1739  
1740      // Replace every spaces to _ (more readable than =20)
1741      $encoded = str_replace(' ', '_', $encoded);
1742  
1743      return $encoded;
1744    }
1745  
1746    /**
1747     * Adds a string or binary attachment (non-filesystem) to the list.
1748     * This method can be used to attach ascii or binary data,
1749     * such as a BLOB record from a database.
1750     * @param string $string String attachment data.
1751     * @param string $filename Name of the attachment.
1752     * @param string $encoding File encoding (see $Encoding).
1753     * @param string $type File extension (MIME) type.
1754     * @return void
1755     */
1756    public function AddStringAttachment($string, $filename, $encoding = 'base64', $type = 'application/octet-stream') {
1757      // Append to $attachment array
1758      $this->attachment[] = array(
1759        0 => $string,
1760        1 => $filename,
1761        2 => basename($filename),
1762        3 => $encoding,
1763        4 => $type,
1764        5 => true,  // isStringAttachment
1765        6 => 'attachment',
1766        7 => 0
1767      );
1768    }
1769  
1770    /**
1771     * Adds an embedded attachment.  This can include images, sounds, and
1772     * just about any other document.  Make sure to set the $type to an
1773     * image type.  For JPEG images use "image/jpeg" and for GIF images
1774     * use "image/gif".
1775     * @param string $path Path to the attachment.
1776     * @param string $cid Content ID of the attachment.  Use this to identify
1777     *        the Id for accessing the image in an HTML form.
1778     * @param string $name Overrides the attachment name.
1779     * @param string $encoding File encoding (see $Encoding).
1780     * @param string $type File extension (MIME) type.
1781     * @return bool
1782     */
1783    public function AddEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
1784  
1785      if ( !@is_file($path) ) {
1786        $this->SetError($this->Lang('file_access') . $path);
1787        return false;
1788      }
1789  
1790      $filename = basename($path);
1791      if ( $name == '' ) {
1792        $name = $filename;
1793      }
1794  
1795      // Append to $attachment array
1796      $this->attachment[] = array(
1797        0 => $path,
1798        1 => $filename,
1799        2 => $name,
1800        3 => $encoding,
1801        4 => $type,
1802        5 => false,  // isStringAttachment
1803        6 => 'inline',
1804        7 => $cid
1805      );
1806  
1807      return true;
1808    }
1809  
1810    /**
1811     * Returns true if an inline attachment is present.
1812     * @access public
1813     * @return bool
1814     */
1815    public function InlineImageExists() {
1816      foreach($this->attachment as $attachment) {
1817        if ($attachment[6] == 'inline') {
1818          return true;
1819        }
1820      }
1821      return false;
1822    }
1823  
1824    /////////////////////////////////////////////////
1825    // CLASS METHODS, MESSAGE RESET
1826    /////////////////////////////////////////////////
1827  
1828    /**
1829     * Clears all recipients assigned in the TO array.  Returns void.
1830     * @return void
1831     */
1832    public function ClearAddresses() {
1833      foreach($this->to as $to) {
1834        unset($this->all_recipients[strtolower($to[0])]);
1835      }
1836      $this->to = array();
1837    }
1838  
1839    /**
1840     * Clears all recipients assigned in the CC array.  Returns void.
1841     * @return void
1842     */
1843    public function ClearCCs() {
1844      foreach($this->cc as $cc) {
1845        unset($this->all_recipients[strtolower($cc[0])]);
1846      }
1847      $this->cc = array();
1848    }
1849  
1850    /**
1851     * Clears all recipients assigned in the BCC array.  Returns void.
1852     * @return void
1853     */
1854    public function ClearBCCs() {
1855      foreach($this->bcc as $bcc) {
1856        unset($this->all_recipients[strtolower($bcc[0])]);
1857      }
1858      $this->bcc = array();
1859    }
1860  
1861    /**
1862     * Clears all recipients assigned in the ReplyTo array.  Returns void.
1863     * @return void
1864     */
1865    public function ClearReplyTos() {
1866      $this->ReplyTo = array();
1867    }
1868  
1869    /**
1870     * Clears all recipients assigned in the TO, CC and BCC
1871     * array.  Returns void.
1872     * @return void
1873     */
1874    public function ClearAllRecipients() {
1875      $this->to = array();
1876      $this->cc = array();
1877      $this->bcc = array();
1878      $this->all_recipients = array();
1879    }
1880  
1881    /**
1882     * Clears all previously set filesystem, string, and binary
1883     * attachments.  Returns void.
1884     * @return void
1885     */
1886    public function ClearAttachments() {
1887      $this->attachment = array();
1888    }
1889  
1890    /**
1891     * Clears all custom headers.  Returns void.
1892     * @return void
1893     */
1894    public function ClearCustomHeaders() {
1895      $this->CustomHeader = array();
1896    }
1897  
1898    /////////////////////////////////////////////////
1899    // CLASS METHODS, MISCELLANEOUS
1900    /////////////////////////////////////////////////
1901  
1902    /**
1903     * Adds the error message to the error container.
1904     * @access protected
1905     * @return void
1906     */
1907    protected function SetError($msg) {
1908      $this->error_count++;
1909      if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
1910        $lasterror = $this->smtp->getError();
1911        if (!empty($lasterror) and array_key_exists('smtp_msg', $lasterror)) {
1912          $msg .= '<p>' . $this->Lang('smtp_error') . $lasterror['smtp_msg'] . "</p>\n";
1913        }
1914      }
1915      $this->ErrorInfo = $msg;
1916    }
1917  
1918    /**
1919     * Returns the proper RFC 822 formatted date.
1920     * @access public
1921     * @return string
1922     * @static
1923     */
1924    public static function RFCDate() {
1925      $tz = date('Z');
1926      $tzs = ($tz < 0) ? '-' : '+';
1927      $tz = abs($tz);
1928      $tz = (int)($tz/3600)*100 + ($tz%3600)/60;
1929      $result = sprintf("%s %s%04d", date('D, j M Y H:i:s'), $tzs, $tz);
1930  
1931      return $result;
1932    }
1933  
1934    /**
1935     * Returns the server hostname or 'localhost.localdomain' if unknown.
1936     * @access private
1937     * @return string
1938     */
1939    private function ServerHostname() {
1940      if (!empty($this->Hostname)) {
1941        $result = $this->Hostname;
1942      } elseif (isset($_SERVER['SERVER_NAME'])) {
1943        $result = $_SERVER['SERVER_NAME'];
1944      } else {
1945        $result = 'localhost.localdomain';
1946      }
1947  
1948      return $result;
1949    }
1950  
1951    /**
1952     * Returns a message in the appropriate language.
1953     * @access private
1954     * @return string
1955     */
1956    private function Lang($key) {
1957      if(count($this->language) < 1) {
1958        $this->SetLanguage('en'); // set the default language
1959      }
1960  
1961      if(isset($this->language[$key])) {
1962        return $this->language[$key];
1963      } else {
1964        return 'Language string failed to load: ' . $key;
1965      }
1966    }
1967  
1968    /**
1969     * Returns true if an error occurred.
1970     * @access public
1971     * @return bool
1972     */
1973    public function IsError() {
1974      return ($this->error_count > 0);
1975    }
1976  
1977    /**
1978     * Changes every end of line from CR or LF to CRLF.
1979     * @access private
1980     * @return string
1981     */
1982    private function FixEOL($str) {
1983      $str = str_replace("\r\n", "\n", $str);
1984      $str = str_replace("\r", "\n", $str);
1985      $str = str_replace("\n", $this->LE, $str);
1986      return $str;
1987    }
1988  
1989    /**
1990     * Adds a custom header.
1991     * @access public
1992     * @return void
1993     */
1994    public function AddCustomHeader($custom_header) {
1995      $this->CustomHeader[] = explode(':', $custom_header, 2);
1996    }
1997  
1998    /**
1999     * Evaluates the message and returns modifications for inline images and backgrounds
2000     * @access public
2001     * @return $message
2002     */
2003    public function MsgHTML($message, $basedir = '') {
2004      preg_match_all("/(src|background)=\"(.*)\"/Ui", $message, $images);
2005      if(isset($images[2])) {
2006        foreach($images[2] as $i => $url) {
2007          // do not change urls for absolute images (thanks to corvuscorax)
2008          if (!preg_match('#^[A-z]+://#',$url)) {
2009            $filename = basename($url);
2010            $directory = dirname($url);
2011            ($directory == '.')?$directory='':'';
2012            $cid = 'cid:' . md5($filename);
2013            $ext = pathinfo($filename, PATHINFO_EXTENSION);
2014            $mimeType  = self::_mime_types($ext);
2015            if ( strlen($basedir) > 1 && substr($basedir,-1) != '/') { $basedir .= '/'; }
2016            if ( strlen($directory) > 1 && substr($directory,-1) != '/') { $directory .= '/'; }
2017            if ( $this->AddEmbeddedImage($basedir.$directory.$filename, md5($filename), $filename, 'base64',$mimeType) ) {
2018              $message = preg_replace("/".$images[1][$i]."=\"".preg_quote($url, '/')."\"/Ui", $images[1][$i]."=\"".$cid."\"", $message);
2019            }
2020          }
2021        }
2022      }
2023      $this->IsHTML(true);
2024      $this->Body = $message;
2025      $textMsg = trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/s','',$message)));
2026      if (!empty($textMsg) && empty($this->AltBody)) {
2027        $this->AltBody = html_entity_decode($textMsg);
2028      }
2029      if (empty($this->AltBody)) {
2030        $this->AltBody = 'To view this email message, open it in a program that understands HTML!' . "\n\n";
2031      }
2032    }
2033  
2034    /**
2035     * Gets the MIME type of the embedded or inline image
2036     * @param string File extension
2037     * @access public
2038     * @return string MIME type of ext
2039     * @static
2040     */
2041    public static function _mime_types($ext = '') {
2042      $mimes = array(
2043        'hqx'   =>  'application/mac-binhex40',
2044        'cpt'   =>  'application/mac-compactpro',
2045        'doc'   =>  'application/msword',
2046        'bin'   =>  'application/macbinary',
2047        'dms'   =>  'application/octet-stream',
2048        'lha'   =>  'application/octet-stream',
2049        'lzh'   =>  'application/octet-stream',
2050        'exe'   =>  'application/octet-stream',
2051        'class' =>  'application/octet-stream',
2052        'psd'   =>  'application/octet-stream',
2053        'so'    =>  'application/octet-stream',
2054        'sea'   =>  'application/octet-stream',
2055        'dll'   =>  'application/octet-stream',
2056        'oda'   =>  'application/oda',
2057        'pdf'   =>  'application/pdf',
2058        'ai'    =>  'application/postscript',
2059        'eps'   =>  'application/postscript',
2060        'ps'    =>  'application/postscript',
2061        'smi'   =>  'application/smil',
2062        'smil'  =>  'application/smil',
2063        'mif'   =>  'application/vnd.mif',
2064        'xls'   =>  'application/vnd.ms-excel',
2065        'ppt'   =>  'application/vnd.ms-powerpoint',
2066        'wbxml' =>  'application/vnd.wap.wbxml',
2067        'wmlc'  =>  'application/vnd.wap.wmlc',
2068        'dcr'   =>  'application/x-director',
2069        'dir'   =>  'application/x-director',
2070        'dxr'   =>  'application/x-director',
2071        'dvi'   =>  'application/x-dvi',
2072        'gtar'  =>  'application/x-gtar',
2073        'php'   =>  'application/x-httpd-php',
2074        'php4'  =>  'application/x-httpd-php',
2075        'php3'  =>  'application/x-httpd-php',
2076        'phtml' =>  'application/x-httpd-php',
2077        'phps'  =>  'application/x-httpd-php-source',
2078        'js'    =>  'application/x-javascript',
2079        'swf'   =>  'application/x-shockwave-flash',
2080        'sit'   =>  'application/x-stuffit',
2081        'tar'   =>  'application/x-tar',
2082        'tgz'   =>  'application/x-tar',
2083        'xhtml' =>  'application/xhtml+xml',
2084        'xht'   =>  'application/xhtml+xml',
2085        'zip'   =>  'application/zip',
2086        'mid'   =>  'audio/midi',
2087        'midi'  =>  'audio/midi',
2088        'mpga'  =>  'audio/mpeg',
2089        'mp2'   =>  'audio/mpeg',
2090        'mp3'   =>  'audio/mpeg',
2091        'aif'   =>  'audio/x-aiff',
2092        'aiff'  =>  'audio/x-aiff',
2093        'aifc'  =>  'audio/x-aiff',
2094        'ram'   =>  'audio/x-pn-realaudio',
2095        'rm'    =>  'audio/x-pn-realaudio',
2096        'rpm'   =>  'audio/x-pn-realaudio-plugin',
2097        'ra'    =>  'audio/x-realaudio',
2098        'rv'    =>  'video/vnd.rn-realvideo',
2099        'wav'   =>  'audio/x-wav',
2100        'bmp'   =>  'image/bmp',
2101        'gif'   =>  'image/gif',
2102        'jpeg'  =>  'image/jpeg',
2103        'jpg'   =>  'image/jpeg',
2104        'jpe'   =>  'image/jpeg',
2105        'png'   =>  'image/png',
2106        'tiff'  =>  'image/tiff',
2107        'tif'   =>  'image/tiff',
2108        'css'   =>  'text/css',
2109        'html'  =>  'text/html',
2110        'htm'   =>  'text/html',
2111        'shtml' =>  'text/html',
2112        'txt'   =>  'text/plain',
2113        'text'  =>  'text/plain',
2114        'log'   =>  'text/plain',
2115        'rtx'   =>  'text/richtext',
2116        'rtf'   =>  'text/rtf',
2117        'xml'   =>  'text/xml',
2118        'xsl'   =>  'text/xml',
2119        'mpeg'  =>  'video/mpeg',
2120        'mpg'   =>  'video/mpeg',
2121        'mpe'   =>  'video/mpeg',
2122        'qt'    =>  'video/quicktime',
2123        'mov'   =>  'video/quicktime',
2124        'avi'   =>  'video/x-msvideo',
2125        'movie' =>  'video/x-sgi-movie',
2126        'doc'   =>  'application/msword',
2127        'word'  =>  'application/msword',
2128        'xl'    =>  'application/excel',
2129        'eml'   =>  'message/rfc822'
2130      );
2131      return (!isset($mimes[strtolower($ext)])) ? 'application/octet-stream' : $mimes[strtolower($ext)];
2132    }
2133  
2134    /**
2135    * Set (or reset) Class Objects (variables)
2136    *
2137    * Usage Example:
2138    * $page->set('X-Priority', '3');
2139    *
2140    * @access public
2141    * @param string $name Parameter Name
2142    * @param mixed $value Parameter Value
2143    * NOTE: will not work with arrays, there are no arrays to set/reset
2144    * @todo Should this not be using __set() magic function?
2145    */
2146    public function set($name, $value = '') {
2147      try {
2148        if (isset($this->$name) ) {
2149          $this->$name = $value;
2150        } else {
2151          throw new phpmailerException($this->Lang('variable_set') . $name, self::STOP_CRITICAL);
2152        }
2153      } catch (Exception $e) {
2154        $this->SetError($e->getMessage());
2155        if ($e->getCode() == self::STOP_CRITICAL) {
2156          return false;
2157        }
2158      }
2159      return true;
2160    }
2161  
2162    /**
2163     * Strips newlines to prevent header injection.
2164     * @access public
2165     * @param string $str String
2166     * @return string
2167     */
2168    public function SecureHeader($str) {
2169      $str = str_replace("\r", '', $str);
2170      $str = str_replace("\n", '', $str);
2171      return trim($str);
2172    }
2173  
2174    /**
2175     * Set the private key file and password to sign the message.
2176     *
2177     * @access public
2178     * @param string $key_filename Parameter File Name
2179     * @param string $key_pass Password for private key
2180     */
2181    public function Sign($cert_filename, $key_filename, $key_pass) {
2182      $this->sign_cert_file = $cert_filename;
2183      $this->sign_key_file = $key_filename;
2184      $this->sign_key_pass = $key_pass;
2185    }
2186  
2187    /**
2188     * Set the private key file and password to sign the message.
2189     *
2190     * @access public
2191     * @param string $key_filename Parameter File Name
2192     * @param string $key_pass Password for private key
2193     */
2194    public function DKIM_QP($txt) {
2195      $tmp="";
2196      $line="";
2197      for ($i=0;$i<strlen($txt);$i++) {
2198        $ord=ord($txt[$i]);
2199        if ( ((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E)) ) {
2200          $line.=$txt[$i];
2201        } else {
2202          $line.="=".sprintf("%02X",$ord);
2203        }
2204      }
2205      return $line;
2206    }
2207  
2208    /**
2209     * Generate DKIM signature
2210     *
2211     * @access public
2212     * @param string $s Header
2213     */
2214    public function DKIM_Sign($s) {
2215      $privKeyStr = file_get_contents($this->DKIM_private);
2216      if ($this->DKIM_passphrase!='') {
2217        $privKey = openssl_pkey_get_private($privKeyStr,$this->DKIM_passphrase);
2218      } else {
2219        $privKey = $privKeyStr;
2220      }
2221      if (openssl_sign($s, $signature, $privKey)) {
2222        return base64_encode($signature);
2223      }
2224    }
2225  
2226    /**
2227     * Generate DKIM Canonicalization Header
2228     *
2229     * @access public
2230     * @param string $s Header
2231     */
2232    public function DKIM_HeaderC($s) {
2233      $s=preg_replace("/\r\n\s+/"," ",$s);
2234      $lines=explode("\r\n",$s);
2235      foreach ($lines as $key=>$line) {
2236        list($heading,$value)=explode(":",$line,2);
2237        $heading=strtolower($heading);
2238        $value=preg_replace("/\s+/"," ",$value) ; // Compress useless spaces
2239        $lines[$key]=$heading.":".trim($value) ; // Don't forget to remove WSP around the value
2240      }
2241      $s=implode("\r\n",$lines);
2242      return $s;
2243    }
2244  
2245    /**
2246     * Generate DKIM Canonicalization Body
2247     *
2248     * @access public
2249     * @param string $body Message Body
2250     */
2251    public function DKIM_BodyC($body) {
2252      if ($body == '') return "\r\n";
2253      // stabilize line endings
2254      $body=str_replace("\r\n","\n",$body);
2255      $body=str_replace("\n","\r\n",$body);
2256      // END stabilize line endings
2257      while (substr($body,strlen($body)-4,4) == "\r\n\r\n") {
2258        $body=substr($body,0,strlen($body)-2);
2259      }
2260      return $body;
2261    }
2262  
2263    /**
2264     * Create the DKIM header, body, as new header
2265     *
2266     * @access public
2267     * @param string $headers_line Header lines
2268     * @param string $subject Subject
2269     * @param string $body Body
2270     */
2271    public function DKIM_Add($headers_line,$subject,$body) {
2272      $DKIMsignatureType    = 'rsa-sha1'; // Signature & hash algorithms
2273      $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body
2274      $DKIMquery            = 'dns/txt'; // Query method
2275      $DKIMtime             = time() ; // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone)
2276      $subject_header       = "Subject: $subject";
2277      $headers              = explode("\r\n",$headers_line);
2278      foreach($headers as $header) {
2279        if (strpos($header,'From:') === 0) {
2280          $from_header=$header;
2281        } elseif (strpos($header,'To:') === 0) {
2282          $to_header=$header;
2283        }
2284      }
2285      $from     = str_replace('|','=7C',$this->DKIM_QP($from_header));
2286      $to       = str_replace('|','=7C',$this->DKIM_QP($to_header));
2287      $subject  = str_replace('|','=7C',$this->DKIM_QP($subject_header)) ; // Copied header fields (dkim-quoted-printable
2288      $body     = $this->DKIM_BodyC($body);
2289      $DKIMlen  = strlen($body) ; // Length of body
2290      $DKIMb64  = base64_encode(pack("H*", sha1($body))) ; // Base64 of packed binary SHA-1 hash of body
2291      $ident    = ($this->DKIM_identity == '')? '' : " i=" . $this->DKIM_identity . ";";
2292      $dkimhdrs = "DKIM-Signature: v=1; a=" . $DKIMsignatureType . "; q=" . $DKIMquery . "; l=" . $DKIMlen . "; s=" . $this->DKIM_selector . ";\r\n".
2293                  "\tt=" . $DKIMtime . "; c=" . $DKIMcanonicalization . ";\r\n".
2294                  "\th=From:To:Subject;\r\n".
2295                  "\td=" . $this->DKIM_domain . ";" . $ident . "\r\n".
2296                  "\tz=$from\r\n".
2297                  "\t|$to\r\n".
2298                  "\t|$subject;\r\n".
2299                  "\tbh=" . $DKIMb64 . ";\r\n".
2300                  "\tb=";
2301      $toSign   = $this->DKIM_HeaderC($from_header . "\r\n" . $to_header . "\r\n" . $subject_header . "\r\n" . $dkimhdrs);
2302      $signed   = $this->DKIM_Sign($toSign);
2303      return "X-PHPMAILER-DKIM: phpmailer.worxware.com\r\n".$dkimhdrs.$signed."\r\n";
2304    }
2305  
2306    protected function doCallback($isSent,$to,$cc,$bcc,$subject,$body) {
2307      if (!empty($this->action_function) && function_exists($this->action_function)) {
2308        $params = array($isSent,$to,$cc,$bcc,$subject,$body);
2309        call_user_func_array($this->action_function,$params);
2310      }
2311    }
2312  }
2313  
2314  class phpmailerException extends Exception {
2315    public function errorMessage() {
2316      $errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n";
2317      return $errorMsg;
2318    }
2319  }
2320  ?>

title

Description

title

Description

title

Description

title

title

Body