fmsystem-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Fmsystem-commits] [13722] PHPmailer: update to latest from upstream


From: Sigurd Nes
Subject: [Fmsystem-commits] [13722] PHPmailer: update to latest from upstream
Date: Sat, 15 Aug 2015 08:48:05 +0000

Revision: 13722
          http://svn.sv.gnu.org/viewvc/?view=rev&root=fmsystem&revision=13722
Author:   sigurdne
Date:     2015-08-15 08:48:04 +0000 (Sat, 15 Aug 2015)
Log Message:
-----------
PHPmailer: update to latest from upstream

Modified Paths:
--------------
    trunk/phpgwapi/inc/phpmailer/PHPMailerAutoload.php
    trunk/phpgwapi/inc/phpmailer/README.md
    trunk/phpgwapi/inc/phpmailer/changelog.md
    trunk/phpgwapi/inc/phpmailer/class.phpmailer.php
    trunk/phpgwapi/inc/phpmailer/class.pop3.php
    trunk/phpgwapi/inc/phpmailer/class.smtp.php
    trunk/phpgwapi/inc/phpmailer/composer.json
    trunk/phpgwapi/inc/phpmailer/docs/extending.html
    trunk/phpgwapi/inc/phpmailer/docs/faq.html
    trunk/phpgwapi/inc/phpmailer/docs/generatedocs.sh
    trunk/phpgwapi/inc/phpmailer/examples/code_generator.phps
    trunk/phpgwapi/inc/phpmailer/examples/contents.html
    trunk/phpgwapi/inc/phpmailer/examples/exceptions.phps
    trunk/phpgwapi/inc/phpmailer/examples/gmail.phps
    trunk/phpgwapi/inc/phpmailer/examples/images/phpmailer.png
    trunk/phpgwapi/inc/phpmailer/examples/index.html
    trunk/phpgwapi/inc/phpmailer/examples/mail.phps
    trunk/phpgwapi/inc/phpmailer/examples/mailing_list.phps
    trunk/phpgwapi/inc/phpmailer/examples/pop_before_smtp.phps
    trunk/phpgwapi/inc/phpmailer/examples/sendmail.phps
    trunk/phpgwapi/inc/phpmailer/examples/smtp.phps
    trunk/phpgwapi/inc/phpmailer/examples/smtp_no_auth.phps
    trunk/phpgwapi/inc/phpmailer/extras/EasyPeasyICS.php
    trunk/phpgwapi/inc/phpmailer/extras/htmlfilter.php
    trunk/phpgwapi/inc/phpmailer/extras/ntlm_sasl_client.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-ar.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-br.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-ca.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-ch.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-cz.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-de.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-dk.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-eo.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-es.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-et.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-fa.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-fi.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-fo.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-fr.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-he.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-hu.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-it.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-ja.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-lt.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-nl.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-no.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-pl.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-ro.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-ru.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-se.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-sk.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-tr.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-uk.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-zh.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-zh_cn.php
    trunk/phpgwapi/inc/phpmailer/test/phpmailerLangTest.php
    trunk/phpgwapi/inc/phpmailer/test/phpmailerTest.php
    trunk/phpgwapi/inc/phpmailer/test/test_callback.php

Added Paths:
-----------
    trunk/phpgwapi/inc/phpmailer/VERSION
    trunk/phpgwapi/inc/phpmailer/examples/contentsutf8.html
    trunk/phpgwapi/inc/phpmailer/examples/images/phpmailer_mini.png
    trunk/phpgwapi/inc/phpmailer/examples/send_file_upload.phps
    trunk/phpgwapi/inc/phpmailer/examples/smtp_check.phps
    trunk/phpgwapi/inc/phpmailer/examples/ssl_options.phps
    trunk/phpgwapi/inc/phpmailer/extras/README.md
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-am.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-az.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-be.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-bg.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-el.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-gl.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-hr.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-id.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-ka.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-ko.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-lv.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-ms.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-pt.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-sl.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-sr.php
    trunk/phpgwapi/inc/phpmailer/language/phpmailer.lang-vi.php
    trunk/phpgwapi/inc/phpmailer/test/bootstrap.php

Modified: trunk/phpgwapi/inc/phpmailer/PHPMailerAutoload.php
===================================================================
--- trunk/phpgwapi/inc/phpmailer/PHPMailerAutoload.php  2015-08-14 23:56:19 UTC 
(rev 13721)
+++ trunk/phpgwapi/inc/phpmailer/PHPMailerAutoload.php  2015-08-15 08:48:04 UTC 
(rev 13722)
@@ -1,14 +1,14 @@
 <?php
 /**
  * PHPMailer SPL autoloader.
- * PHP Version 5.0.0
+ * PHP Version 5
  * @package PHPMailer
- * @link https://github.com/PHPMailer/PHPMailer/
- * @author Marcus Bointon (coolbru) <address@hidden>
+ * @link https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
+ * @author Marcus Bointon (Synchro/coolbru) <address@hidden>
  * @author Jim Jagielski (jimjag) <address@hidden>
  * @author Andy Prevost (codeworxtech) <address@hidden>
  * @author Brent R. Matzelle (original founder)
- * @copyright 2013 Marcus Bointon
+ * @copyright 2012 - 2014 Marcus Bointon
  * @copyright 2010 - 2012 Jim Jagielski
  * @copyright 2004 - 2009 Andy Prevost
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public 
License
@@ -30,4 +30,20 @@
     }
 }
 
-spl_autoload_register('PHPMailerAutoload');
+if (version_compare(PHP_VERSION, '5.1.2', '>=')) {
+    //SPL autoloading was introduced in PHP 5.1.2
+    if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
+        spl_autoload_register('PHPMailerAutoload', true, true);
+    } else {
+        spl_autoload_register('PHPMailerAutoload');
+    }
+} else {
+    /**
+     * Fall back to traditional autoload for old PHP versions
+     * @param string $classname The name of the class to load
+     */
+    function __autoload($classname)
+    {
+        PHPMailerAutoload($classname);
+    }
+}

Modified: trunk/phpgwapi/inc/phpmailer/README.md
===================================================================
--- trunk/phpgwapi/inc/phpmailer/README.md      2015-08-14 23:56:19 UTC (rev 
13721)
+++ trunk/phpgwapi/inc/phpmailer/README.md      2015-08-15 08:48:04 UTC (rev 
13722)
@@ -1,17 +1,24 @@
+![PHPMailer](https://raw.github.com/PHPMailer/PHPMailer/master/examples/images/phpmailer.png)
+
 # PHPMailer - A full-featured email creation and transfer class for PHP
 
-Build status: [![Build 
Status](https://travis-ci.org/Synchro/PHPMailer.png)](https://travis-ci.org/Synchro/PHPMailer)
+Build status: [![Build 
Status](https://travis-ci.org/PHPMailer/PHPMailer.svg)](https://travis-ci.org/PHPMailer/PHPMailer)
+[![Scrutinizer Quality 
Score](https://scrutinizer-ci.com/g/PHPMailer/PHPMailer/badges/quality-score.png?s=3758e21d279becdf847a557a56a3ed16dfec9d5d)](https://scrutinizer-ci.com/g/PHPMailer/PHPMailer/)
+[![Code 
Coverage](https://scrutinizer-ci.com/g/PHPMailer/PHPMailer/badges/coverage.png?s=3fe6ca5fe8cd2cdf96285756e42932f7ca256962)](https://scrutinizer-ci.com/g/PHPMailer/PHPMailer/)
 
+[![Latest Stable 
Version](https://poser.pugx.org/phpmailer/phpmailer/v/stable.svg)](https://packagist.org/packages/phpmailer/phpmailer)
 [![Total 
Downloads](https://poser.pugx.org/phpmailer/phpmailer/downloads)](https://packagist.org/packages/phpmailer/phpmailer)
 [![Latest Unstable 
Version](https://poser.pugx.org/phpmailer/phpmailer/v/unstable.svg)](https://packagist.org/packages/phpmailer/phpmailer)
 
[![License](https://poser.pugx.org/phpmailer/phpmailer/license.svg)](https://packagist.org/packages/phpmailer/phpmailer)
+
 ## Class Features
 
 - Probably the world's most popular code for sending email from PHP!
-- Used by many open-source projects: Drupal, SugarCRM, Yii, Joomla! and many 
more
+- Used by many open-source projects: WordPress, Drupal, 1CRM, SugarCRM, Yii, 
Joomla! and many more
 - Integrated SMTP support - send without a local mail server
-- send emails with multiple TOs, CCs, BCCs and REPLY-TOs
+- Send emails with multiple TOs, CCs, BCCs and REPLY-TOs
 - Multipart/alternative emails for mail clients that do not read HTML email
-- Support for 8bit, base64, binary, and quoted-printable encoding
-- SMTP authentication with LOGIN, PLAIN, NTLM and CRAM-MD5 mechanisms
-- Native language support
+- Support for UTF-8 content and 8bit, base64, binary, and quoted-printable 
encodings
+- SMTP authentication with LOGIN, PLAIN, NTLM and CRAM-MD5 mechanisms over SSL 
and TLS transports
+- Error messages in 47 languages!
+- DKIM and S/MIME signing support
 - Compatible with PHP 5.0 and later
 - Much more!
 
@@ -26,38 +33,59 @@
 
 ## License
 
-This software is licenced under the [LGPL 
2.1](http://www.gnu.org/licenses/lgpl-2.1.html). Please read LICENSE for 
information on the
+This software is distributed under the [LGPL 
2.1](http://www.gnu.org/licenses/lgpl-2.1.html) license. Please read LICENSE 
for information on the
 software availability and distribution.
 
-## Installation
+## Installation & loading
 
-PHPMailer is available via 
[Composer/Packagist](https://packagist.org/packages/phpmailer/phpmailer). 
Alternatively, just copy the contents of the PHPMailer folder into somewhere 
that's in your PHP `include_path` setting. If you don't speak git or just want 
a tarball, click the 'zip' button at the top of the page in GitHub.
+PHPMailer is available via 
[Composer/Packagist](https://packagist.org/packages/phpmailer/phpmailer) (using 
semantic versioning), so just add this line to your `composer.json` file:
 
+```json
+"phpmailer/phpmailer": "~5.2"
+```
 
+or
+
+```sh
+composer require phpmailer/phpmailer
+```
+
+Alternatively, copy the contents of the PHPMailer folder into somewhere that's 
in your PHP `include_path` setting. If you don't speak git or just want a 
tarball, click the 'zip' button at the top of the page in GitHub.
+
+If you're not using composer's autoloader, PHPMailer provides an 
SPL-compatible autoloader, and that is the preferred way of loading the library 
- just `require '/path/to/PHPMailerAutoload.php';` and everything should work. 
The autoloader does not throw errors if it can't find classes so it prepends 
itself to the SPL list, allowing your own (or your framework's) autoloader to 
catch errors. SPL autoloading was introduced in PHP 5.1.0, so if you are using 
a version older than that you will need to require/include each class manually.
+
+PHPMailer does *not* declare a namespace because namespaces were only 
introduced in PHP 5.3.
+
+### Minimal installation
+
+While installing the entire package manually or with composer is simple, 
convenient and reliable, you may want to include only vital files in your 
project. At the very least you will need 
[class.phpmailer.php](class.phpmailer.php). If you're using SMTP, you'll need 
[class.smtp.php](class.smtp.php), and if you're using POP-before SMTP, you'll 
need [class.pop3.php](class.pop3.php). For all of these, we recommend you use 
[the autoloader](PHPMailerAutoload.php) too as otherwise you will either have 
to `require` all classes manually or use some other autoloader. You can skip 
the [language](language/) folder if you're not showing errors to users and can 
make do with English-only errors. You may need the additional classes in the 
[extras](extras/) folder if you are using those features, including NTLM 
authentication and ics generation.
+
 ## A Simple Example
 
 ```php
 <?php
-require 'class.phpmailer.php';
+require 'PHPMailerAutoload.php';
 
 $mail = new PHPMailer;
 
+//$mail->SMTPDebug = 3;                               // Enable verbose debug 
output
+
 $mail->isSMTP();                                      // Set mailer to use SMTP
-$mail->Host = 'smtp1.example.com;smtp2.example.com';  // Specify main and 
backup server
+$mail->Host = 'smtp1.example.com;smtp2.example.com';  // Specify main and 
backup SMTP servers
 $mail->SMTPAuth = true;                               // Enable SMTP 
authentication
-$mail->Username = 'jswan';                            // SMTP username
+$mail->Username = 'address@hidden';                 // SMTP username
 $mail->Password = 'secret';                           // SMTP password
-$mail->SMTPSecure = 'tls';                            // Enable encryption, 
'ssl' also accepted
+$mail->SMTPSecure = 'tls';                            // Enable TLS 
encryption, `ssl` also accepted
+$mail->Port = 587;                                    // TCP port to connect to
 
 $mail->From = 'address@hidden';
 $mail->FromName = 'Mailer';
-$mail->addAddress('address@hidden', 'Josh Adams');  // Add a recipient
+$mail->addAddress('address@hidden', 'Joe User');     // Add a recipient
 $mail->addAddress('address@hidden');               // Name is optional
 $mail->addReplyTo('address@hidden', 'Information');
 $mail->addCC('address@hidden');
 $mail->addBCC('address@hidden');
 
-$mail->WordWrap = 50;                                 // Set word wrap to 50 
characters
 $mail->addAttachment('/var/tmp/file.tar.gz');         // Add attachments
 $mail->addAttachment('/tmp/image.jpg', 'new.jpg');    // Optional name
 $mail->isHTML(true);                                  // Set email format to 
HTML
@@ -67,35 +95,44 @@
 $mail->AltBody = 'This is the body in plain text for non-HTML mail clients';
 
 if(!$mail->send()) {
-   echo 'Message could not be sent.';
-   echo 'Mailer Error: ' . $mail->ErrorInfo;
-   exit;
+    echo 'Message could not be sent.';
+    echo 'Mailer Error: ' . $mail->ErrorInfo;
+} else {
+    echo 'Message has been sent';
 }
-
-echo 'Message has been sent';
 ```
 
-You'll find plenty more to play with in the `examples` folder.
+You'll find plenty more to play with in the [examples](examples/) folder.
 
 That's it. You should now be ready to use PHPMailer!
 
 ## Localization
-PHPMailer defaults to English, but in the `languages` folder you'll find 
numerous translations for PHPMailer error messages that you may encounter. 
Their filenames contain [ISO 639-1](http://en.wikipedia.org/wiki/ISO_639-1) 
language code for the translations, for example `fr` for French. To specify a 
language, you need to tell PHPMailer which one to use, like this:
+PHPMailer defaults to English, but in the [language](language/) folder you'll 
find numerous (46 at the time of writing!) translations for PHPMailer error 
messages that you may encounter. Their filenames contain [ISO 
639-1](http://en.wikipedia.org/wiki/ISO_639-1) language code for the 
translations, for example `fr` for French. To specify a language, you need to 
tell PHPMailer which one to use, like this:
 
 ```php
 // To load the French version
 $mail->setLanguage('fr', '/optional/path/to/language/directory/');
 ```
 
+We welcome corrections and new languages - if you're looking for corrections 
to do, run the [phpmailerLangTest.php](test/phpmailerLangTest.php) script in 
the tests folder and it will show any missing translations.
+
 ## Documentation
 
-You'll find some basic user-level docs in the docs folder, and you can 
generate complete API-level documentation using the `generatedocs.sh` shell 
script in the docs folder, though you'll need to install 
[PHPDocumentor](http://www.phpdoc.org) first.
+Examples of how to use PHPMailer for common scenarios can be found in the 
[examples](examples/) folder. If you're looking for a good starting point, we 
recommend you start with [the gmail example](examples/gmail.phps).
 
+There are tips and a troubleshooting guide in the [GitHub 
wiki](https://github.com/PHPMailer/PHPMailer/wiki). If you're having trouble, 
this should be the first place you look as it's the most frequently updated.
+
+Complete generated API documentation is [available 
online](http://phpmailer.github.io/PHPMailer/).
+
+You'll find some basic user-level docs in the [docs](docs/) folder, and you 
can generate complete API-level documentation using the 
[generatedocs.sh](docs/generatedocs.sh) shell script in the docs folder, though 
you'll need to install [PHPDocumentor](http://www.phpdoc.org) first. You may 
find [the unit tests](test/phpmailerTest.php) a good source of how to do 
various operations such as encryption.
+
+If the documentation doesn't cover what you need, search the [many questions 
on StackOverflow](http://stackoverflow.com/questions/tagged/phpmailer), and 
before you ask a question about "SMTP Error: Could not connect to SMTP host.", 
[read the troubleshooting 
guide](https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting).
+
 ## Tests
 
-You'll find a PHPUnit test script in the `test` folder.
+There is a PHPUnit test script in the [test](test/) folder.
 
-Build status: [![Build 
Status](https://travis-ci.org/PHPMailer/PHPMailer.png)](https://travis-ci.org/PHPMailer/PHPMailer)
+Build status: [![Build 
Status](https://travis-ci.org/PHPMailer/PHPMailer.svg)](https://travis-ci.org/PHPMailer/PHPMailer)
 
 If this isn't passing, is there something you can do to help?
 
@@ -107,10 +144,20 @@
 
 With the move to the PHPMailer GitHub organisation, you'll need to update any 
remote URLs referencing the old GitHub location with a command like this from 
within your clone:
 
-`git remote set-url upstream https://github.com/PHPMailer/PHPMailer.git`
+```sh
+git remote set-url upstream https://github.com/PHPMailer/PHPMailer.git
+```
 
 Please *don't* use the SourceForge or Google Code projects any more.
 
+## Sponsorship
+
+Development time and resources for PHPMailer are provided by 
[Smartmessages.net](https://info.smartmessages.net/), a powerful email 
marketing system.
+
+<a href="https://info.smartmessages.net/";><img 
src="https://www.smartmessages.net/img/smartmessages-logo.svg"; width="250" 
height="28" alt="Smartmessages email marketing"></a>
+
+Other contributions are gladly received, whether in beer 🍺, T-shirts 👕, Amazon 
wishlist raids, or cold, hard cash 💰.
+
 ## Changelog
 
 See [changelog](changelog.md).
@@ -128,7 +175,7 @@
 - Test suite.
 - Continuous integration with Travis-CI.
 - Composer support.
-- Rolling releases.
+- Public development.
 - Additional languages and language strings.
 - CRAM-MD5 authentication support.
 - Preserves full repo history of authors, commits and branches from the 
original SourceForge project.

Added: trunk/phpgwapi/inc/phpmailer/VERSION
===================================================================
--- trunk/phpgwapi/inc/phpmailer/VERSION                                (rev 0)
+++ trunk/phpgwapi/inc/phpmailer/VERSION        2015-08-15 08:48:04 UTC (rev 
13722)
@@ -0,0 +1 @@
+5.2.10
\ No newline at end of file

Modified: trunk/phpgwapi/inc/phpmailer/changelog.md
===================================================================
--- trunk/phpgwapi/inc/phpmailer/changelog.md   2015-08-14 23:56:19 UTC (rev 
13721)
+++ trunk/phpgwapi/inc/phpmailer/changelog.md   2015-08-15 08:48:04 UTC (rev 
13722)
@@ -1,11 +1,112 @@
 # ChangeLog
 
+* Don't switch to quoted-printable for long lines if already using base64
+* Fixed Travis-CI config when run on PHP 7
+* Add address parser for RFC822-format addresses
+* Update MS Office MIME types
+* Don't convert line breaks when using quoted-printable encoding
+* Handle MS Exchange returning an invalid empty AUTH-type list in EHLO
+
+## Version 5.2.10 (May 4th 2015)
+* Add custom header getter
+* Use `application/javascript` for .js attachments
+* Improve RFC2821 compliance for timelimits, especially for end-of-data
+* Add Azerbaijani translations (Thanks to @mirjalal)
+* Minor code cleanup for robustness
+* Add Indonesian translations (Thanks to @ceceprawiro)
+* Avoid `error_log` Debugoutput naming clash
+* Add ability to parse server capabilities in response to EHLO (useful for 
SendGrid etc)
+* Amended default values for WordWrap to match RFC
+* Remove html2text converter class (has incompatible license)
+* Provide new mechanism for injecting html to text converters
+* Improve pointers to docs and support in README
+* Add example file upload script
+* Refactor and major cleanup of EasyPeasyICS, now a lot more usable
+* Make set() method simpler and more reliable
+* Add Malay translation (Thanks to @nawawi)
+* Add Bulgarian translation (Thanks to @mialy)
+* Add Armenian translation (Thanks to Hrayr Grigoryan)
+* Add Slovenian translation (Thanks to Klemen Tušar)
+* More efficient word wrapping
+* Add support for S/MIME signing with additional CA certificate (thanks to 
@IgitBuh)
+* Fix incorrect MIME structure when using S/MIME signing and isMail() (#372)
+* Improved checks and error messages for missing extensions
+* Store and report SMTP errors more consistently
+* Add MIME multipart preamble for better Outlook compatibility
+* Enable TLS encryption automatically if the server offers it
+* Provide detailed errors when individual recipients fail
+* Report more errors when connecting
+* Add extras classes to composer classmap
+* Expose stream_context_create options via new SMTPOptions property
+* Automatic encoding switch to quoted-printable if message lines are too long
+* Add Korean translation (Thanks to @ChalkPE)
+* Provide a pointer to troubleshooting docs on SMTP connection failure
+
+## Version 5.2.9 (Sept 25th 2014)
+* **Important: The autoloader is no longer autoloaded by the PHPMailer class**
+* Update html2text from https://github.com/mtibben/html2text
+* Improve Arabic translations (Thanks to @tarekdj)
+* Consistent handling of connection variables in SMTP and POP3
+* PHPDoc cleanup
+* Update composer to use PHPUnit 4.1
+* Pass consistent params to callbacks
+* More consistent handling of error states and debug output
+* Use property defaults, remove constructors
+* Remove unreachable code
+* Use older regex validation pattern for troublesome PCRE library versions
+* Improve PCRE detection in older PHP versions
+* Handle debug output consistently, and always in UTF-8
+* Allow user-defined debug output method via a callable
+* msgHTML now converts data URIs to embedded images
+* SMTP::getLastReply() will now always be populated
+* Improved example code in README
+* Ensure long filenames in Content-Disposition are encoded correctly
+* Simplify SMTP debug output mechanism, clarify levels with constants
+* Add SMTP connection check example
+* Simplify examples, don't use mysql* functions
+
+## Version 5.2.8 (May 14th 2014)
 * Increase timeout to match RFC2821 section 4.5.3.2 and thus not fail 
greetdelays, fixes #104
 * Add timestamps to default debug output
 * Add connection events and new level 3 to debug output options
+* Chinese language update (Thanks to @binaryoung)
+* Allow custom Mailer types (Thanks to @michield)
+* Cope with spaces around SMTP host specs
+* Fix processing of multiple hosts in connect string
+* Added Galician translation (Thanks to @donatorouco)
+* Autoloader now prepends
+* Docs updates
+* Add Latvian translation (Thanks to @eddsstudio)
+* Add Belarusian translation (Thanks to @amaksymiuk)
+* Make autoloader work better on older PHP versions
+* Avoid double-encoding if mbstring is overloading mail()
+* Add Portuguese translation (Thanks to @Jonadabe)
+* Make quoted-printable encoder respect line ending setting
+* Improve Chinese translation (Thanks to @PeterDaveHello)
+* Add Georgian translation (Thanks to @akalongman)
+* Add Greek translation (Thanks to @lenasterg)
+* Fix serverHostname on PHP < 5.3
+* Improve performance of SMTP class
+* Implement automatic 7bit downgrade
+* Add Vietnamese translation (Thanks to @vinades)
+* Improve example images, switch to PNG
+* Add Croatian translation (Thanks to @hrvoj3e)
+* Remove setting the Return-Path and deprecate the Return-path property - it's 
just wrong!
+* Fix language file loading if CWD has changed (@stephandesouza)
+* Add HTML5 email validation pattern
+* Improve Turkish translations (Thanks to @yasinaydin)
+* Improve Romanian translations (Thanks to @aflorea)
+* Check php.ini for path to sendmail/qmail before using default
+* Improve Farsi translation (Thanks to @MHM5000)
+* Don't use quoted-printable encoding for multipart types
+* Add Serbian translation (Thanks to ajevremovic at gmail.com)
+* Remove useless PHP5 check
+* Use SVG for build status badges
+* Store MessageDate on creation
+* Better default behaviour for validateAddress
 
 ## Version 5.2.7 (September 12th 2013)
-* Add Ukranian translation from @Krezalis
+* Add Ukrainian translation from @Krezalis
 * Support for do_verp
 * Fix bug in CRAM-MD5 AUTH
 * Propagate Debugoutput option to SMTP class (@Reblutus)
@@ -126,7 +227,7 @@
                #52, #31, #41, #5. #70, #69
 
 ## Version 5.2.1 (January 16, 2012)
-* Closed several bugs#5
+* Closed several bugs #5
 * Performance improvements
 * MsgHTML() now returns the message as required.
 * New method: GetSentMIMEMessage() (returns full copy of sent message)
@@ -255,11 +356,11 @@
     to, an error was thrown for the date() functions used (line 1565 and 1569).
     This is NOT a PHPMailer error, it is the result of an incorrectly 
configured
     PHP5 installation. The fix is to modify your 'php.ini' file and include the
-    date.timezone = America/New York
+    date.timezone = Etc/UTC (or your own zone)
     directive, to your own server timezone
   - If you do get this error, and are unable to access your php.ini file:
     In your PHP script, add
-    `date_default_timezone_set('America/Toronto');`
+    `date_default_timezone_set('Etc/UTC');`
   - do not try to use
     `$myVar = date_default_timezone_get();`
     as a test, it will throw an error.
@@ -299,31 +400,6 @@
 * included example showing how to use PHPMailer with GMAIL
 * fixed the missing Cc in SendMail() and Mail()
 
-******************
-A note on sending bulk emails:
-
-If the email you are sending is not personalized, consider using the
-"undisclosed-recipient:;" strategy. That is, put all of your recipients
-in the Bcc field and set the To field to "undisclosed-recipients:;".
-It's a lot faster (only one send) and saves quite a bit on resources.
-Contrary to some opinions, this will not get you listed in spam engines -
-it's a legitimate way for you to send emails.
-
-A partial example for use with PHPMailer:
-
-```
-$mail->AddAddress("undisclosed-recipients:;");
-$mail->AddBCC("address@hidden,address@hidden,address@hidden");
-```
-
-Many email service providers restrict the number of emails that can be sent
-in any given time period. Often that is between 50 - 60 emails maximum
-per hour or per send session.
-
-If that's the case, then break up your Bcc lists into chunks that are one
-less than your limit, and put a pause in your script.
-*******************
-
 ## Version 2.0.0 rc1 (Thu, Nov 08 2007), interim release
 * dramatically simplified using inline graphics ... it's fully automated and 
requires no user input
 * added automatic document type detection for attachments and pictures
@@ -336,26 +412,8 @@
 * added Estonian language file by Indrek P&auml;ri
 * added header injection patch
 * added "set" method to permit users to create their own pseudo-properties 
like 'X-Headers', etc.
-  example of use:
-
-```
-$mail->set('X-Priority', '3');
-$mail->set('X-MSMail-Priority', 'Normal');
-```
-
 * fixed warning message in SMTP get_lines method
-* added TLS/SSL SMTP support. Example of use:
-
-```
-$mail = new PHPMailer();
-$mail->Mailer = "smtp";
-$mail->Host = "smtp.example.com";
-$mail->SMTPSecure   = "tls"; // option
-//$mail->SMTPSecure   = "ssl";  // option
-...
-$mail->Send();
-```
-
+* added TLS/SSL SMTP support.
 * PHPMailer has been tested with PHP4 (4.4.7) and PHP5 (5.2.7)
 * Works with PHP installed as a module or as CGI-PHP
 NOTE: will NOT work with PHP5 in E_STRICT error mode
@@ -486,7 +544,7 @@
 ## Version 1.15 (Fri, Jun 15 2001)
 Note: these changes contributed by Patrice Fournier
 * Changed all remaining \n to \r\n
-* Bcc: header no longer writen to message except
+* Bcc: header no longer written to message except
   when sent directly to sendmail
 * Added a small message to non-MIME compliant mail reader
 * Added Sender variable to change the Sender email

Modified: trunk/phpgwapi/inc/phpmailer/class.phpmailer.php
===================================================================
--- trunk/phpgwapi/inc/phpmailer/class.phpmailer.php    2015-08-14 23:56:19 UTC 
(rev 13721)
+++ trunk/phpgwapi/inc/phpmailer/class.phpmailer.php    2015-08-15 08:48:04 UTC 
(rev 13722)
@@ -1,15 +1,14 @@
 <?php
 /**
  * PHPMailer - PHP email creation and transport class.
- * PHP Version 5.0.0
- * Version 5.2.7
+ * PHP Version 5
  * @package PHPMailer
- * @link https://github.com/PHPMailer/PHPMailer/
- * @author Marcus Bointon (coolbru) <address@hidden>
+ * @link https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
+ * @author Marcus Bointon (Synchro/coolbru) <address@hidden>
  * @author Jim Jagielski (jimjag) <address@hidden>
  * @author Andy Prevost (codeworxtech) <address@hidden>
  * @author Brent R. Matzelle (original founder)
- * @copyright 2013 Marcus Bointon
+ * @copyright 2012 - 2014 Marcus Bointon
  * @copyright 2010 - 2012 Jim Jagielski
  * @copyright 2004 - 2009 Andy Prevost
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public 
License
@@ -18,21 +17,13 @@
  * FITNESS FOR A PARTICULAR PURPOSE.
  */
 
-if (version_compare(PHP_VERSION, '5.0.0', '<')) {
-    exit("Sorry, PHPMailer will only run on PHP version 5 or greater!\n");
-}
-
 /**
  * PHPMailer - PHP email creation and transport class.
- * PHP Version 5.0.0
  * @package PHPMailer
- * @author Marcus Bointon (coolbru) <address@hidden>
+ * @author Marcus Bointon (Synchro/coolbru) <address@hidden>
  * @author Jim Jagielski (jimjag) <address@hidden>
  * @author Andy Prevost (codeworxtech) <address@hidden>
  * @author Brent R. Matzelle (original founder)
- * @copyright 2013 Marcus Bointon
- * @copyright 2010 - 2012 Jim Jagielski
- * @copyright 2004 - 2009 Andy Prevost
  */
 class PHPMailer
 {
@@ -40,14 +31,15 @@
      * The PHPMailer Version number.
      * @type string
      */
-    public $Version = '5.2.7';
+    public $Version = '5.2.10';
 
     /**
      * Email priority.
-     * Options: 1 = High, 3 = Normal, 5 = low.
-     * @type int
+     * Options: null (default), 1 = High, 3 = Normal, 5 = low.
+     * When null, the header is not set at all.
+     * @type integer
      */
-    public $Priority = 3;
+    public $Priority = null;
 
     /**
      * The character set of the message.
@@ -97,6 +89,9 @@
      * The Return-Path of the message.
      * If empty, it will be set to either From or Sender.
      * @type string
+     * @deprecated Email senders should never set a return-path header;
+     * it's the receiver's job (RFC5321 section 4.4), so this no longer does 
anything.
+     * @link https://tools.ietf.org/html/rfc5321#section-4.4 RFC5321 reference
      */
     public $ReturnPath = '';
 
@@ -155,7 +150,8 @@
 
     /**
      * Word-wrap the message body to this number of chars.
-     * @type int
+     * Set to 0 to not wrap. A useful value here is 78, for RFC2822 section 
2.1.1 compliance.
+     * @type integer
      */
     public $WordWrap = 0;
 
@@ -175,7 +171,7 @@
     /**
      * Whether mail() uses a fully sendmail-compatible MTA.
      * One which supports sendmail's "-oi -f" options.
-     * @type bool
+     * @type boolean
      */
     public $UseSendmailOptions = true;
 
@@ -222,6 +218,8 @@
      * You can also specify a different port
      * for each host by using this format: [hostname:port]
      * (e.g. "smtp1.example.com:25;smtp2.example.com").
+     * You can also specify encryption type, for example:
+     * (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465").
      * Hosts will be tried in order.
      * @type string
      */
@@ -229,8 +227,8 @@
 
     /**
      * The default SMTP server port.
-     * @type int
-     * @Todo Why is this needed when the SMTP class takes care of it?
+     * @type integer
+     * @TODO Why is this needed when the SMTP class takes care of it?
      */
     public $Port = 25;
 
@@ -243,22 +241,36 @@
     public $Helo = '';
 
     /**
-     * The secure connection prefix.
-     * Options: "", "ssl" or "tls"
+     * What kind of encryption to use on the SMTP connection.
+     * Options: '', 'ssl' or 'tls'
      * @type string
      */
     public $SMTPSecure = '';
 
     /**
+     * Whether to enable TLS encryption automatically if a server supports it,
+     * even if `SMTPSecure` is not set to 'tls'.
+     * Be aware that in PHP >= 5.6 this requires that the server's 
certificates are valid.
+     * @type boolean
+     */
+    public $SMTPAutoTLS = true;
+
+    /**
      * Whether to use SMTP authentication.
      * Uses the Username and Password properties.
-     * @type bool
+     * @type boolean
      * @see PHPMailer::$Username
      * @see PHPMailer::$Password
      */
     public $SMTPAuth = false;
 
     /**
+     * Options array passed to stream_context_create when connecting via SMTP.
+     * @type array
+     */
+    public $SMTPOptions = array();
+
+    /**
      * SMTP username.
      * @type string
      */
@@ -293,45 +305,60 @@
 
     /**
      * The SMTP server timeout in seconds.
-     * @type int
+     * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
+     * @type integer
      */
-    public $Timeout = 10;
+    public $Timeout = 300;
 
     /**
      * SMTP class debug output mode.
-     * Options: 0 = off, 1 = commands, 2 = commands and data
-     * @type int
+     * Debug output level.
+     * Options:
+     * * `0` No output
+     * * `1` Commands
+     * * `2` Data and commands
+     * * `3` As 2 plus connection status
+     * * `4` Low-level data output
+     * @type integer
      * @see SMTP::$do_debug
      */
     public $SMTPDebug = 0;
 
     /**
-     * The function/method to use for debugging output.
-     * Options: "echo" or "error_log"
-     * @type string
+     * How to handle debug output.
+     * Options:
+     * * `echo` Output plain-text as-is, appropriate for CLI
+     * * `html` Output escaped, line breaks converted to `<br>`, appropriate 
for browser output
+     * * `error_log` Output to error log as configured in php.ini
+     *
+     * Alternatively, you can provide a callable expecting two params: a 
message string and the debug level:
+     * <code>
+     * $mail->Debugoutput = function($str, $level) {echo "debug level $level; 
message: $str";};
+     * </code>
+     * @type string|callable
      * @see SMTP::$Debugoutput
      */
-    public $Debugoutput = "echo";
+    public $Debugoutput = 'echo';
 
     /**
      * Whether to keep SMTP connection open after each message.
      * If this is set to true then to close the connection
      * requires an explicit call to smtpClose().
-     * @type bool
+     * @type boolean
      */
     public $SMTPKeepAlive = false;
 
     /**
      * Whether to split multiple to addresses into multiple messages
      * or send them all in one message.
-     * @type bool
+     * @type boolean
      */
     public $SingleTo = false;
 
     /**
      * Storage for addresses when SingleTo is enabled.
      * @type array
-     * @todo This should really not be public
+     * @TODO This should really not be public
      */
     public $SingleToArray = array();
 
@@ -339,13 +366,14 @@
      * Whether to generate VERP addresses on send.
      * Only applicable when sending via SMTP.
      * @link http://en.wikipedia.org/wiki/Variable_envelope_return_path
-     * @type bool
+     * @link http://www.postfix.org/VERP_README.html Postfix VERP info
+     * @type boolean
      */
     public $do_verp = false;
 
     /**
      * Whether to allow sending messages with an empty body.
-     * @type bool
+     * @type boolean
      */
     public $AllowEmpty = false;
 
@@ -396,28 +424,23 @@
      * The function that handles the result of the send email action.
      * It is called out by send() for each email sent.
      *
-     * Value can be:
-     * - 'function_name' for function names
-     * - 'Class::Method' for static method calls
-     * - array($object, 'Method') for calling methods on $object
-     * See http://php.net/is_callable manual page for more details.
+     * Value can be any php callable: http://www.php.net/is_callable
      *
      * Parameters:
-     *   bool    $result        result of the send action
+     *   boolean $result        result of the send action
      *   string  $to            email address of the recipient
      *   string  $cc            cc email addresses
      *   string  $bcc           bcc email addresses
      *   string  $subject       the subject
      *   string  $body          the email body
      *   string  $from          email address of sender
-     * 
      * @type string
      */
     public $action_function = '';
 
     /**
-     * What to use in the X-Mailer header.
-     * Options: null for default, whitespace for none, or a string to use
+     * What to put in the X-Mailer header.
+     * Options: An empty string for PHPMailer default, whitespace for none, or 
a string to use
      * @type string
      */
     public $XMailer = '';
@@ -459,7 +482,7 @@
 
     /**
      * An array of all kinds of addresses.
-     * Includes all of $to, $cc, $bcc, $replyto
+     * Includes all of $to, $cc, $bcc
      * @type array
      * @access protected
      */
@@ -529,6 +552,13 @@
     protected $sign_key_file = '';
 
     /**
+     * The optional S/MIME extra certificates ("CA Chain") file path.
+     * @type string
+     * @access protected
+     */
+    protected $sign_extracerts_file = '';
+
+    /**
      * The S/MIME password for the key.
      * Used only if the key is encrypted.
      * @type string
@@ -538,42 +568,51 @@
 
     /**
      * Whether to throw exceptions for errors.
-     * @type bool
+     * @type boolean
      * @access protected
      */
     protected $exceptions = false;
 
     /**
-     * Error severity: message only, continue processing
+     * Unique ID used for message ID and boundaries.
+     * @type string
+     * @access protected
      */
+    protected $uniqueid = '';
+
+    /**
+     * Error severity: message only, continue processing.
+     */
     const STOP_MESSAGE = 0;
 
     /**
-     * Error severity: message, likely ok to continue processing
+     * Error severity: message, likely ok to continue processing.
      */
     const STOP_CONTINUE = 1;
 
     /**
-     * Error severity: message, plus full stop, critical error reached
+     * Error severity: message, plus full stop, critical error reached.
      */
     const STOP_CRITICAL = 2;
 
     /**
-     * SMTP RFC standard line ending
+     * SMTP RFC standard line ending.
      */
     const CRLF = "\r\n";
 
     /**
-     * Constructor
-     * @param bool $exceptions Should we throw external exceptions?
+     * The maximum line length allowed by RFC 2822 section 2.1.1
+     * @type integer
      */
+    const MAX_LINE_LENGTH = 998;
+
+    /**
+     * Constructor.
+     * @param boolean $exceptions Should we throw external exceptions?
+     */
     public function __construct($exceptions = false)
     {
-        $this->exceptions = ($exceptions == true);
-        //Make sure our autoloader is loaded
-        if (!in_array('PHPMailerAutoload', spl_autoload_functions())) {
-            require 'PHPMailerAutoload.php';
-        }
+        $this->exceptions = (boolean)$exceptions;
     }
 
     /**
@@ -581,7 +620,8 @@
      */
     public function __destruct()
     {
-        if ($this->Mailer == 'smtp') { //close any open SMTP connection nicely
+        //Close any open SMTP connection nicely
+        if ($this->Mailer == 'smtp') {
             $this->smtpClose();
         }
     }
@@ -597,53 +637,75 @@
      * @param string $header Additional Header(s)
      * @param string $params Params
      * @access private
-     * @return bool
+     * @return boolean
      */
     private function mailPassthru($to, $subject, $body, $header, $params)
     {
+        //Check overloading of mail function to avoid double-encoding
+        if (ini_get('mbstring.func_overload') & 1) {
+            $subject = $this->secureHeader($subject);
+        } else {
+            $subject = $this->encodeHeader($this->secureHeader($subject));
+        }
         if (ini_get('safe_mode') || !($this->UseSendmailOptions)) {
-            $rt = @mail($to, 
$this->encodeHeader($this->secureHeader($subject)), $body, $header);
+            $result = @mail($to, $subject, $body, $header);
         } else {
-            $rt = @mail($to, 
$this->encodeHeader($this->secureHeader($subject)), $body, $header, $params);
+            $result = @mail($to, $subject, $body, $header, $params);
         }
-        return $rt;
+        return $result;
     }
 
     /**
      * Output debugging info via user-defined method.
-     * Only if debug output is enabled.
+     * Only generates output if SMTP debug output is enabled (@see 
SMTP::$do_debug).
      * @see PHPMailer::$Debugoutput
      * @see PHPMailer::$SMTPDebug
      * @param string $str
      */
     protected function edebug($str)
     {
-        if (!$this->SMTPDebug) {
+        if ($this->SMTPDebug <= 0) {
             return;
         }
+        //Avoid clash with built-in function names
+        if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) 
and is_callable($this->Debugoutput)) {
+            call_user_func($this->Debugoutput, $str, $this->SMTPDebug);
+            return;
+        }
         switch ($this->Debugoutput) {
             case 'error_log':
+                //Don't output, just log
                 error_log($str);
                 break;
             case 'html':
-                //Cleans up output a bit for a better looking display that's 
HTML-safe
-                echo htmlentities(preg_replace('/[\r\n]+/', '', $str), 
ENT_QUOTES, $this->CharSet) . "<br>\n";
+                //Cleans up output a bit for a better looking, HTML-safe output
+                echo htmlentities(
+                    preg_replace('/[\r\n]+/', '', $str),
+                    ENT_QUOTES,
+                    'UTF-8'
+                )
+                . "<br>\n";
                 break;
             case 'echo':
             default:
-                //Just echoes exactly what was received
-                echo $str;
+                //Normalize line breaks
+                $str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str);
+                echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
+                    "\n",
+                    "\n                   \t                  ",
+                    trim($str)
+                ) . "\n";
         }
     }
 
     /**
      * Sets message type to HTML or plain.
-     * @param bool $ishtml True for HTML mode.
+     * @param boolean $isHtml True for HTML mode.
      * @return void
      */
-    public function isHTML($ishtml = true)
+    public function isHTML($isHtml = true)
     {
-        if ($ishtml) {
+        if ($isHtml) {
             $this->ContentType = 'text/html';
         } else {
             $this->ContentType = 'text/plain';
@@ -674,8 +736,12 @@
      */
     public function isSendmail()
     {
-        if (!stristr(ini_get('sendmail_path'), 'sendmail')) {
-            $this->Sendmail = '/var/qmail/bin/sendmail';
+        $ini_sendmail_path = ini_get('sendmail_path');
+
+        if (!stristr($ini_sendmail_path, 'sendmail')) {
+            $this->Sendmail = '/usr/sbin/sendmail';
+        } else {
+            $this->Sendmail = $ini_sendmail_path;
         }
         $this->Mailer = 'sendmail';
     }
@@ -686,17 +752,21 @@
      */
     public function isQmail()
     {
-        if (stristr(ini_get('sendmail_path'), 'qmail')) {
-            $this->Sendmail = '/var/qmail/bin/sendmail';
+        $ini_sendmail_path = ini_get('sendmail_path');
+
+        if (!stristr($ini_sendmail_path, 'qmail')) {
+            $this->Sendmail = '/var/qmail/bin/qmail-inject';
+        } else {
+            $this->Sendmail = $ini_sendmail_path;
         }
-        $this->Mailer = 'sendmail';
+        $this->Mailer = 'qmail';
     }
 
     /**
      * Add a "To" address.
      * @param string $address
      * @param string $name
-     * @return bool true on success, false if address already used
+     * @return boolean true on success, false if address already used
      */
     public function addAddress($address, $name = '')
     {
@@ -708,7 +778,7 @@
      * @note: This function works with the SMTP mailer on win32, not with the 
"mail" mailer.
      * @param string $address
      * @param string $name
-     * @return bool true on success, false if address already used
+     * @return boolean true on success, false if address already used
      */
     public function addCC($address, $name = '')
     {
@@ -720,7 +790,7 @@
      * @note: This function works with the SMTP mailer on win32, not with the 
"mail" mailer.
      * @param string $address
      * @param string $name
-     * @return bool true on success, false if address already used
+     * @return boolean true on success, false if address already used
      */
     public function addBCC($address, $name = '')
     {
@@ -731,7 +801,7 @@
      * Add a "Reply-to" address.
      * @param string $address
      * @param string $name
-     * @return bool
+     * @return boolean
      */
     public function addReplyTo($address, $name = '')
     {
@@ -745,27 +815,27 @@
      * @param string $address The email address to send to
      * @param string $name
      * @throws phpmailerException
-     * @return bool true on success, false if address already used or invalid 
in some way
+     * @return boolean true on success, false if address already used or 
invalid in some way
      * @access protected
      */
     protected function addAnAddress($kind, $address, $name = '')
     {
         if (!preg_match('/^(to|cc|bcc|Reply-To)$/', $kind)) {
             $this->setError($this->lang('Invalid recipient array') . ': ' . 
$kind);
+            $this->edebug($this->lang('Invalid recipient array') . ': ' . 
$kind);
             if ($this->exceptions) {
                 throw new phpmailerException('Invalid recipient array: ' . 
$kind);
             }
-            $this->edebug($this->lang('Invalid recipient array') . ': ' . 
$kind);
             return false;
         }
         $address = trim($address);
         $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and 
trim
         if (!$this->validateAddress($address)) {
             $this->setError($this->lang('invalid_address') . ': ' . $address);
+            $this->edebug($this->lang('invalid_address') . ': ' . $address);
             if ($this->exceptions) {
                 throw new phpmailerException($this->lang('invalid_address') . 
': ' . $address);
             }
-            $this->edebug($this->lang('invalid_address') . ': ' . $address);
             return false;
         }
         if ($kind != 'Reply-To') {
@@ -784,12 +854,67 @@
     }
 
     /**
+     * Parse and validate a string containing one or more RFC822-style 
comma-separated email addresses
+     * of the form "display name <address>" into an array of name/address 
pairs.
+     * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is 
available.
+     * Note that quotes in the name part are removed.
+     * @param string $addrstr The address list string
+     * @param bool $useimap Whether to use the IMAP extension to parse the list
+     * @return array
+     * @link 
http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more 
careful implementation
+     */
+    public function parseAddresses($addrstr, $useimap = true)
+    {
+        $addresses = array();
+        if ($useimap and function_exists('imap_rfc822_parse_adrlist')) {
+            //Use this built-in parser if it's available
+            $list = imap_rfc822_parse_adrlist($addrstr, '');
+            foreach ($list as $address) {
+                if ($address->host != '.SYNTAX-ERROR.') {
+                    if ($this->validateAddress($address->mailbox . '@' . 
$address->host)) {
+                        $addresses[] = array(
+                            'name' => (property_exists($address, 'personal') ? 
$address->personal : ''),
+                            'address' => $address->mailbox . '@' . 
$address->host
+                        );
+                    }
+                }
+            }
+        } else {
+            //Use this simpler parser
+            $list = explode(',', $addrstr);
+            foreach ($list as $address) {
+                $address = trim($address);
+                //Is there a separate name part?
+                if (strpos($address, '<') === false) {
+                    //No separate name, just use the whole thing
+                    if ($this->validateAddress($address)) {
+                        $addresses[] = array(
+                            'name' => '',
+                            'address' => $address
+                        );
+                    }
+                } else {
+                    list($name, $email) = explode('<', $address);
+                    $email = trim(str_replace('>', '', $email));
+                    if ($this->validateAddress($email)) {
+                        $addresses[] = array(
+                            'name' => trim(str_replace(array('"', "'"), '', 
$name)),
+                            'address' => $email
+                        );
+                    }
+                }
+            }
+        }
+        return $addresses;
+    }
+
+    /**
      * Set the From and FromName properties.
      * @param string $address
      * @param string $name
-     * @param bool $auto Whether to also set the Sender address, defaults to 
true
+     * @param boolean $auto Whether to also set the Sender address, defaults 
to true
      * @throws phpmailerException
-     * @return bool
+     * @return boolean
      */
     public function setFrom($address, $name = '', $auto = true)
     {
@@ -797,10 +922,10 @@
         $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and 
trim
         if (!$this->validateAddress($address)) {
             $this->setError($this->lang('invalid_address') . ': ' . $address);
+            $this->edebug($this->lang('invalid_address') . ': ' . $address);
             if ($this->exceptions) {
                 throw new phpmailerException($this->lang('invalid_address') . 
': ' . $address);
             }
-            $this->edebug($this->lang('invalid_address') . ': ' . $address);
             return false;
         }
         $this->From = $address;
@@ -829,27 +954,31 @@
      * Check that a string looks like an email address.
      * @param string $address The email address to check
      * @param string $patternselect A selector for the validation pattern to 
use :
-     *   'auto' - pick best one automatically;
-     *   'pcre8' - use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 
5.3.2, 5.2.14;
-     *   'pcre' - use old PCRE implementation;
-     *   'php' - use PHP built-in FILTER_VALIDATE_EMAIL; faster, less thorough;
-     *   'noregex' - super fast, really dumb.
-     * @return bool
+     * * `auto` Pick strictest one automatically;
+     * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 
5.3.2, 5.2.14;
+     * * `pcre` Use old PCRE implementation;
+     * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL; same as pcre8 but does 
not allow 'dotless' domains;
+     * * `html5` Use the pattern given by the HTML5 spec for 'email' type form 
input elements.
+     * * `noregex` Don't use a regex: super fast, really dumb.
+     * @return boolean
      * @static
      * @access public
      */
     public static function validateAddress($address, $patternselect = 'auto')
     {
-        if ($patternselect == 'auto') {
-            if (defined(
-                'PCRE_VERSION'
-            )
-            ) { //Check this instead of extension_loaded so it works when that 
function is disabled
-                if (version_compare(PCRE_VERSION, '8.0') >= 0) {
+        if (!$patternselect or $patternselect == 'auto') {
+            //Check this constant first so it works when extension_loaded() is 
disabled by safe mode
+            //Constant was added in PHP 5.2.4
+            if (defined('PCRE_VERSION')) {
+                //This pattern can get stuck in a recursive loop in PCRE <= 
8.0.2
+                if (version_compare(PCRE_VERSION, '8.0.3') >= 0) {
                     $patternselect = 'pcre8';
                 } else {
                     $patternselect = 'pcre';
                 }
+            } elseif (function_exists('extension_loaded') and 
extension_loaded('pcre')) {
+                //Fall back to older PCRE
+                $patternselect = 'pcre';
             } else {
                 //Filter_var appeared in PHP 5.2.0 and does not require the 
PCRE extension
                 if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
@@ -862,14 +991,12 @@
         switch ($patternselect) {
             case 'pcre8':
                 /**
-                 * Conforms to RFC5322: Uses *correct* regex on which 
FILTER_VALIDATE_EMAIL is
-                 * based; So why not use FILTER_VALIDATE_EMAIL? Because it was 
broken to
-                 * not allow address@hidden type valid addresses :(
+                 * Uses the same RFC5322 regex on which FILTER_VALIDATE_EMAIL 
is based, but allows dotless domains.
                  * @link 
http://squiloople.com/2009/12/20/email-address-validation/
                  * @copyright 2009-2010 Michael Rushton
                  * Feel free to use and redistribute this code. But please 
keep this copyright notice.
                  */
-                return (bool)preg_match(
+                return (boolean)preg_match(
                     '/^(?!(?>(?1)"?(?>\\\[ 
-~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' .
                     '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t 
]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' .
                     
'(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)'
 .
@@ -881,10 +1008,9 @@
                     '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD',
                     $address
                 );
-                break;
             case 'pcre':
                 //An older regex that doesn't need a recent PCRE
-                return (bool)preg_match(
+                return (boolean)preg_match(
                     '/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ 
-~]|[^"])"?){65,}@)(?>' .
                     
'[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")'
 .
                     
'(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*'
 .
@@ -897,27 +1023,33 @@
                     
'|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD',
                     $address
                 );
-                break;
-            case 'php':
-            default:
-                return (bool)filter_var($address, FILTER_VALIDATE_EMAIL);
-                break;
+            case 'html5':
+                /**
+                 * This is the pattern used in the HTML5 spec for validation 
of 'email' type form input elements.
+                 * @link 
http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email)
+                 */
+                return (boolean)preg_match(
+                    
'/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|address@hidden(?:[a-zA-Z0-9-]{0,61}' .
+                    
'[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD',
+                    $address
+                );
             case 'noregex':
                 //No PCRE! Do something _very_ approximate!
                 //Check the address is 3 chars or longer and contains an @ 
that's not the first or last char
                 return (strlen($address) >= 3
                     and strpos($address, '@') >= 1
                     and strpos($address, '@') != strlen($address) - 1);
-                break;
+            case 'php':
+            default:
+                return (boolean)filter_var($address, FILTER_VALIDATE_EMAIL);
         }
     }
 
     /**
      * Create a message and send it.
      * Uses the sending method specified by $Mailer.
-     * Returns false on error - Use the ErrorInfo variable to view description 
of the error.
      * @throws phpmailerException
-     * @return bool
+     * @return boolean false on error - See the ErrorInfo property for details 
of the error.
      */
     public function send()
     {
@@ -926,11 +1058,11 @@
                 return false;
             }
             return $this->postSend();
-        } catch (phpmailerException $e) {
+        } catch (phpmailerException $exc) {
             $this->mailHeader = '';
-            $this->setError($e->getMessage());
+            $this->setError($exc->getMessage());
             if ($this->exceptions) {
-                throw $e;
+                throw $exc;
             }
             return false;
         }
@@ -939,12 +1071,12 @@
     /**
      * Prepare a message for sending.
      * @throws phpmailerException
-     * @return bool
+     * @return boolean
      */
     public function preSend()
     {
         try {
-            $this->mailHeader = "";
+            $this->mailHeader = '';
             if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) 
{
                 throw new phpmailerException($this->lang('provide_address'), 
self::STOP_CRITICAL);
             }
@@ -954,23 +1086,28 @@
                 $this->ContentType = 'multipart/alternative';
             }
 
-            $this->error_count = 0; // reset errors
+            $this->error_count = 0; // Reset errors
             $this->setMessageType();
             // Refuse to send an empty message unless we are specifically 
allowing it
             if (!$this->AllowEmpty and empty($this->Body)) {
                 throw new phpmailerException($this->lang('empty_message'), 
self::STOP_CRITICAL);
             }
 
+            // Create body before headers in case body makes changes to 
headers (e.g. altering transfer encoding)
+            $this->MIMEHeader = '';
+            $this->MIMEBody = $this->createBody();
+            // createBody may have added some headers, so retain them
+            $tempheaders = $this->MIMEHeader;
             $this->MIMEHeader = $this->createHeader();
-            $this->MIMEBody = $this->createBody();
+            $this->MIMEHeader .= $tempheaders;
 
             // To capture the complete message when using mail(), create
             // an extra header list which createHeader() doesn't fold in
             if ($this->Mailer == 'mail') {
                 if (count($this->to) > 0) {
-                    $this->mailHeader .= $this->addrAppend("To", $this->to);
+                    $this->mailHeader .= $this->addrAppend('To', $this->to);
                 } else {
-                    $this->mailHeader .= $this->headerLine("To", 
"undisclosed-recipients:;");
+                    $this->mailHeader .= $this->headerLine('To', 
'undisclosed-recipients:;');
                 }
                 $this->mailHeader .= $this->headerLine(
                     'Subject',
@@ -982,7 +1119,6 @@
             if (!empty($this->DKIM_domain)
                 && !empty($this->DKIM_private)
                 && !empty($this->DKIM_selector)
-                && !empty($this->DKIM_domain)
                 && file_exists($this->DKIM_private)) {
                 $header_dkim = $this->DKIM_Add(
                     $this->MIMEHeader . $this->mailHeader,
@@ -993,11 +1129,10 @@
                     str_replace("\r\n", "\n", $header_dkim) . self::CRLF;
             }
             return true;
-
-        } catch (phpmailerException $e) {
-            $this->setError($e->getMessage());
+        } catch (phpmailerException $exc) {
+            $this->setError($exc->getMessage());
             if ($this->exceptions) {
-                throw $e;
+                throw $exc;
             }
             return false;
         }
@@ -1007,7 +1142,7 @@
      * Actually send a message.
      * Send the email via the selected mechanism
      * @throws phpmailerException
-     * @return bool
+     * @return boolean
      */
     public function postSend()
     {
@@ -1015,20 +1150,26 @@
             // Choose the mailer and send through it
             switch ($this->Mailer) {
                 case 'sendmail':
+                case 'qmail':
                     return $this->sendmailSend($this->MIMEHeader, 
$this->MIMEBody);
                 case 'smtp':
                     return $this->smtpSend($this->MIMEHeader, $this->MIMEBody);
                 case 'mail':
                     return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
                 default:
+                    $sendMethod = $this->Mailer.'Send';
+                    if (method_exists($this, $sendMethod)) {
+                        return $this->$sendMethod($this->MIMEHeader, 
$this->MIMEBody);
+                    }
+
                     return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
             }
-        } catch (phpmailerException $e) {
-            $this->setError($e->getMessage());
+        } catch (phpmailerException $exc) {
+            $this->setError($exc->getMessage());
+            $this->edebug($exc->getMessage());
             if ($this->exceptions) {
-                throw $e;
+                throw $exc;
             }
-            $this->edebug($e->getMessage() . "\n");
         }
         return false;
     }
@@ -1040,27 +1181,41 @@
      * @see PHPMailer::$Sendmail
      * @throws phpmailerException
      * @access protected
-     * @return bool
+     * @return boolean
      */
     protected function sendmailSend($header, $body)
     {
         if ($this->Sender != '') {
-            $sendmail = sprintf("%s -oi -f%s -t", 
escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
+            if ($this->Mailer == 'qmail') {
+                $sendmail = sprintf('%s -f%s', 
escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
+            } else {
+                $sendmail = sprintf('%s -oi -f%s -t', 
escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
+            }
         } else {
-            $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail));
+            if ($this->Mailer == 'qmail') {
+                $sendmail = sprintf('%s', escapeshellcmd($this->Sendmail));
+            } else {
+                $sendmail = sprintf('%s -oi -t', 
escapeshellcmd($this->Sendmail));
+            }
         }
-        if ($this->SingleTo === true) {
-            foreach ($this->SingleToArray as $val) {
+        if ($this->SingleTo) {
+            foreach ($this->SingleToArray as $toAddr) {
                 if (address@hidden = popen($sendmail, 'w')) {
                     throw new phpmailerException($this->lang('execute') . 
$this->Sendmail, self::STOP_CRITICAL);
                 }
-                fputs($mail, "To: " . $val . "\n");
+                fputs($mail, 'To: ' . $toAddr . "\n");
                 fputs($mail, $header);
                 fputs($mail, $body);
                 $result = pclose($mail);
-                // implement call back function if it exists
-                $isSent = ($result == 0) ? 1 : 0;
-                $this->doCallback($isSent, $val, $this->cc, $this->bcc, 
$this->Subject, $body, $this->From);
+                $this->doCallback(
+                    ($result == 0),
+                    array($toAddr),
+                    $this->cc,
+                    $this->bcc,
+                    $this->Subject,
+                    $body,
+                    $this->From
+                );
                 if ($result != 0) {
                     throw new phpmailerException($this->lang('execute') . 
$this->Sendmail, self::STOP_CRITICAL);
                 }
@@ -1072,9 +1227,7 @@
             fputs($mail, $header);
             fputs($mail, $body);
             $result = pclose($mail);
-            // implement call back function if it exists
-            $isSent = ($result == 0) ? 1 : 0;
-            $this->doCallback($isSent, $this->to, $this->cc, $this->bcc, 
$this->Subject, $body, $this->From);
+            $this->doCallback(($result == 0), $this->to, $this->cc, 
$this->bcc, $this->Subject, $body, $this->From);
             if ($result != 0) {
                 throw new phpmailerException($this->lang('execute') . 
$this->Sendmail, self::STOP_CRITICAL);
             }
@@ -1089,43 +1242,39 @@
      * @link http://www.php.net/manual/en/book.mail.php
      * @throws phpmailerException
      * @access protected
-     * @return bool
+     * @return boolean
      */
     protected function mailSend($header, $body)
     {
         $toArr = array();
-        foreach ($this->to as $t) {
-            $toArr[] = $this->addrFormat($t);
+        foreach ($this->to as $toaddr) {
+            $toArr[] = $this->addrFormat($toaddr);
         }
         $to = implode(', ', $toArr);
 
         if (empty($this->Sender)) {
-            $params = " ";
+            $params = ' ';
         } else {
-            $params = sprintf("-f%s", $this->Sender);
+            $params = sprintf('-f%s', $this->Sender);
         }
         if ($this->Sender != '' and !ini_get('safe_mode')) {
             $old_from = ini_get('sendmail_from');
             ini_set('sendmail_from', $this->Sender);
         }
-        $rt = false;
-        if ($this->SingleTo === true && count($toArr) > 1) {
-            foreach ($toArr as $val) {
-                $rt = $this->mailPassthru($val, $this->Subject, $body, 
$header, $params);
-                // implement call back function if it exists
-                $isSent = ($rt == 1) ? 1 : 0;
-                $this->doCallback($isSent, $val, $this->cc, $this->bcc, 
$this->Subject, $body, $this->From);
+        $result = false;
+        if ($this->SingleTo && count($toArr) > 1) {
+            foreach ($toArr as $toAddr) {
+                $result = $this->mailPassthru($toAddr, $this->Subject, $body, 
$header, $params);
+                $this->doCallback($result, array($toAddr), $this->cc, 
$this->bcc, $this->Subject, $body, $this->From);
             }
         } else {
-            $rt = $this->mailPassthru($to, $this->Subject, $body, $header, 
$params);
-            // implement call back function if it exists
-            $isSent = ($rt == 1) ? 1 : 0;
-            $this->doCallback($isSent, $to, $this->cc, $this->bcc, 
$this->Subject, $body, $this->From);
+            $result = $this->mailPassthru($to, $this->Subject, $body, $header, 
$params);
+            $this->doCallback($result, $this->to, $this->cc, $this->bcc, 
$this->Subject, $body, $this->From);
         }
         if (isset($old_from)) {
             ini_set('sendmail_from', $old_from);
         }
-        if (!$rt) {
+        if (!$result) {
             throw new phpmailerException($this->lang('instantiate'), 
self::STOP_CRITICAL);
         }
         return true;
@@ -1154,62 +1303,59 @@
      * @throws phpmailerException
      * @uses SMTP
      * @access protected
-     * @return bool
+     * @return boolean
      */
     protected function smtpSend($header, $body)
     {
         $bad_rcpt = array();
-
-        if (!$this->smtpConnect()) {
+        if (!$this->smtpConnect($this->SMTPOptions)) {
             throw new phpmailerException($this->lang('smtp_connect_failed'), 
self::STOP_CRITICAL);
         }
-        $smtp_from = ($this->Sender == '') ? $this->From : $this->Sender;
+        if ('' == $this->Sender) {
+            $smtp_from = $this->From;
+        } else {
+            $smtp_from = $this->Sender;
+        }
         if (!$this->smtp->mail($smtp_from)) {
             $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . 
implode(',', $this->smtp->getError()));
             throw new phpmailerException($this->ErrorInfo, 
self::STOP_CRITICAL);
         }
 
-        // Attempt to send attach all recipients
-        foreach ($this->to as $to) {
-            if (!$this->smtp->recipient($to[0])) {
-                $bad_rcpt[] = $to[0];
-                $isSent = 0;
-            } else {
-                $isSent = 1;
+        // Attempt to send to all recipients
+        foreach (array($this->to, $this->cc, $this->bcc) as $togroup) {
+            foreach ($togroup as $to) {
+                if (!$this->smtp->recipient($to[0])) {
+                    $error = $this->smtp->getError();
+                    $bad_rcpt[] = array('to' => $to[0], 'error' => 
$error['detail']);
+                    $isSent = false;
+                } else {
+                    $isSent = true;
+                }
+                $this->doCallback($isSent, array($to[0]), array(), array(), 
$this->Subject, $body, $this->From);
             }
-            $this->doCallback($isSent, $to[0], '', '', $this->Subject, $body, 
$this->From);
         }
-        foreach ($this->cc as $cc) {
-            if (!$this->smtp->recipient($cc[0])) {
-                $bad_rcpt[] = $cc[0];
-                $isSent = 0;
-            } else {
-                $isSent = 1;
-            }
-            $this->doCallback($isSent, '', $cc[0], '', $this->Subject, $body, 
$this->From);
-        }
-        foreach ($this->bcc as $bcc) {
-            if (!$this->smtp->recipient($bcc[0])) {
-                $bad_rcpt[] = $bcc[0];
-                $isSent = 0;
-            } else {
-                $isSent = 1;
-            }
-            $this->doCallback($isSent, '', '', $bcc[0], $this->Subject, $body, 
$this->From);
-        }
 
-        if (count($bad_rcpt) > 0) { //Create error message for any bad 
addresses
-            throw new phpmailerException($this->lang('recipients_failed') . 
implode(', ', $bad_rcpt));
-        }
-        if (!$this->smtp->data($header . $body)) {
+        // Only send the DATA command if we have viable recipients
+        if ((count($this->all_recipients) > count($bad_rcpt)) and 
!$this->smtp->data($header . $body)) {
             throw new phpmailerException($this->lang('data_not_accepted'), 
self::STOP_CRITICAL);
         }
-        if ($this->SMTPKeepAlive == true) {
+        if ($this->SMTPKeepAlive) {
             $this->smtp->reset();
         } else {
             $this->smtp->quit();
             $this->smtp->close();
         }
+        //Create error message for any bad addresses
+        if (count($bad_rcpt) > 0) {
+            $errstr = '';
+            foreach ($bad_rcpt as $bad) {
+                $errstr .= $bad['to'] . ': ' . $bad['error'];
+            }
+            throw new phpmailerException(
+                $this->lang('recipients_failed') . $errstr,
+                self::STOP_CONTINUE
+            );
+        }
         return true;
     }
 
@@ -1220,7 +1366,7 @@
      * @uses SMTP
      * @access public
      * @throws phpmailerException
-     * @return bool
+     * @return boolean
      */
     public function smtpConnect($options = array())
     {
@@ -1228,7 +1374,7 @@
             $this->smtp = $this->getSMTPInstance();
         }
 
-        //Already connected?
+        // Already connected?
         if ($this->smtp->connected()) {
             return true;
         }
@@ -1237,25 +1383,47 @@
         $this->smtp->setDebugLevel($this->SMTPDebug);
         $this->smtp->setDebugOutput($this->Debugoutput);
         $this->smtp->setVerp($this->do_verp);
-        $tls = ($this->SMTPSecure == 'tls');
-        $ssl = ($this->SMTPSecure == 'ssl');
         $hosts = explode(';', $this->Host);
         $lastexception = null;
 
         foreach ($hosts as $hostentry) {
             $hostinfo = array();
-            $host = $hostentry;
+            if 
(!preg_match('/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*):?([0-9]*)$/', 
trim($hostentry), $hostinfo)) {
+                // Not a valid host entry
+                continue;
+            }
+            // $hostinfo[2]: optional ssl or tls prefix
+            // $hostinfo[3]: the hostname
+            // $hostinfo[4]: optional port number
+            // The host string prefix can temporarily override the current 
setting for SMTPSecure
+            // If it's not specified, the default value is used
+            $prefix = '';
+            $secure = $this->SMTPSecure;
+            $tls = ($this->SMTPSecure == 'tls');
+            if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == 
$this->SMTPSecure)) {
+                $prefix = 'ssl://';
+                $tls = false; // Can't have SSL and TLS at the same time
+                $secure = 'ssl';
+            } elseif ($hostinfo[2] == 'tls') {
+                $tls = true;
+                // tls doesn't use a prefix
+                $secure = 'tls';
+            }
+            //Do we need the OpenSSL extension?
+            $sslext = defined('OPENSSL_ALGO_SHA1');
+            if ('tls' === $secure or 'ssl' === $secure) {
+                //Check for an OpenSSL constant rather than using 
extension_loaded, which is sometimes disabled
+                if (!$sslext) {
+                    throw new 
phpmailerException($this->lang('extension_missing').'openssl', 
self::STOP_CRITICAL);
+                }
+            }
+            $host = $hostinfo[3];
             $port = $this->Port;
-            if (preg_match(
-                '/^(.+):([0-9]+)$/',
-                $hostentry,
-                $hostinfo
-            )
-            ) { //If $hostentry contains 'address:port', override default
-                $host = $hostinfo[1];
-                $port = $hostinfo[2];
+            $tport = (integer)$hostinfo[4];
+            if ($tport > 0 and $tport < 65536) {
+                $port = $tport;
             }
-            if ($this->smtp->connect(($ssl ? 'ssl://' : '') . $host, $port, 
$this->Timeout, $options)) {
+            if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, 
$options)) {
                 try {
                     if ($this->Helo) {
                         $hello = $this->Helo;
@@ -1263,12 +1431,19 @@
                         $hello = $this->serverHostname();
                     }
                     $this->smtp->hello($hello);
-
+                    //Automatically enable TLS encryption if:
+                    // * it's not disabled
+                    // * we have openssl extension
+                    // * we are not already using SSL
+                    // * the server offers STARTTLS
+                    if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' 
and $this->smtp->getServerExt('STARTTLS')) {
+                        $tls = true;
+                    }
                     if ($tls) {
                         if (!$this->smtp->startTLS()) {
                             throw new 
phpmailerException($this->lang('connect_host'));
                         }
-                        //We must resend HELO after tls negotiation
+                        // We must resend HELO after tls negotiation
                         $this->smtp->hello($hello);
                     }
                     if ($this->SMTPAuth) {
@@ -1284,16 +1459,17 @@
                         }
                     }
                     return true;
-                } catch (phpmailerException $e) {
-                    $lastexception = $e;
-                    //We must have connected, but then failed TLS or Auth, so 
close connection nicely
+                } catch (phpmailerException $exc) {
+                    $lastexception = $exc;
+                    $this->edebug($exc->getMessage());
+                    // We must have connected, but then failed TLS or Auth, so 
close connection nicely
                     $this->smtp->quit();
                 }
             }
         }
-        //If we get here, all connection attempts have failed, so close 
connection hard
+        // If we get here, all connection attempts have failed, so close 
connection hard
         $this->smtp->close();
-        //As we've caught all exceptions, just report whatever the last one was
+        // As we've caught all exceptions, just report whatever the last one 
was
         if ($this->exceptions and !is_null($lastexception)) {
             throw $lastexception;
         }
@@ -1320,12 +1496,12 @@
      * The default language is English.
      * @param string $langcode ISO 639-1 2-character language code (e.g. 
French is "fr")
      * @param string $lang_path Path to the language file directory, with 
trailing separator (slash)
-     * @return bool
+     * @return boolean
      * @access public
      */
-    public function setLanguage($langcode = 'en', $lang_path = 'language/')
+    public function setLanguage($langcode = 'en', $lang_path = '')
     {
-        //Define full set of translatable strings
+        // Define full set of translatable strings in English
         $PHPMAILER_LANG = array(
             'authenticate' => 'SMTP Error: Could not authenticate.',
             'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
@@ -1344,16 +1520,28 @@
             'signing' => 'Signing Error: ',
             'smtp_connect_failed' => 'SMTP connect() failed.',
             'smtp_error' => 'SMTP server error: ',
-            'variable_set' => 'Cannot set or reset variable: '
+            'variable_set' => 'Cannot set or reset variable: ',
+            'extension_missing' => 'Extension missing: '
         );
-        //Overwrite language-specific strings.
-        //This way we'll never have missing translations - no more "language 
string failed to load"!
-        $l = true;
-        if ($langcode != 'en') { //There is no English translation file
-            $l = @include $lang_path . 'phpmailer.lang-' . $langcode . '.php';
+        if (empty($lang_path)) {
+            // Calculate an absolute path so it can work if CWD is not here
+            $lang_path = dirname(__FILE__). DIRECTORY_SEPARATOR . 'language'. 
DIRECTORY_SEPARATOR;
         }
+        $foundlang = true;
+        $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php';
+        // There is no English translation file
+        if ($langcode != 'en') {
+            // Make sure language file path is readable
+            if (!is_readable($lang_file)) {
+                $foundlang = false;
+            } else {
+                // Overwrite language-specific strings.
+                // This way we'll never have missing translation keys.
+                $foundlang = include $lang_file;
+            }
+        }
         $this->language = $PHPMAILER_LANG;
-        return ($l == true); //Returns false if language not found
+        return (boolean)$foundlang; // Returns false if language not found
     }
 
     /**
@@ -1378,8 +1566,8 @@
     public function addrAppend($type, $addr)
     {
         $addresses = array();
-        foreach ($addr as $a) {
-            $addresses[] = $this->addrFormat($a);
+        foreach ($addr as $address) {
+            $addresses[] = $this->addrFormat($address);
         }
         return $type . ': ' . implode(', ', $addresses) . $this->LE;
     }
@@ -1396,9 +1584,9 @@
         if (empty($addr[1])) { // No name provided
             return $this->secureHeader($addr[0]);
         } else {
-            return $this->encodeHeader($this->secureHeader($addr[1]), 
'phrase') . " <" . $this->secureHeader(
+            return $this->encodeHeader($this->secureHeader($addr[1]), 
'phrase') . ' <' . $this->secureHeader(
                 $addr[0]
-            ) . ">";
+            ) . '>';
         }
     }
 
@@ -1409,47 +1597,54 @@
      * Original written by philippe.
      * @param string $message The message to wrap
      * @param integer $length The line length to wrap to
-     * @param bool $qp_mode Whether to run in Quoted-Printable mode
+     * @param boolean $qp_mode Whether to run in Quoted-Printable mode
      * @access public
      * @return string
      */
     public function wrapText($message, $length, $qp_mode = false)
     {
-        $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE;
+        if ($qp_mode) {
+            $soft_break = sprintf(' =%s', $this->LE);
+        } else {
+            $soft_break = $this->LE;
+        }
         // If utf-8 encoding is used, we will need to make sure we don't
         // split multibyte characters when we wrap
-        $is_utf8 = (strtolower($this->CharSet) == "utf-8");
+        $is_utf8 = (strtolower($this->CharSet) == 'utf-8');
         $lelen = strlen($this->LE);
         $crlflen = strlen(self::CRLF);
 
         $message = $this->fixEOL($message);
+        //Remove a trailing line break
         if (substr($message, -$lelen) == $this->LE) {
             $message = substr($message, 0, -$lelen);
         }
 
-        $line = explode($this->LE, $message); // Magic. We know fixEOL uses $LE
+        //Split message into lines
+        $lines = explode($this->LE, $message);
+        //Message will be rebuilt in here
         $message = '';
-        for ($i = 0; $i < count($line); $i++) {
-            $line_part = explode(' ', $line[$i]);
+        foreach ($lines as $line) {
+            $words = explode(' ', $line);
             $buf = '';
-            for ($e = 0; $e < count($line_part); $e++) {
-                $word = $line_part[$e];
+            $firstword = true;
+            foreach ($words as $word) {
                 if ($qp_mode and (strlen($word) > $length)) {
                     $space_left = $length - strlen($buf) - $crlflen;
-                    if ($e != 0) {
+                    if (!$firstword) {
                         if ($space_left > 20) {
                             $len = $space_left;
                             if ($is_utf8) {
                                 $len = $this->utf8CharBoundary($word, $len);
-                            } elseif (substr($word, $len - 1, 1) == "=") {
+                            } elseif (substr($word, $len - 1, 1) == '=') {
                                 $len--;
-                            } elseif (substr($word, $len - 2, 1) == "=") {
+                            } elseif (substr($word, $len - 2, 1) == '=') {
                                 $len -= 2;
                             }
                             $part = substr($word, 0, $len);
                             $word = substr($word, $len);
                             $buf .= ' ' . $part;
-                            $message .= $buf . sprintf("=%s", self::CRLF);
+                            $message .= $buf . sprintf('=%s', self::CRLF);
                         } else {
                             $message .= $buf . $soft_break;
                         }
@@ -1462,29 +1657,33 @@
                         $len = $length;
                         if ($is_utf8) {
                             $len = $this->utf8CharBoundary($word, $len);
-                        } elseif (substr($word, $len - 1, 1) == "=") {
+                        } elseif (substr($word, $len - 1, 1) == '=') {
                             $len--;
-                        } elseif (substr($word, $len - 2, 1) == "=") {
+                        } elseif (substr($word, $len - 2, 1) == '=') {
                             $len -= 2;
                         }
                         $part = substr($word, 0, $len);
                         $word = substr($word, $len);
 
                         if (strlen($word) > 0) {
-                            $message .= $part . sprintf("=%s", self::CRLF);
+                            $message .= $part . sprintf('=%s', self::CRLF);
                         } else {
                             $buf = $part;
                         }
                     }
                 } else {
                     $buf_o = $buf;
-                    $buf .= ($e == 0) ? $word : (' ' . $word);
+                    if (!$firstword) {
+                        $buf .= ' ';
+                    }
+                    $buf .= $word;
 
                     if (strlen($buf) > $length and $buf_o != '') {
                         $message .= $buf_o . $soft_break;
                         $buf = $word;
                     }
                 }
+                $firstword = false;
             }
             $message .= $buf . self::CRLF;
         }
@@ -1494,12 +1693,12 @@
 
     /**
      * Find the last character boundary prior to $maxLength in a utf-8
-     * quoted (printable) encoded string.
+     * quoted-printable encoded string.
      * Original written by Colin Brown.
      * @access public
      * @param string $encodedText utf-8 QP text
-     * @param int $maxLength   find last character boundary prior to this 
length
-     * @return int
+     * @param integer $maxLength Find the last character boundary prior to 
this length
+     * @return integer
      */
     public function utf8CharBoundary($encodedText, $maxLength)
     {
@@ -1507,23 +1706,27 @@
         $lookBack = 3;
         while (!$foundSplitPos) {
             $lastChunk = substr($encodedText, $maxLength - $lookBack, 
$lookBack);
-            $encodedCharPos = strpos($lastChunk, "=");
-            if ($encodedCharPos !== false) {
+            $encodedCharPos = strpos($lastChunk, '=');
+            if (false !== $encodedCharPos) {
                 // Found start of encoded character byte within $lookBack 
block.
                 // Check the encoded byte value (the 2 chars after the '=')
                 $hex = substr($encodedText, $maxLength - $lookBack + 
$encodedCharPos + 1, 2);
                 $dec = hexdec($hex);
-                if ($dec < 128) { // Single byte character.
+                if ($dec < 128) {
+                    // Single byte character.
                     // If the encoded char was found at pos 0, it will fit
                     // otherwise reduce maxLength to start of the encoded char
-                    $maxLength = ($encodedCharPos == 0) ? $maxLength :
-                        $maxLength - ($lookBack - $encodedCharPos);
+                    if ($encodedCharPos > 0) {
+                        $maxLength = $maxLength - ($lookBack - 
$encodedCharPos);
+                    }
                     $foundSplitPos = true;
-                } elseif ($dec >= 192) { // First byte of a multi byte 
character
+                } elseif ($dec >= 192) {
+                    // First byte of a multi byte character
                     // Reduce maxLength to split at start of character
                     $maxLength = $maxLength - ($lookBack - $encodedCharPos);
                     $foundSplitPos = true;
-                } elseif ($dec < 192) { // Middle byte of a multi byte 
character, look further back
+                } elseif ($dec < 192) {
+                    // Middle byte of a multi byte character, look further back
                     $lookBack += 3;
                 }
             } else {
@@ -1534,9 +1737,11 @@
         return $maxLength;
     }
 
-
     /**
-     * Set the body wrapping.
+     * Apply word wrapping to the message body.
+     * Wraps the message body to the number of chars set in the WordWrap 
property.
+     * You should only do this to plain-text bodies as wrapping HTML tags may 
break them.
+     * This is called automatically by createBody(), so you don't need to call 
it yourself.
      * @access public
      * @return void
      */
@@ -1568,38 +1773,26 @@
     {
         $result = '';
 
-        // Set the boundaries
-        $uniq_id = md5(uniqid(time()));
-        $this->boundary[1] = 'b1_' . $uniq_id;
-        $this->boundary[2] = 'b2_' . $uniq_id;
-        $this->boundary[3] = 'b3_' . $uniq_id;
-
         if ($this->MessageDate == '') {
-            $result .= $this->headerLine('Date', self::rfcDate());
-        } else {
-            $result .= $this->headerLine('Date', $this->MessageDate);
+            $this->MessageDate = self::rfcDate();
         }
+        $result .= $this->headerLine('Date', $this->MessageDate);
 
-        if ($this->ReturnPath) {
-            $result .= $this->headerLine('Return-Path', '<' . 
trim($this->ReturnPath) . '>');
-        } elseif ($this->Sender == '') {
-            $result .= $this->headerLine('Return-Path', '<' . 
trim($this->From) . '>');
-        } else {
-            $result .= $this->headerLine('Return-Path', '<' . 
trim($this->Sender) . '>');
-        }
 
         // To be created automatically by mail()
-        if ($this->Mailer != 'mail') {
-            if ($this->SingleTo === true) {
-                foreach ($this->to as $t) {
-                    $this->SingleToArray[] = $this->addrFormat($t);
+        if ($this->SingleTo) {
+            if ($this->Mailer != 'mail') {
+                foreach ($this->to as $toaddr) {
+                    $this->SingleToArray[] = $this->addrFormat($toaddr);
                 }
-            } else {
-                if (count($this->to) > 0) {
+            }
+        } else {
+            if (count($this->to) > 0) {
+                if ($this->Mailer != 'mail') {
                     $result .= $this->addrAppend('To', $this->to);
-                } elseif (count($this->cc) == 0) {
-                    $result .= $this->headerLine('To', 
'undisclosed-recipients:;');
                 }
+            } elseif (count($this->cc) == 0) {
+                $result .= $this->headerLine('To', 'undisclosed-recipients:;');
             }
         }
 
@@ -1611,7 +1804,11 @@
         }
 
         // sendmail and mail() extract Bcc from the header before sending
-        if ((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && 
(count($this->bcc) > 0)) {
+        if ((
+                $this->Mailer == 'sendmail' or $this->Mailer == 'qmail' or 
$this->Mailer == 'mail'
+            )
+            and count($this->bcc) > 0
+        ) {
             $result .= $this->addrAppend('Bcc', $this->bcc);
         }
 
@@ -1627,10 +1824,12 @@
         if ($this->MessageID != '') {
             $this->lastMessageID = $this->MessageID;
         } else {
-            $this->lastMessageID = sprintf("<address@hidden>", $uniq_id, 
$this->ServerHostname());
+            $this->lastMessageID = sprintf('<address@hidden>', 
$this->uniqueid, $this->ServerHostname());
         }
-        $result .= $this->HeaderLine('Message-ID', $this->lastMessageID);
-        $result .= $this->headerLine('X-Priority', $this->Priority);
+        $result .= $this->headerLine('Message-ID', $this->lastMessageID);
+        if (!is_null($this->Priority)) {
+            $result .= $this->headerLine('X-Priority', $this->Priority);
+        }
         if ($this->XMailer == '') {
             $result .= $this->headerLine(
                 'X-Mailer',
@@ -1648,10 +1847,10 @@
         }
 
         // Add custom headers
-        for ($index = 0; $index < count($this->CustomHeader); $index++) {
+        foreach ($this->CustomHeader as $header) {
             $result .= $this->headerLine(
-                trim($this->CustomHeader[$index][0]),
-                $this->encodeHeader(trim($this->CustomHeader[$index][1]))
+                trim($header[0]),
+                $this->encodeHeader(trim($header[1]))
             );
         }
         if (!$this->sign_key_file) {
@@ -1670,6 +1869,7 @@
     public function getMailMIME()
     {
         $result = '';
+        $ismultipart = true;
         switch ($this->message_type) {
             case 'inline':
                 $result .= $this->headerLine('Content-Type', 
'multipart/related;');
@@ -1690,11 +1890,20 @@
             default:
                 // Catches case 'plain': and case '':
                 $result .= $this->textLine('Content-Type: ' . 
$this->ContentType . '; charset=' . $this->CharSet);
+                $ismultipart = false;
                 break;
         }
-        //RFC1341 part 5 says 7bit is assumed if not specified
+        // RFC1341 part 5 says 7bit is assumed if not specified
         if ($this->Encoding != '7bit') {
-            $result .= $this->headerLine('Content-Transfer-Encoding', 
$this->Encoding);
+            // RFC 2045 section 6.4 says multipart MIME parts may only use 
7bit, 8bit or binary CTE
+            if ($ismultipart) {
+                if ($this->Encoding == '8bit') {
+                    $result .= $this->headerLine('Content-Transfer-Encoding', 
'8bit');
+                }
+                // The only remaining alternatives are quoted-printable and 
base64, which are both 7bit compatible
+            } else {
+                $result .= $this->headerLine('Content-Transfer-Encoding', 
$this->Encoding);
+            }
         }
 
         if ($this->Mailer != 'mail') {
@@ -1707,8 +1916,8 @@
     /**
      * Returns the whole MIME message.
      * Includes complete headers and body.
-     * Only valid post PreSend().
-     * @see PHPMailer::PreSend()
+     * Only valid post preSend().
+     * @see PHPMailer::preSend()
      * @access public
      * @return string
      */
@@ -1717,7 +1926,6 @@
         return $this->MIMEHeader . $this->mailHeader . self::CRLF . 
$this->MIMEBody;
     }
 
-
     /**
      * Assemble the message body.
      * Returns an empty string on failure.
@@ -1728,6 +1936,11 @@
     public function createBody()
     {
         $body = '';
+        //Create unique IDs and preset boundaries
+        $this->uniqueid = md5(uniqid(time()));
+        $this->boundary[1] = 'b1_' . $this->uniqueid;
+        $this->boundary[2] = 'b2_' . $this->uniqueid;
+        $this->boundary[3] = 'b3_' . $this->uniqueid;
 
         if ($this->sign_key_file) {
             $body .= $this->getMailMIME() . $this->LE;
@@ -1735,37 +1948,68 @@
 
         $this->setWordWrap();
 
+        $bodyEncoding = $this->Encoding;
+        $bodyCharSet = $this->CharSet;
+        //Can we do a 7-bit downgrade?
+        if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) {
+            $bodyEncoding = '7bit';
+            $bodyCharSet = 'us-ascii';
+        }
+        //If lines are too long, and we're not already using an encoding that 
will shorten them,
+        //change to quoted-printable transfer encoding
+        if ('base64' != $this->Encoding and 
self::hasLineLongerThanMax($this->Body)) {
+            $this->Encoding = 'quoted-printable';
+            $bodyEncoding = 'quoted-printable';
+        }
+
+        $altBodyEncoding = $this->Encoding;
+        $altBodyCharSet = $this->CharSet;
+        //Can we do a 7-bit downgrade?
+        if ($altBodyEncoding == '8bit' and 
!$this->has8bitChars($this->AltBody)) {
+            $altBodyEncoding = '7bit';
+            $altBodyCharSet = 'us-ascii';
+        }
+        //If lines are too long, change to quoted-printable transfer encoding
+        if (self::hasLineLongerThanMax($this->AltBody)) {
+            $altBodyEncoding = 'quoted-printable';
+        }
+        //Use this as a preamble in all multipart message types
+        $mimepre = "This is a multi-part message in MIME format." . $this->LE 
. $this->LE;
         switch ($this->message_type) {
             case 'inline':
-                $body .= $this->getBoundary($this->boundary[1], '', '', '');
-                $body .= $this->encodeString($this->Body, $this->Encoding);
+                $body .= $mimepre;
+                $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 
'', $bodyEncoding);
+                $body .= $this->encodeString($this->Body, $bodyEncoding);
                 $body .= $this->LE . $this->LE;
                 $body .= $this->attachAll('inline', $this->boundary[1]);
                 break;
             case 'attach':
-                $body .= $this->getBoundary($this->boundary[1], '', '', '');
-                $body .= $this->encodeString($this->Body, $this->Encoding);
+                $body .= $mimepre;
+                $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 
'', $bodyEncoding);
+                $body .= $this->encodeString($this->Body, $bodyEncoding);
                 $body .= $this->LE . $this->LE;
                 $body .= $this->attachAll('attachment', $this->boundary[1]);
                 break;
             case 'inline_attach':
+                $body .= $mimepre;
                 $body .= $this->textLine('--' . $this->boundary[1]);
                 $body .= $this->headerLine('Content-Type', 
'multipart/related;');
                 $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] 
. '"');
                 $body .= $this->LE;
-                $body .= $this->getBoundary($this->boundary[2], '', '', '');
-                $body .= $this->encodeString($this->Body, $this->Encoding);
+                $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 
'', $bodyEncoding);
+                $body .= $this->encodeString($this->Body, $bodyEncoding);
                 $body .= $this->LE . $this->LE;
                 $body .= $this->attachAll('inline', $this->boundary[2]);
                 $body .= $this->LE;
                 $body .= $this->attachAll('attachment', $this->boundary[1]);
                 break;
             case 'alt':
-                $body .= $this->getBoundary($this->boundary[1], '', 
'text/plain', '');
-                $body .= $this->encodeString($this->AltBody, $this->Encoding);
+                $body .= $mimepre;
+                $body .= $this->getBoundary($this->boundary[1], 
$altBodyCharSet, 'text/plain', $altBodyEncoding);
+                $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
                 $body .= $this->LE . $this->LE;
-                $body .= $this->getBoundary($this->boundary[1], '', 
'text/html', '');
-                $body .= $this->encodeString($this->Body, $this->Encoding);
+                $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 
'text/html', $bodyEncoding);
+                $body .= $this->encodeString($this->Body, $bodyEncoding);
                 $body .= $this->LE . $this->LE;
                 if (!empty($this->Ical)) {
                     $body .= $this->getBoundary($this->boundary[1], '', 
'text/calendar; method=REQUEST', '');
@@ -1775,49 +2019,52 @@
                 $body .= $this->endBoundary($this->boundary[1]);
                 break;
             case 'alt_inline':
-                $body .= $this->getBoundary($this->boundary[1], '', 
'text/plain', '');
-                $body .= $this->encodeString($this->AltBody, $this->Encoding);
+                $body .= $mimepre;
+                $body .= $this->getBoundary($this->boundary[1], 
$altBodyCharSet, 'text/plain', $altBodyEncoding);
+                $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
                 $body .= $this->LE . $this->LE;
                 $body .= $this->textLine('--' . $this->boundary[1]);
                 $body .= $this->headerLine('Content-Type', 
'multipart/related;');
                 $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] 
. '"');
                 $body .= $this->LE;
-                $body .= $this->getBoundary($this->boundary[2], '', 
'text/html', '');
-                $body .= $this->encodeString($this->Body, $this->Encoding);
+                $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 
'text/html', $bodyEncoding);
+                $body .= $this->encodeString($this->Body, $bodyEncoding);
                 $body .= $this->LE . $this->LE;
                 $body .= $this->attachAll('inline', $this->boundary[2]);
                 $body .= $this->LE;
                 $body .= $this->endBoundary($this->boundary[1]);
                 break;
             case 'alt_attach':
+                $body .= $mimepre;
                 $body .= $this->textLine('--' . $this->boundary[1]);
                 $body .= $this->headerLine('Content-Type', 
'multipart/alternative;');
                 $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] 
. '"');
                 $body .= $this->LE;
-                $body .= $this->getBoundary($this->boundary[2], '', 
'text/plain', '');
-                $body .= $this->encodeString($this->AltBody, $this->Encoding);
+                $body .= $this->getBoundary($this->boundary[2], 
$altBodyCharSet, 'text/plain', $altBodyEncoding);
+                $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
                 $body .= $this->LE . $this->LE;
-                $body .= $this->getBoundary($this->boundary[2], '', 
'text/html', '');
-                $body .= $this->encodeString($this->Body, $this->Encoding);
+                $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 
'text/html', $bodyEncoding);
+                $body .= $this->encodeString($this->Body, $bodyEncoding);
                 $body .= $this->LE . $this->LE;
                 $body .= $this->endBoundary($this->boundary[2]);
                 $body .= $this->LE;
                 $body .= $this->attachAll('attachment', $this->boundary[1]);
                 break;
             case 'alt_inline_attach':
+                $body .= $mimepre;
                 $body .= $this->textLine('--' . $this->boundary[1]);
                 $body .= $this->headerLine('Content-Type', 
'multipart/alternative;');
                 $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] 
. '"');
                 $body .= $this->LE;
-                $body .= $this->getBoundary($this->boundary[2], '', 
'text/plain', '');
-                $body .= $this->encodeString($this->AltBody, $this->Encoding);
+                $body .= $this->getBoundary($this->boundary[2], 
$altBodyCharSet, 'text/plain', $altBodyEncoding);
+                $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
                 $body .= $this->LE . $this->LE;
                 $body .= $this->textLine('--' . $this->boundary[2]);
                 $body .= $this->headerLine('Content-Type', 
'multipart/related;');
                 $body .= $this->textLine("\tboundary=\"" . $this->boundary[3] 
. '"');
                 $body .= $this->LE;
-                $body .= $this->getBoundary($this->boundary[3], '', 
'text/html', '');
-                $body .= $this->encodeString($this->Body, $this->Encoding);
+                $body .= $this->getBoundary($this->boundary[3], $bodyCharSet, 
'text/html', $bodyEncoding);
+                $body .= $this->encodeString($this->Body, $bodyEncoding);
                 $body .= $this->LE . $this->LE;
                 $body .= $this->attachAll('inline', $this->boundary[3]);
                 $body .= $this->LE;
@@ -1827,7 +2074,7 @@
                 break;
             default:
                 // catch case 'plain' and case ''
-                $body .= $this->encodeString($this->Body, $this->Encoding);
+                $body .= $this->encodeString($this->Body, $bodyEncoding);
                 break;
         }
 
@@ -1836,31 +2083,51 @@
         } elseif ($this->sign_key_file) {
             try {
                 if (!defined('PKCS7_TEXT')) {
-                    throw new phpmailerException($this->lang('signing') . ' 
OpenSSL extension missing.');
+                    throw new 
phpmailerException($this->lang('extension_missing') . 'openssl');
                 }
+                // @TODO would be nice to use php://temp streams here, but 
need to wrap for PHP < 5.1
                 $file = tempnam(sys_get_temp_dir(), 'mail');
-                file_put_contents($file, $body); //TODO check this worked
+                if (false === file_put_contents($file, $body)) {
+                    throw new phpmailerException($this->lang('signing') . ' 
Could not write temp file');
+                }
                 $signed = tempnam(sys_get_temp_dir(), 'signed');
-                if (@openssl_pkcs7_sign(
-                    $file,
-                    $signed,
-                    'file://' . realpath($this->sign_cert_file),
-                    array('file://' . realpath($this->sign_key_file), 
$this->sign_key_pass),
-                    null
-                )
-                ) {
+                //Workaround for PHP bug https://bugs.php.net/bug.php?id=69197
+                if (empty($this->sign_extracerts_file)) {
+                    $sign = @openssl_pkcs7_sign(
+                        $file,
+                        $signed,
+                        'file://' . realpath($this->sign_cert_file),
+                        array('file://' . realpath($this->sign_key_file), 
$this->sign_key_pass),
+                        null
+                    );
+                } else {
+                    $sign = @openssl_pkcs7_sign(
+                        $file,
+                        $signed,
+                        'file://' . realpath($this->sign_cert_file),
+                        array('file://' . realpath($this->sign_key_file), 
$this->sign_key_pass),
+                        null,
+                        PKCS7_DETACHED,
+                        $this->sign_extracerts_file
+                    );
+                }
+                if ($sign) {
                     @unlink($file);
                     $body = file_get_contents($signed);
                     @unlink($signed);
+                    //The message returned by openssl contains both headers 
and body, so need to split them up
+                    $parts = explode("\n\n", $body, 2);
+                    $this->MIMEHeader .= $parts[0] . $this->LE . $this->LE;
+                    $body = $parts[1];
                 } else {
                     @unlink($file);
                     @unlink($signed);
                     throw new phpmailerException($this->lang('signing') . 
openssl_error_string());
                 }
-            } catch (phpmailerException $e) {
+            } catch (phpmailerException $exc) {
                 $body = '';
                 if ($this->exceptions) {
-                    throw $e;
+                    throw $exc;
                 }
             }
         }
@@ -1889,9 +2156,12 @@
             $encoding = $this->Encoding;
         }
         $result .= $this->textLine('--' . $boundary);
-        $result .= sprintf("Content-Type: %s; charset=%s", $contentType, 
$charSet);
+        $result .= sprintf('Content-Type: %s; charset=%s', $contentType, 
$charSet);
         $result .= $this->LE;
-        $result .= $this->headerLine('Content-Transfer-Encoding', $encoding);
+        // RFC1341 part 5 says 7bit is assumed if not specified
+        if ($encoding != '7bit') {
+            $result .= $this->headerLine('Content-Transfer-Encoding', 
$encoding);
+        }
         $result .= $this->LE;
 
         return $result;
@@ -1917,19 +2187,19 @@
      */
     protected function setMessageType()
     {
-        $this->message_type = array();
+        $type = array();
         if ($this->alternativeExists()) {
-            $this->message_type[] = "alt";
+            $type[] = 'alt';
         }
         if ($this->inlineImageExists()) {
-            $this->message_type[] = "inline";
+            $type[] = 'inline';
         }
         if ($this->attachmentExists()) {
-            $this->message_type[] = "attach";
+            $type[] = 'attach';
         }
-        $this->message_type = implode("_", $this->message_type);
-        if ($this->message_type == "") {
-            $this->message_type = "plain";
+        $this->message_type = implode('_', $type);
+        if ($this->message_type == '') {
+            $this->message_type = 'plain';
         }
     }
 
@@ -1965,7 +2235,7 @@
      * @param string $type File extension (MIME) type.
      * @param string $disposition Disposition to use
      * @throws phpmailerException
-     * @return bool
+     * @return boolean
      */
     public function addAttachment($path, $name = '', $encoding = 'base64', 
$type = '', $disposition = 'attachment')
     {
@@ -1974,7 +2244,7 @@
                 throw new phpmailerException($this->lang('file_access') . 
$path, self::STOP_CONTINUE);
             }
 
-            //If a MIME type is not specified, try to work it out from the 
file name
+            // If a MIME type is not specified, try to work it out from the 
file name
             if ($type == '') {
                 $type = self::filenameToType($path);
             }
@@ -1995,12 +2265,12 @@
                 7 => 0
             );
 
-        } catch (phpmailerException $e) {
-            $this->setError($e->getMessage());
+        } catch (phpmailerException $exc) {
+            $this->setError($exc->getMessage());
+            $this->edebug($exc->getMessage());
             if ($this->exceptions) {
-                throw $e;
+                throw $exc;
             }
-            $this->edebug($e->getMessage() . "\n");
             return false;
         }
         return true;
@@ -2059,17 +2329,20 @@
                 }
                 $cidUniq[$cid] = true;
 
-                $mime[] = sprintf("--%s%s", $boundary, $this->LE);
+                $mime[] = sprintf('--%s%s', $boundary, $this->LE);
                 $mime[] = sprintf(
-                    "Content-Type: %s; name=\"%s\"%s",
+                    'Content-Type: %s; name="%s"%s',
                     $type,
                     $this->encodeHeader($this->secureHeader($name)),
                     $this->LE
                 );
-                $mime[] = sprintf("Content-Transfer-Encoding: %s%s", 
$encoding, $this->LE);
+                // RFC1341 part 5 says 7bit is assumed if not specified
+                if ($encoding != '7bit') {
+                    $mime[] = sprintf('Content-Transfer-Encoding: %s%s', 
$encoding, $this->LE);
+                }
 
                 if ($disposition == 'inline') {
-                    $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE);
+                    $mime[] = sprintf('Content-ID: <%s>%s', $cid, $this->LE);
                 }
 
                 // If a filename contains any of these chars, it should be 
quoted,
@@ -2077,18 +2350,19 @@
                 // Fixes a warning in IETF's msglint MIME checker
                 // Allow for bypassing the Content-Disposition header totally
                 if (!(empty($disposition))) {
-                    if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $name)) {
+                    $encoded_name = 
$this->encodeHeader($this->secureHeader($name));
+                    if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', 
$encoded_name)) {
                         $mime[] = sprintf(
-                            "Content-Disposition: %s; filename=\"%s\"%s",
+                            'Content-Disposition: %s; filename="%s"%s',
                             $disposition,
-                            $this->encodeHeader($this->secureHeader($name)),
+                            $encoded_name,
                             $this->LE . $this->LE
                         );
                     } else {
                         $mime[] = sprintf(
-                            "Content-Disposition: %s; filename=%s%s",
+                            'Content-Disposition: %s; filename=%s%s',
                             $disposition,
-                            $this->encodeHeader($this->secureHeader($name)),
+                            $encoded_name,
                             $this->LE . $this->LE
                         );
                     }
@@ -2113,9 +2387,9 @@
             }
         }
 
-        $mime[] = sprintf("--%s--%s", $boundary, $this->LE);
+        $mime[] = sprintf('--%s--%s', $boundary, $this->LE);
 
-        return implode("", $mime);
+        return implode('', $mime);
     }
 
     /**
@@ -2137,9 +2411,12 @@
             $magic_quotes = get_magic_quotes_runtime();
             if ($magic_quotes) {
                 if (version_compare(PHP_VERSION, '5.3.0', '<')) {
-                    set_magic_quotes_runtime(0);
+                    set_magic_quotes_runtime(false);
                 } else {
-                    ini_set('magic_quotes_runtime', 0);
+                    //Doesn't exist in PHP 5.4, but we don't need to check 
because
+                    //get_magic_quotes_runtime always returns false in 5.4+
+                    //so it will never get here
+                    ini_set('magic_quotes_runtime', false);
                 }
             }
             $file_buffer = file_get_contents($path);
@@ -2152,8 +2429,8 @@
                 }
             }
             return $file_buffer;
-        } catch (Exception $e) {
-            $this->setError($e->getMessage());
+        } catch (Exception $exc) {
+            $this->setError($exc->getMessage());
             return '';
         }
     }
@@ -2176,7 +2453,7 @@
             case '7bit':
             case '8bit':
                 $encoded = $this->fixEOL($str);
-                //Make sure it ends with a line break
+                // Make sure it ends with a line break
                 if (substr($encoded, -(strlen($this->LE))) != $this->LE) {
                     $encoded .= $this->LE;
                 }
@@ -2204,11 +2481,11 @@
      */
     public function encodeHeader($str, $position = 'text')
     {
-        $x = 0;
+        $matchcount = 0;
         switch (strtolower($position)) {
             case 'phrase':
                 if (!preg_match('/[\200-\377]/', $str)) {
-                    // Can't use addslashes as we don't know what value has 
magic_quotes_sybase
+                    // Can't use addslashes as we don't know the value of 
magic_quotes_sybase
                     $encoded = addcslashes($str, "\0..\37\177\\\"");
                     if (($str == $encoded) && 
!preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
                         return ($encoded);
@@ -2216,26 +2493,27 @@
                         return ("\"$encoded\"");
                     }
                 }
-                $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, 
$matches);
+                $matchcount = 
preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
                 break;
             /** @noinspection PhpMissingBreakStatementInspection */
             case 'comment':
-                $x = preg_match_all('/[()"]/', $str, $matches);
+                $matchcount = preg_match_all('/[()"]/', $str, $matches);
                 // Intentional fall-through
             case 'text':
             default:
-                $x += 
preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
+                $matchcount += 
preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
                 break;
         }
 
-        if ($x == 0) { //There are no chars that need encoding
+        //There are no chars that need encoding
+        if ($matchcount == 0) {
             return ($str);
         }
 
         $maxlen = 75 - 7 - strlen($this->CharSet);
         // Try to select the encoding which should produce the shortest output
-        if ($x > strlen($str) / 3) {
-            //More than a third of the content will need encoding, so B 
encoding will be most efficient
+        if ($matchcount > strlen($str) / 3) {
+            // More than a third of the content will need encoding, so B 
encoding will be most efficient
             $encoding = 'B';
             if (function_exists('mb_strlen') && $this->hasMultiBytes($str)) {
                 // Use a custom function which correctly encodes and wraps long
@@ -2253,7 +2531,7 @@
             $encoded = str_replace('=' . self::CRLF, "\n", trim($encoded));
         }
 
-        $encoded = preg_replace('/^(.*)$/m', " =?" . $this->CharSet . 
"?$encoding?\\1?=", $encoded);
+        $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . 
"?$encoding?\\1?=", $encoded);
         $encoded = trim(str_replace("\n", $this->LE, $encoded));
 
         return $encoded;
@@ -2263,7 +2541,7 @@
      * Check if a string contains multi-byte characters.
      * @access public
      * @param string $str multi-byte text to wrap encode
-     * @return bool
+     * @return boolean
      */
     public function hasMultiBytes($str)
     {
@@ -2275,21 +2553,32 @@
     }
 
     /**
+     * Does a string contain any 8-bit chars (in any charset)?
+     * @param string $text
+     * @return boolean
+     */
+    public function has8bitChars($text)
+    {
+        return (boolean)preg_match('/[\x80-\xFF]/', $text);
+    }
+
+    /**
      * Encode and wrap long multibyte strings for mail headers
      * without breaking lines within a character.
-     * Adapted from a function by paravoid at 
http://uk.php.net/manual/en/function.mb-encode-mimeheader.php
+     * Adapted from a function by paravoid
+     * @link 
http://www.php.net/manual/en/function.mb-encode-mimeheader.php#60283
      * @access public
      * @param string $str multi-byte text to wrap encode
-     * @param string $lf string to use as linefeed/end-of-line
+     * @param string $linebreak string to use as linefeed/end-of-line
      * @return string
      */
-    public function base64EncodeWrapMB($str, $lf = null)
+    public function base64EncodeWrapMB($str, $linebreak = null)
     {
-        $start = "=?" . $this->CharSet . "?B?";
-        $end = "?=";
-        $encoded = "";
-        if ($lf === null) {
-            $lf = $this->LE;
+        $start = '=?' . $this->CharSet . '?B?';
+        $end = '?=';
+        $encoded = '';
+        if ($linebreak === null) {
+            $linebreak = $this->LE;
         }
 
         $mb_length = mb_strlen($str, $this->CharSet);
@@ -2308,11 +2597,11 @@
                 $chunk = base64_encode($chunk);
                 $lookBack++;
             } while (strlen($chunk) > $length);
-            $encoded .= $chunk . $lf;
+            $encoded .= $chunk . $linebreak;
         }
 
         // Chomp the last linefeed
-        $encoded = substr($encoded, 0, -strlen($lf));
+        $encoded = substr($encoded, 0, -strlen($linebreak));
         return $encoded;
     }
 
@@ -2323,21 +2612,21 @@
      * @param string $string The text to encode
      * @param integer $line_max Number of chars allowed on a line before 
wrapping
      * @return string
-     * @link PHP version adapted from 
http://www.php.net/manual/en/function.quoted-printable-decode.php#89417
+     * @link 
http://www.php.net/manual/en/function.quoted-printable-decode.php#89417 Adapted 
from this comment
      */
     public function encodeQP($string, $line_max = 76)
     {
-        if (function_exists('quoted_printable_encode')) { //Use native 
function if it's available (>= PHP5.3)
+        // Use native function if it's available (>= PHP5.3)
+        if (function_exists('quoted_printable_encode')) {
             return quoted_printable_encode($string);
         }
-        //Fall back to a pure PHP implementation
+        // Fall back to a pure PHP implementation
         $string = str_replace(
             array('%20', '%0D%0A.', '%0D%0A', '%'),
             array(' ', "\r\n=2E", "\r\n", '='),
             rawurlencode($string)
         );
-        $string = preg_replace('/[^\r\n]{' . ($line_max - 3) . 
'}[^=\r\n]{2}/', "$0=\r\n", $string);
-        return $string;
+        return preg_replace('/[^\r\n]{' . ($line_max - 3) . '}[^=\r\n]{2}/', 
"$0=\r\n", $string);
     }
 
     /**
@@ -2346,7 +2635,7 @@
      * @access public
      * @param string $string
      * @param integer $line_max
-     * @param bool $space_conv
+     * @param boolean $space_conv
      * @return string
      * @deprecated Use encodeQP instead.
      */
@@ -2368,41 +2657,41 @@
      */
     public function encodeQ($str, $position = 'text')
     {
-        //There should not be any EOL in the string
+        // There should not be any EOL in the string
         $pattern = '';
         $encoded = str_replace(array("\r", "\n"), '', $str);
         switch (strtolower($position)) {
             case 'phrase':
-                //RFC 2047 section 5.3
+                // RFC 2047 section 5.3
                 $pattern = '^A-Za-z0-9!*+\/ -';
                 break;
             /** @noinspection PhpMissingBreakStatementInspection */
             case 'comment':
-                //RFC 2047 section 5.2
+                // RFC 2047 section 5.2
                 $pattern = '\(\)"';
-                //intentional fall-through
-                //for this reason we build the $pattern without including 
delimiters and []
+                // intentional fall-through
+                // for this reason we build the $pattern without including 
delimiters and []
             case 'text':
             default:
-                //RFC 2047 section 5.1
-                //Replace every high ascii, control, =, ? and _ characters
+                // RFC 2047 section 5.1
+                // Replace every high ascii, control, =, ? and _ characters
                 $pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . 
$pattern;
                 break;
         }
         $matches = array();
         if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
-            //If the string contains an '=', make sure it's the first thing we 
replace
-            //so as to avoid double-encoding
-            $s = array_search('=', $matches[0]);
-            if ($s !== false) {
-                unset($matches[0][$s]);
+            // If the string contains an '=', make sure it's the first thing 
we replace
+            // so as to avoid double-encoding
+            $eqkey = array_search('=', $matches[0]);
+            if (false !== $eqkey) {
+                unset($matches[0][$eqkey]);
                 array_unshift($matches[0], '=');
             }
             foreach (array_unique($matches[0]) as $char) {
                 $encoded = str_replace($char, '=' . sprintf('%02X', 
ord($char)), $encoded);
             }
         }
-        //Replace every spaces to _ (more readable than =20)
+        // Replace every spaces to _ (more readable than =20)
         return str_replace(' ', '_', $encoded);
     }
 
@@ -2425,7 +2714,7 @@
         $type = '',
         $disposition = 'attachment'
     ) {
-        //If a MIME type is not specified, try to work it out from the file 
name
+        // If a MIME type is not specified, try to work it out from the file 
name
         if ($type == '') {
             $type = self::filenameToType($filename);
         }
@@ -2445,7 +2734,7 @@
     /**
      * Add an embedded (inline) attachment from a file.
      * This can include images, sounds, and just about any other document type.
-     * These differ from 'regular' attachmants in that they are intended to be
+     * These differ from 'regular' attachments in that they are intended to be
      * displayed inline with the message, not just attached for download.
      * This is used in HTML messages that embed the images
      * the HTML refers to using the $cid value.
@@ -2456,7 +2745,7 @@
      * @param string $encoding File encoding (see $Encoding).
      * @param string $type File MIME type.
      * @param string $disposition Disposition to use
-     * @return bool True on successfully adding an attachment
+     * @return boolean True on successfully adding an attachment
      */
     public function addEmbeddedImage($path, $cid, $name = '', $encoding = 
'base64', $type = '', $disposition = 'inline')
     {
@@ -2465,7 +2754,7 @@
             return false;
         }
 
-        //If a MIME type is not specified, try to work it out from the file 
name
+        // If a MIME type is not specified, try to work it out from the file 
name
         if ($type == '') {
             $type = self::filenameToType($path);
         }
@@ -2501,7 +2790,7 @@
      * @param string $encoding File encoding (see $Encoding).
      * @param string $type MIME type.
      * @param string $disposition Disposition to use
-     * @return bool True on successfully adding an attachment
+     * @return boolean True on successfully adding an attachment
      */
     public function addStringEmbeddedImage(
         $string,
@@ -2511,7 +2800,7 @@
         $type = '',
         $disposition = 'inline'
     ) {
-        //If a MIME type is not specified, try to work it out from the name
+        // If a MIME type is not specified, try to work it out from the name
         if ($type == '') {
             $type = self::filenameToType($name);
         }
@@ -2533,7 +2822,7 @@
     /**
      * Check if an inline attachment is present.
      * @access public
-     * @return bool
+     * @return boolean
      */
     public function inlineImageExists()
     {
@@ -2547,7 +2836,7 @@
 
     /**
      * Check if an attachment (non-inline) is present.
-     * @return bool
+     * @return boolean
      */
     public function attachmentExists()
     {
@@ -2561,7 +2850,7 @@
 
     /**
      * Check if this message has an alternative body set.
-     * @return bool
+     * @return boolean
      */
     public function alternativeExists()
     {
@@ -2654,8 +2943,17 @@
         $this->error_count++;
         if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
             $lasterror = $this->smtp->getError();
-            if (!empty($lasterror) and array_key_exists('smtp_msg', 
$lasterror)) {
-                $msg .= '<p>' . $this->lang('smtp_error') . 
$lasterror['smtp_msg'] . "</p>\n";
+            if (!empty($lasterror['error'])) {
+                $msg .= $this->lang('smtp_error') . $lasterror['error'];
+                if (!empty($lasterror['detail'])) {
+                    $msg .= ' Detail: '. $lasterror['detail'];
+                }
+                if (!empty($lasterror['smtp_code'])) {
+                    $msg .= ' SMTP code: ' . $lasterror['smtp_code'];
+                }
+                if (!empty($lasterror['smtp_code_ex'])) {
+                    $msg .= ' Additional SMTP info: ' . 
$lasterror['smtp_code_ex'];
+                }
             }
         }
         $this->ErrorInfo = $msg;
@@ -2669,8 +2967,8 @@
      */
     public static function rfcDate()
     {
-        //Set the time zone to whatever the default is to avoid 500 errors
-        //Will default to UTC if it's not set properly in php.ini
+        // Set the time zone to whatever the default is to avoid 500 errors
+        // Will default to UTC if it's not set properly in php.ini
         date_default_timezone_set(@date_default_timezone_get());
         return date('D, j M Y H:i:s O');
     }
@@ -2683,14 +2981,16 @@
      */
     protected function serverHostname()
     {
+        $result = 'localhost.localdomain';
         if (!empty($this->Hostname)) {
             $result = $this->Hostname;
-        } elseif (isset($_SERVER['SERVER_NAME'])) {
+        } elseif (isset($_SERVER) and array_key_exists('SERVER_NAME', 
$_SERVER) and !empty($_SERVER['SERVER_NAME'])) {
             $result = $_SERVER['SERVER_NAME'];
-        } else {
-            $result = 'localhost.localdomain';
+        } elseif (function_exists('gethostname') && gethostname() !== false) {
+            $result = gethostname();
+        } elseif (php_uname('n') !== false) {
+            $result = php_uname('n');
         }
-
         return $result;
     }
 
@@ -2706,17 +3006,24 @@
             $this->setLanguage('en'); // set the default language
         }
 
-        if (isset($this->language[$key])) {
+        if (array_key_exists($key, $this->language)) {
+            if ($key == 'smtp_connect_failed') {
+                //Include a link to troubleshooting docs on SMTP connection 
failure
+                //this is by far the biggest cause of support questions
+                //but it's usually not PHPMailer's fault.
+                return $this->language[$key] . ' 
https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting';
+            }
             return $this->language[$key];
         } else {
-            return 'Language string failed to load: ' . $key;
+            //Return the key as a fallback
+            return $key;
         }
     }
 
     /**
      * Check if an error occurred.
      * @access public
-     * @return bool True if an error did occur.
+     * @return boolean True if an error did occur.
      */
     public function isError()
     {
@@ -2761,6 +3068,16 @@
     }
 
     /**
+     * Returns all custom headers
+     *
+     * @return array
+     */
+    public function getCustomHeaders()
+    {
+        return $this->CustomHeader;
+    }
+
+    /**
      * Create a message from an HTML string.
      * Automatically makes modifications for inline images and backgrounds
      * and creates a plain-text version by converting the HTML.
@@ -2768,22 +3085,39 @@
      * @access public
      * @param string $message HTML message string
      * @param string $basedir baseline directory for path
-     * @param bool $advanced Whether to use the advanced HTML to text converter
+     * @param boolean|callable $advanced Whether to use the internal HTML to 
text converter
+     *    or your own custom converter @see html2text()
      * @return string $message
      */
     public function msgHTML($message, $basedir = '', $advanced = false)
     {
-        preg_match_all("/(src|background)=[\"'](.*)[\"']/Ui", $message, 
$images);
+        preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, 
$images);
         if (isset($images[2])) {
-            foreach ($images[2] as $i => $url) {
-                // do not change urls for absolute images (thanks to 
corvuscorax)
-                if (!preg_match('#^[A-z]+://#', $url)) {
+            foreach ($images[2] as $imgindex => $url) {
+                // Convert data URIs into embedded images
+                if (preg_match('#^data:(image[^;,]*)(;base64)?,#', $url, 
$match)) {
+                    $data = substr($url, strpos($url, ','));
+                    if ($match[2]) {
+                        $data = base64_decode($data);
+                    } else {
+                        $data = rawurldecode($data);
+                    }
+                    $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
+                    if ($this->addStringEmbeddedImage($data, $cid, '', 
'base64', $match[1])) {
+                        $message = str_replace(
+                            $images[0][$imgindex],
+                            $images[1][$imgindex] . '="cid:' . $cid . '"',
+                            $message
+                        );
+                    }
+                } elseif (!preg_match('#^[A-z]+://#', $url)) {
+                    // Do not change urls for absolute images (thanks to 
corvuscorax)
                     $filename = basename($url);
                     $directory = dirname($url);
                     if ($directory == '.') {
                         $directory = '';
                     }
-                    $cid = md5($url) . '@phpmailer.0'; //RFC2392 S 2
+                    $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
                     if (strlen($basedir) > 1 && substr($basedir, -1) != '/') {
                         $basedir .= '/';
                     }
@@ -2795,12 +3129,12 @@
                         $cid,
                         $filename,
                         'base64',
-                        self::_mime_types(self::mb_pathinfo($filename, 
PATHINFO_EXTENSION))
+                        self::_mime_types((string)self::mb_pathinfo($filename, 
PATHINFO_EXTENSION))
                     )
                     ) {
                         $message = preg_replace(
-                            "/" . $images[1][$i] . "=[\"']" . preg_quote($url, 
'/') . "[\"']/Ui",
-                            $images[1][$i] . "=\"cid:" . $cid . "\"",
+                            '/' . $images[1][$imgindex] . '=["\']' . 
preg_quote($url, '/') . '["\']/Ui',
+                            $images[1][$imgindex] . '="cid:' . $cid . '"',
                             $message
                         );
                     }
@@ -2808,27 +3142,40 @@
             }
         }
         $this->isHTML(true);
+        // Convert all message body line breaks to CRLF, makes 
quoted-printable encoding work much better
+        $this->Body = $this->normalizeBreaks($message);
+        $this->AltBody = $this->normalizeBreaks($this->html2text($message, 
$advanced));
         if (empty($this->AltBody)) {
-            $this->AltBody = 'To view this email message, open it in a program 
that understands HTML!' . "\n\n";
+            $this->AltBody = 'To view this email message, open it in a program 
that understands HTML!' .
+                self::CRLF . self::CRLF;
         }
-        //Convert all message body line breaks to CRLF, makes quoted-printable 
encoding work much better
-        $this->Body = $this->normalizeBreaks($message);
-        $this->AltBody = $this->normalizeBreaks($this->html2text($message, 
$advanced));
         return $this->Body;
     }
 
     /**
      * Convert an HTML string into plain text.
+     * This is used by msgHTML().
+     * Note - older versions of this function used a bundled advanced converter
+     * which was been removed for license reasons in #232
+     * Example usage:
+     * <code>
+     * // Use default conversion
+     * $plain = $mail->html2text($html);
+     * // Use your own custom converter
+     * $plain = $mail->html2text($html, function($html) {
+     *     $converter = new MyHtml2text($html);
+     *     return $converter->get_text();
+     * });
+     * </code>
      * @param string $html The HTML text to convert
-     * @param bool $advanced Should this use the more complex html2text 
converter or just a simple one?
+     * @param boolean|callable $advanced Any boolean value to use the internal 
converter,
+     *   or provide your own callable for custom conversion.
      * @return string
      */
     public function html2text($html, $advanced = false)
     {
-        if ($advanced) {
-            require_once 'extras/class.html2text.php';
-            $h = new html2text($html);
-            return $h->get_text();
+        if (is_callable($advanced)) {
+            return call_user_func($advanced, $html);
         }
         return html_entity_decode(
             
trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/si', 
'', $html))),
@@ -2847,94 +3194,109 @@
     public static function _mime_types($ext = '')
     {
         $mimes = array(
-            'xl' => 'application/excel',
-            'hqx' => 'application/mac-binhex40',
-            'cpt' => 'application/mac-compactpro',
-            'bin' => 'application/macbinary',
-            'doc' => 'application/msword',
-            'word' => 'application/msword',
+            'xl'    => 'application/excel',
+            'js'    => 'application/javascript',
+            'hqx'   => 'application/mac-binhex40',
+            'cpt'   => 'application/mac-compactpro',
+            'bin'   => 'application/macbinary',
+            'doc'   => 'application/msword',
+            'word'  => 'application/msword',
+            'xlsx'  => 
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+            'xltx'  => 
'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
+            'potx'  => 
'application/vnd.openxmlformats-officedocument.presentationml.template',
+            'ppsx'  => 
'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
+            'pptx'  => 
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+            'sldx'  => 
'application/vnd.openxmlformats-officedocument.presentationml.slide',
+            'docx'  => 
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+            'dotx'  => 
'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
+            'xlam'  => 'application/vnd.ms-excel.addin.macroEnabled.12',
+            'xlsb'  => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
             'class' => 'application/octet-stream',
-            'dll' => 'application/octet-stream',
-            'dms' => 'application/octet-stream',
-            'exe' => 'application/octet-stream',
-            'lha' => 'application/octet-stream',
-            'lzh' => 'application/octet-stream',
-            'psd' => 'application/octet-stream',
-            'sea' => 'application/octet-stream',
-            'so' => 'application/octet-stream',
-            'oda' => 'application/oda',
-            'pdf' => 'application/pdf',
-            'ai' => 'application/postscript',
-            'eps' => 'application/postscript',
-            'ps' => 'application/postscript',
-            'smi' => 'application/smil',
-            'smil' => 'application/smil',
-            'mif' => 'application/vnd.mif',
-            'xls' => 'application/vnd.ms-excel',
-            'ppt' => 'application/vnd.ms-powerpoint',
+            'dll'   => 'application/octet-stream',
+            'dms'   => 'application/octet-stream',
+            'exe'   => 'application/octet-stream',
+            'lha'   => 'application/octet-stream',
+            'lzh'   => 'application/octet-stream',
+            'psd'   => 'application/octet-stream',
+            'sea'   => 'application/octet-stream',
+            'so'    => 'application/octet-stream',
+            'oda'   => 'application/oda',
+            'pdf'   => 'application/pdf',
+            'ai'    => 'application/postscript',
+            'eps'   => 'application/postscript',
+            'ps'    => 'application/postscript',
+            'smi'   => 'application/smil',
+            'smil'  => 'application/smil',
+            'mif'   => 'application/vnd.mif',
+            'xls'   => 'application/vnd.ms-excel',
+            'ppt'   => 'application/vnd.ms-powerpoint',
             'wbxml' => 'application/vnd.wap.wbxml',
-            'wmlc' => 'application/vnd.wap.wmlc',
-            'dcr' => 'application/x-director',
-            'dir' => 'application/x-director',
-            'dxr' => 'application/x-director',
-            'dvi' => 'application/x-dvi',
-            'gtar' => 'application/x-gtar',
-            'php3' => 'application/x-httpd-php',
-            'php4' => 'application/x-httpd-php',
-            'php' => 'application/x-httpd-php',
+            'wmlc'  => 'application/vnd.wap.wmlc',
+            'dcr'   => 'application/x-director',
+            'dir'   => 'application/x-director',
+            'dxr'   => 'application/x-director',
+            'dvi'   => 'application/x-dvi',
+            'gtar'  => 'application/x-gtar',
+            'php3'  => 'application/x-httpd-php',
+            'php4'  => 'application/x-httpd-php',
+            'php'   => 'application/x-httpd-php',
             'phtml' => 'application/x-httpd-php',
-            'phps' => 'application/x-httpd-php-source',
-            'js' => 'application/x-javascript',
-            'swf' => 'application/x-shockwave-flash',
-            'sit' => 'application/x-stuffit',
-            'tar' => 'application/x-tar',
-            'tgz' => 'application/x-tar',
-            'xht' => 'application/xhtml+xml',
+            'phps'  => 'application/x-httpd-php-source',
+            'swf'   => 'application/x-shockwave-flash',
+            'sit'   => 'application/x-stuffit',
+            'tar'   => 'application/x-tar',
+            'tgz'   => 'application/x-tar',
+            'xht'   => 'application/xhtml+xml',
             'xhtml' => 'application/xhtml+xml',
-            'zip' => 'application/zip',
-            'mid' => 'audio/midi',
-            'midi' => 'audio/midi',
-            'mp2' => 'audio/mpeg',
-            'mp3' => 'audio/mpeg',
-            'mpga' => 'audio/mpeg',
-            'aif' => 'audio/x-aiff',
-            'aifc' => 'audio/x-aiff',
-            'aiff' => 'audio/x-aiff',
-            'ram' => 'audio/x-pn-realaudio',
-            'rm' => 'audio/x-pn-realaudio',
-            'rpm' => 'audio/x-pn-realaudio-plugin',
-            'ra' => 'audio/x-realaudio',
-            'wav' => 'audio/x-wav',
-            'bmp' => 'image/bmp',
-            'gif' => 'image/gif',
-            'jpeg' => 'image/jpeg',
-            'jpe' => 'image/jpeg',
-            'jpg' => 'image/jpeg',
-            'png' => 'image/png',
-            'tiff' => 'image/tiff',
-            'tif' => 'image/tiff',
-            'eml' => 'message/rfc822',
-            'css' => 'text/css',
-            'html' => 'text/html',
-            'htm' => 'text/html',
+            'zip'   => 'application/zip',
+            'mid'   => 'audio/midi',
+            'midi'  => 'audio/midi',
+            'mp2'   => 'audio/mpeg',
+            'mp3'   => 'audio/mpeg',
+            'mpga'  => 'audio/mpeg',
+            'aif'   => 'audio/x-aiff',
+            'aifc'  => 'audio/x-aiff',
+            'aiff'  => 'audio/x-aiff',
+            'ram'   => 'audio/x-pn-realaudio',
+            'rm'    => 'audio/x-pn-realaudio',
+            'rpm'   => 'audio/x-pn-realaudio-plugin',
+            'ra'    => 'audio/x-realaudio',
+            'wav'   => 'audio/x-wav',
+            'bmp'   => 'image/bmp',
+            'gif'   => 'image/gif',
+            'jpeg'  => 'image/jpeg',
+            'jpe'   => 'image/jpeg',
+            'jpg'   => 'image/jpeg',
+            'png'   => 'image/png',
+            'tiff'  => 'image/tiff',
+            'tif'   => 'image/tiff',
+            'eml'   => 'message/rfc822',
+            'css'   => 'text/css',
+            'html'  => 'text/html',
+            'htm'   => 'text/html',
             'shtml' => 'text/html',
-            'log' => 'text/plain',
-            'text' => 'text/plain',
-            'txt' => 'text/plain',
-            'rtx' => 'text/richtext',
-            'rtf' => 'text/rtf',
-            'xml' => 'text/xml',
-            'xsl' => 'text/xml',
-            'mpeg' => 'video/mpeg',
-            'mpe' => 'video/mpeg',
-            'mpg' => 'video/mpeg',
-            'mov' => 'video/quicktime',
-            'qt' => 'video/quicktime',
-            'rv' => 'video/vnd.rn-realvideo',
-            'avi' => 'video/x-msvideo',
+            'log'   => 'text/plain',
+            'text'  => 'text/plain',
+            'txt'   => 'text/plain',
+            'rtx'   => 'text/richtext',
+            'rtf'   => 'text/rtf',
+            'vcf'   => 'text/vcard',
+            'vcard' => 'text/vcard',
+            'xml'   => 'text/xml',
+            'xsl'   => 'text/xml',
+            'mpeg'  => 'video/mpeg',
+            'mpe'   => 'video/mpeg',
+            'mpg'   => 'video/mpeg',
+            'mov'   => 'video/quicktime',
+            'qt'    => 'video/quicktime',
+            'rv'    => 'video/vnd.rn-realvideo',
+            'avi'   => 'video/x-msvideo',
             'movie' => 'video/x-sgi-movie'
         );
-        return (array_key_exists(strtolower($ext), $mimes) ? 
$mimes[strtolower($ext)]: 'application/octet-stream');
+        if (array_key_exists(strtolower($ext), $mimes)) {
+            return $mimes[strtolower($ext)];
+        }
+        return 'application/octet-stream';
     }
 
     /**
@@ -2946,9 +3308,9 @@
      */
     public static function filenameToType($filename)
     {
-        //In case the path is a URL, strip any query string before getting 
extension
+        // In case the path is a URL, strip any query string before getting 
extension
         $qpos = strpos($filename, '?');
-        if ($qpos !== false) {
+        if (false !== $qpos) {
             $filename = substr($filename, 0, $qpos);
         }
         $pathinfo = self::mb_pathinfo($filename);
@@ -2969,37 +3331,34 @@
     public static function mb_pathinfo($path, $options = null)
     {
         $ret = array('dirname' => '', 'basename' => '', 'extension' => '', 
'filename' => '');
-        $m = array();
-        
preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', 
$path, $m);
-        if (array_key_exists(1, $m)) {
-            $ret['dirname'] = $m[1];
+        $pathinfo = array();
+        if 
(preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', 
$path, $pathinfo)) {
+            if (array_key_exists(1, $pathinfo)) {
+                $ret['dirname'] = $pathinfo[1];
+            }
+            if (array_key_exists(2, $pathinfo)) {
+                $ret['basename'] = $pathinfo[2];
+            }
+            if (array_key_exists(5, $pathinfo)) {
+                $ret['extension'] = $pathinfo[5];
+            }
+            if (array_key_exists(3, $pathinfo)) {
+                $ret['filename'] = $pathinfo[3];
+            }
         }
-        if (array_key_exists(2, $m)) {
-            $ret['basename'] = $m[2];
-        }
-        if (array_key_exists(5, $m)) {
-            $ret['extension'] = $m[5];
-        }
-        if (array_key_exists(3, $m)) {
-            $ret['filename'] = $m[3];
-        }
         switch ($options) {
             case PATHINFO_DIRNAME:
             case 'dirname':
                 return $ret['dirname'];
-                break;
             case PATHINFO_BASENAME:
             case 'basename':
                 return $ret['basename'];
-                break;
             case PATHINFO_EXTENSION:
             case 'extension':
                 return $ret['extension'];
-                break;
             case PATHINFO_FILENAME:
             case 'filename':
                 return $ret['filename'];
-                break;
             default:
                 return $ret;
         }
@@ -3007,33 +3366,27 @@
 
     /**
      * Set or reset instance properties.
-     *
+     * You should avoid this function - it's more verbose, less efficient, 
more error-prone and
+     * harder to debug than setting properties directly.
      * Usage Example:
-     * $page->set('X-Priority', '3');
-     *
+     * `$mail->set('SMTPSecure', 'tls');`
+     *   is the same as:
+     * `$mail->SMTPSecure = 'tls';`
      * @access public
-     * @param string $name
-     * @param mixed $value
-     * NOTE: will not work with arrays, there are no arrays to set/reset
-     * @throws phpmailerException
-     * @return bool
-     * @todo Should this not be using __set() magic function?
+     * @param string $name The property name to set
+     * @param mixed $value The value to set the property to
+     * @return boolean
+     * @TODO Should this not be using the __set() magic function?
      */
     public function set($name, $value = '')
     {
-        try {
-            if (isset($this->$name)) {
-                $this->$name = $value;
-            } else {
-                throw new phpmailerException($this->lang('variable_set') . 
$name, self::STOP_CRITICAL);
-            }
-        } catch (Exception $e) {
-            $this->setError($e->getMessage());
-            if ($e->getCode() == self::STOP_CRITICAL) {
-                return false;
-            }
+        if (property_exists($this, $name)) {
+            $this->$name = $value;
+            return true;
+        } else {
+            $this->setError($this->lang('variable_set') . $name);
+            return false;
         }
-        return true;
     }
 
     /**
@@ -3064,17 +3417,19 @@
 
 
     /**
-     * Set the private key file and password for S/MIME signing.
+     * Set the public and private key files and password for S/MIME signing.
      * @access public
      * @param string $cert_filename
      * @param string $key_filename
      * @param string $key_pass Password for private key
+     * @param string $extracerts_filename Optional path to chain certificate
      */
-    public function sign($cert_filename, $key_filename, $key_pass)
+    public function sign($cert_filename, $key_filename, $key_pass, 
$extracerts_filename = '')
     {
         $this->sign_cert_file = $cert_filename;
         $this->sign_key_file = $key_filename;
         $this->sign_key_pass = $key_pass;
+        $this->sign_extracerts_file = $extracerts_filename;
     }
 
     /**
@@ -3091,7 +3446,7 @@
             if (((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E 
<= $ord) && ($ord <= 0x7E))) {
                 $line .= $txt[$i];
             } else {
-                $line .= "=" . sprintf("%02X", $ord);
+                $line .= '=' . sprintf('%02X', $ord);
             }
         }
         return $line;
@@ -3100,15 +3455,15 @@
     /**
      * Generate a DKIM signature.
      * @access public
-     * @param string $s Header
+     * @param string $signHeader
      * @throws phpmailerException
      * @return string
      */
-    public function DKIM_Sign($s)
+    public function DKIM_Sign($signHeader)
     {
         if (!defined('PKCS7_TEXT')) {
             if ($this->exceptions) {
-                throw new phpmailerException($this->lang("signing") . ' 
OpenSSL extension missing.');
+                throw new phpmailerException($this->lang('extension_missing') 
. 'openssl');
             }
             return '';
         }
@@ -3118,7 +3473,7 @@
         } else {
             $privKey = $privKeyStr;
         }
-        if (openssl_sign($s, $signature, $privKey)) {
+        if (openssl_sign($signHeader, $signature, $privKey)) {
             return base64_encode($signature);
         }
         return '';
@@ -3127,21 +3482,21 @@
     /**
      * Generate a DKIM canonicalization header.
      * @access public
-     * @param string $s Header
+     * @param string $signHeader Header
      * @return string
      */
-    public function DKIM_HeaderC($s)
+    public function DKIM_HeaderC($signHeader)
     {
-        $s = preg_replace("/\r\n\s+/", " ", $s);
-        $lines = explode("\r\n", $s);
+        $signHeader = preg_replace('/\r\n\s+/', ' ', $signHeader);
+        $lines = explode("\r\n", $signHeader);
         foreach ($lines as $key => $line) {
-            list($heading, $value) = explode(":", $line, 2);
+            list($heading, $value) = explode(':', $line, 2);
             $heading = strtolower($heading);
-            $value = preg_replace("/\s+/", " ", $value); // Compress useless 
spaces
-            $lines[$key] = $heading . ":" . trim($value); // Don't forget to 
remove WSP around the value
+            $value = preg_replace('/\s+/', ' ', $value); // Compress useless 
spaces
+            $lines[$key] = $heading . ':' . trim($value); // Don't forget to 
remove WSP around the value
         }
-        $s = implode("\r\n", $lines);
-        return $s;
+        $signHeader = implode("\r\n", $lines);
+        return $signHeader;
     }
 
     /**
@@ -3192,8 +3547,8 @@
                 $to_header = $header;
                 $current = 'to_header';
             } else {
-                if ($current && strpos($header, ' =?') === 0) {
-                    $current .= $header;
+                if (!empty($$current) && strpos($header, ' =?') === 0) {
+                    $$current .= $header;
                 } else {
                     $current = '';
                 }
@@ -3208,17 +3563,21 @@
         ); // Copied header fields (dkim-quoted-printable)
         $body = $this->DKIM_BodyC($body);
         $DKIMlen = strlen($body); // Length of body
-        $DKIMb64 = base64_encode(pack("H*", sha1($body))); // Base64 of packed 
binary SHA-1 hash of body
-        $ident = ($this->DKIM_identity == '') ? '' : " i=" . 
$this->DKIM_identity . ";";
-        $dkimhdrs = "DKIM-Signature: v=1; a=" .
-            $DKIMsignatureType . "; q=" .
-            $DKIMquery . "; l=" .
-            $DKIMlen . "; s=" .
+        $DKIMb64 = base64_encode(pack('H*', sha1($body))); // Base64 of packed 
binary SHA-1 hash of body
+        if ('' == $this->DKIM_identity) {
+            $ident = '';
+        } else {
+            $ident = ' i=' . $this->DKIM_identity . ';';
+        }
+        $dkimhdrs = 'DKIM-Signature: v=1; a=' .
+            $DKIMsignatureType . '; q=' .
+            $DKIMquery . '; l=' .
+            $DKIMlen . '; s=' .
             $this->DKIM_selector .
             ";\r\n" .
-            "\tt=" . $DKIMtime . "; c=" . $DKIMcanonicalization . ";\r\n" .
+            "\tt=" . $DKIMtime . '; c=' . $DKIMcanonicalization . ";\r\n" .
             "\th=From:To:Subject;\r\n" .
-            "\td=" . $this->DKIM_domain . ";" . $ident . "\r\n" .
+            "\td=" . $this->DKIM_domain . ';' . $ident . "\r\n" .
             "\tz=$from\r\n" .
             "\t|$to\r\n" .
             "\t|$subject;\r\n" .
@@ -3232,16 +3591,78 @@
     }
 
     /**
+     * Detect if a string contains a line longer than the maximum line length 
allowed.
+     * @param string $str
+     * @return boolean
+     * @static
+     */
+    public static function hasLineLongerThanMax($str)
+    {
+        //+2 to include CRLF line break for a 1000 total
+        return (boolean)preg_match('/^(.{'.(self::MAX_LINE_LENGTH + 
2).',})/m', $str);
+    }
+
+    /**
+     * Allows for public read access to 'to' property.
+     * @access public
+     * @return array
+     */
+    public function getToAddresses()
+    {
+        return $this->to;
+    }
+
+    /**
+     * Allows for public read access to 'cc' property.
+     * @access public
+     * @return array
+     */
+    public function getCcAddresses()
+    {
+        return $this->cc;
+    }
+
+    /**
+     * Allows for public read access to 'bcc' property.
+     * @access public
+     * @return array
+     */
+    public function getBccAddresses()
+    {
+        return $this->bcc;
+    }
+
+    /**
+     * Allows for public read access to 'ReplyTo' property.
+     * @access public
+     * @return array
+     */
+    public function getReplyToAddresses()
+    {
+        return $this->ReplyTo;
+    }
+
+    /**
+     * Allows for public read access to 'all_recipients' property.
+     * @access public
+     * @return array
+     */
+    public function getAllRecipientAddresses()
+    {
+        return $this->all_recipients;
+    }
+
+    /**
      * Perform a callback.
-     * @param bool $isSent
-     * @param string $to
-     * @param string $cc
-     * @param string $bcc
+     * @param boolean $isSent
+     * @param array $to
+     * @param array $cc
+     * @param array $bcc
      * @param string $subject
      * @param string $body
      * @param string $from
      */
-    protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, 
$from = null)
+    protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, 
$from)
     {
         if (!empty($this->action_function) && 
is_callable($this->action_function)) {
             $params = array($isSent, $to, $cc, $bcc, $subject, $body, $from);

Modified: trunk/phpgwapi/inc/phpmailer/class.pop3.php
===================================================================
--- trunk/phpgwapi/inc/phpmailer/class.pop3.php 2015-08-14 23:56:19 UTC (rev 
13721)
+++ trunk/phpgwapi/inc/phpmailer/class.pop3.php 2015-08-15 08:48:04 UTC (rev 
13722)
@@ -1,15 +1,14 @@
 <?php
 /**
  * PHPMailer POP-Before-SMTP Authentication Class.
- * PHP Version 5.0.0
- * Version 5.2.7
+ * PHP Version 5
  * @package PHPMailer
  * @link https://github.com/PHPMailer/PHPMailer/
- * @author Marcus Bointon (coolbru) <address@hidden>
+ * @author Marcus Bointon (Synchro/coolbru) <address@hidden>
  * @author Jim Jagielski (jimjag) <address@hidden>
  * @author Andy Prevost (codeworxtech) <address@hidden>
  * @author Brent R. Matzelle (original founder)
- * @copyright 2013 Marcus Bointon
+ * @copyright 2012 - 2014 Marcus Bointon
  * @copyright 2010 - 2012 Jim Jagielski
  * @copyright 2004 - 2009 Andy Prevost
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public 
License
@@ -24,11 +23,10 @@
  * Does not support APOP.
  * @package PHPMailer
  * @author Richard Davey (original author) <address@hidden>
- * @author Marcus Bointon (coolbru) <address@hidden>
+ * @author Marcus Bointon (Synchro/coolbru) <address@hidden>
  * @author Jim Jagielski (jimjag) <address@hidden>
  * @author Andy Prevost (codeworxtech) <address@hidden>
  */
-
 class POP3
 {
     /**
@@ -36,18 +34,18 @@
      * @type string
      * @access public
      */
-    public $Version = '5.2.7';
+    public $Version = '5.2.10';
 
     /**
      * Default POP3 port number.
-     * @type int
+     * @type integer
      * @access public
      */
     public $POP3_PORT = 110;
 
     /**
      * Default timeout in seconds.
-     * @type int
+     * @type integer
      * @access public
      */
     public $POP3_TIMEOUT = 30;
@@ -63,7 +61,7 @@
     /**
      * Debug display level.
      * Options: 0 = no, 1+ = yes
-     * @type int
+     * @type integer
      * @access public
      */
     public $do_debug = 0;
@@ -77,14 +75,14 @@
 
     /**
      * POP3 port number.
-     * @type int
+     * @type integer
      * @access public
      */
     public $port;
 
     /**
      * POP3 Timeout Value in seconds.
-     * @type int
+     * @type integer
      * @access public
      */
     public $tval;
@@ -112,17 +110,17 @@
 
     /**
      * Are we connected?
-     * @type bool
+     * @type boolean
      * @access private
      */
-    private $connected;
+    private $connected = false;
 
     /**
      * Error container.
      * @type array
      * @access private
      */
-    private $error;
+    private $errors = array();
 
     /**
      * Line break constant
@@ -130,36 +128,25 @@
     const CRLF = "\r\n";
 
     /**
-     * Constructor.
-     * @access public
-     */
-    public function __construct()
-    {
-        $this->pop_conn = 0;
-        $this->connected = false;
-        $this->error = null;
-    }
-
-    /**
      * Simple static wrapper for all-in-one POP before SMTP
      * @param $host
-     * @param bool $port
-     * @param bool $tval
+     * @param integer|boolean $port The port number to connect to
+     * @param integer|boolean $timeout The timeout value
      * @param string $username
      * @param string $password
-     * @param int $debug_level
-     * @return bool
+     * @param integer $debug_level
+     * @return boolean
      */
     public static function popBeforeSmtp(
         $host,
         $port = false,
-        $tval = false,
+        $timeout = false,
         $username = '',
         $password = '',
         $debug_level = 0
     ) {
         $pop = new POP3;
-        return $pop->authorise($host, $port, $tval, $username, $password, 
$debug_level);
+        return $pop->authorise($host, $port, $timeout, $username, $password, 
$debug_level);
     }
 
     /**
@@ -167,34 +154,34 @@
      * A connect, login, disconnect sequence
      * appropriate for POP-before SMTP authorisation.
      * @access public
-     * @param string $host
-     * @param bool|int $port
-     * @param bool|int $tval
+     * @param string $host The hostname to connect to
+     * @param integer|boolean $port The port number to connect to
+     * @param integer|boolean $timeout The timeout value
      * @param string $username
      * @param string $password
-     * @param int $debug_level
-     * @return bool
+     * @param integer $debug_level
+     * @return boolean
      */
-    public function authorise($host, $port = false, $tval = false, $username = 
'', $password = '', $debug_level = 0)
+    public function authorise($host, $port = false, $timeout = false, 
$username = '', $password = '', $debug_level = 0)
     {
         $this->host = $host;
         // If no port value provided, use default
-        if ($port === false) {
+        if (false === $port) {
             $this->port = $this->POP3_PORT;
         } else {
-            $this->port = $port;
+            $this->port = (integer)$port;
         }
         // If no timeout value provided, use default
-        if ($tval === false) {
+        if (false === $timeout) {
             $this->tval = $this->POP3_TIMEOUT;
         } else {
-            $this->tval = $tval;
+            $this->tval = (integer)$timeout;
         }
         $this->do_debug = $debug_level;
         $this->username = $username;
         $this->password = $password;
-        //  Refresh the error log
-        $this->error = null;
+        //  Reset the error log
+        $this->errors = array();
         //  connect
         $result = $this->connect($this->host, $this->port, $this->tval);
         if ($result) {
@@ -213,7 +200,7 @@
      * Connect to a POP3 server.
      * @access public
      * @param string $host
-     * @param bool|int $port
+     * @param integer|boolean $port
      * @param integer $tval
      * @return boolean
      */
@@ -228,6 +215,10 @@
         //Rather than suppress it with @fsockopen, capture it cleanly instead
         set_error_handler(array($this, 'catchWarning'));
 
+        if (false === $port) {
+            $port = $this->POP3_PORT;
+        }
+
         //  connect to the POP3 server
         $this->pop_conn = fsockopen(
             $host, //  POP3 Host
@@ -238,34 +229,20 @@
         ); //  Timeout (seconds)
         //  Restore the error handler
         restore_error_handler();
-        //  Does the Error Log now contain anything?
-        if ($this->error && $this->do_debug >= 1) {
-            $this->displayErrors();
-        }
+
         //  Did we connect?
-        if ($this->pop_conn == false) {
+        if (false === $this->pop_conn) {
             //  It would appear not...
-            $this->error = array(
+            $this->setError(array(
                 'error' => "Failed to connect to server $host on port $port",
                 'errno' => $errno,
                 'errstr' => $errstr
-            );
-            if ($this->do_debug >= 1) {
-                $this->displayErrors();
-            }
+            ));
             return false;
         }
 
         //  Increase the stream time-out
-        //  Check for PHP 4.3.0 or later
-        if (version_compare(phpversion(), '5.0.0', 'ge')) {
-            stream_set_timeout($this->pop_conn, $tval, 0);
-        } else {
-            //  Does not work on Windows
-            if (substr(PHP_OS, 0, 3) !== 'WIN') {
-                socket_set_timeout($this->pop_conn, $tval, 0);
-            }
-        }
+        stream_set_timeout($this->pop_conn, $tval, 0);
 
         //  Get the POP3 server response

@@ Diff output truncated at 153600 characters. @@



reply via email to

[Prev in Thread] Current Thread [Next in Thread]