Compare commits

..

No commits in common. "master" and "v6.10.0" have entirely different histories.

39 changed files with 612 additions and 1257 deletions

View File

@ -8,14 +8,7 @@ updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "cron"
cronjob: "10 22 5,20 * *" # At 22:10, every 5th and 20th day of the month.
interval: "weekly"
open-pull-requests-limit: 5
commit-message:
prefix: "GH Actions:"
groups:
action-runners:
applies-to: version-updates
update-types:
- "minor"
- "patch"

View File

@ -14,14 +14,13 @@ jobs:
if: github.repository == 'PHPMailer/PHPMailer'
steps:
- name: Checkout sources
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@v4
with:
fetch-depth: 1
persist-credentials: false
- name: Build Docs
uses: ./.github/actions/build-docs
- name: Publish Docs to gh-pages
uses: JamesIves/github-pages-deploy-action@9d877eea73427180ae43cf98e8914934fe157a1a # v4.7.6
uses: JamesIves/github-pages-deploy-action@v4
with:
branch: gh-pages
folder: docs

View File

@ -7,29 +7,30 @@ on:
push:
branches: [ "master" ]
permissions: {}
# Declare default permissions as read only.
permissions: read-all
jobs:
analysis:
# Don't run the cron job on forks.
if: ${{ github.event_name != 'schedule' || github.event.repository.fork == false }}
name: Scorecards analysis
runs-on: ubuntu-latest
permissions:
# Required when publishing results (badge / API / code scanning)
# Needed to upload the results to code-scanning dashboard.
security-events: write
# Used to receive a badge. (Upcoming feature)
id-token: write
# Needs for private repositories.
contents: read
actions: read
steps:
- name: "Checkout code"
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
uses: actions/checkout@v4
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46
with:
results_file: results.sarif
results_format: sarif
@ -48,7 +49,7 @@ jobs:
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@v4
with:
name: SARIF file
path: results.sarif
@ -56,6 +57,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif

View File

@ -6,7 +6,8 @@ on:
# Allow manually triggering the workflow.
workflow_dispatch:
permissions: {}
permissions:
contents: read # to fetch code (actions/checkout)
jobs:
@ -14,17 +15,12 @@ jobs:
runs-on: ubuntu-22.04
name: Coding standards
permissions:
contents: read # to fetch code (actions/checkout)
steps:
- name: Check out code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
uses: actions/checkout@v4
- name: Set up PHP
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # 2.36.0
uses: shivammathur/setup-php@v2
with:
php-version: 'latest'
coverage: none
@ -33,7 +29,7 @@ jobs:
# Install dependencies and handle caching in one go.
# @link https://github.com/marketplace/actions/install-php-dependencies-with-composer
- name: Install Composer dependencies
uses: "ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520" # 3.1.1
uses: "ramsey/composer-install@v3"
with:
# Bust the cache at least once a month - output format: YYYY-MM.
custom-cache-suffix: $(date -u "+%Y-%m")
@ -50,46 +46,40 @@ jobs:
runs-on: ubuntu-22.04
strategy:
matrix:
php: ['5.5', '7.2', '8.0', '8.5']
php: ['5.5', '7.2', '8.0', '8.4']
experimental: [false]
include:
- php: 'nightly'
- php: '8.5'
experimental: true
name: "Lint: PHP ${{ matrix.php }}"
continue-on-error: ${{ matrix.experimental }}
permissions:
contents: read # to fetch code (actions/checkout)
steps:
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
uses: actions/checkout@v4
- name: Install PHP
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # 2.36.0
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
ini-values: error_reporting=-1, display_errors=On, display_startup_errors=On
coverage: none
tools: cs2pr
# Install dependencies and handle caching in one go.
# @link https://github.com/marketplace/actions/install-php-dependencies-with-composer
- name: Install Composer dependencies
uses: "ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520" # 3.1.1
uses: "ramsey/composer-install@v3"
with:
# Bust the cache at least once a month - output format: YYYY-MM.
custom-cache-suffix: $(date -u "+%Y-%m")
- name: Lint against parse errors
if: ${{ matrix.php != 'nightly' }}
if: ${{ matrix.php != '8.5' }}
run: composer lint -- --checkstyle | cs2pr
- name: Lint against future parse errors (PHP nightly)
if: ${{ matrix.php == 'nightly' }}
- name: Lint against future parse errors (PHP 8.5)
if: ${{ matrix.php == '8.5' }}
run: composer lint
test:
@ -97,7 +87,7 @@ jobs:
runs-on: ubuntu-22.04
strategy:
matrix:
php: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4']
php: ['5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3']
extensions: ['optimal', 'minimal']
coverage: [false]
experimental: [false]
@ -111,21 +101,21 @@ jobs:
extensions: 'minimal'
coverage: true
experimental: false
- php: '8.5'
- php: '8.4'
extensions: 'optimal'
coverage: true
experimental: false
- php: '8.5'
- php: '8.4'
extensions: 'minimal'
coverage: true
experimental: false
# Experimental builds. These are allowed to fail.
- php: '8.6'
- php: '8.5'
extensions: 'optimal'
coverage: false
experimental: true
- php: '8.6'
- php: '8.5'
extensions: 'minimal'
coverage: false
experimental: true
@ -134,14 +124,9 @@ jobs:
continue-on-error: ${{ matrix.experimental }}
permissions:
contents: read # to fetch code (actions/checkout)
steps:
- name: Check out code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
uses: actions/checkout@v4
# About the "extensions":
#
@ -171,26 +156,26 @@ jobs:
fi
- name: Set up PHP
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # 2.36.0
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
coverage: ${{ matrix.coverage && 'xdebug' || 'none' }}
ini-values: sendmail_path=/usr/sbin/sendmail -t -i, error_reporting=-1, display_errors=On, display_startup_errors=On
ini-values: sendmail_path=/usr/sbin/sendmail -t -i, error_reporting=E_ALL, display_errors=On
extensions: ${{ steps.set_extensions.outputs.EXT }}
# Install dependencies and handle caching in one go.
# @link https://github.com/marketplace/actions/install-php-dependencies-with-composer
- name: Install PHP packages - normal
if: ${{ matrix.php != '8.6' }}
uses: "ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520" # 3.1.1
if: ${{ matrix.php != '8.5' }}
uses: "ramsey/composer-install@v3"
with:
composer-options: ${{ steps.set_extensions.outputs.COMPOSER_OPTIONS }}
# Bust the cache at least once a month - output format: YYYY-MM.
custom-cache-suffix: $(date -u "+%Y-%m")
- name: Install PHP packages - ignore-platform-reqs
if: ${{ matrix.php == '8.6' }}
uses: "ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520" # 3.1.1
if: ${{ matrix.php == '8.5' }}
uses: "ramsey/composer-install@v3"
with:
composer-options: --ignore-platform-reqs ${{ steps.set_extensions.outputs.COMPOSER_OPTIONS }}
# Bust the cache at least once a month - output format: YYYY-MM.
@ -199,7 +184,7 @@ jobs:
# Install postfix and automatically retry if the install failed, which happens reguarly.
# @link https://github.com/marketplace/actions/retry-step
- name: Install postfix
uses: nick-invision/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3.0.2
uses: nick-invision/retry@v3
with:
timeout_minutes: 2
max_attempts: 3
@ -227,8 +212,8 @@ jobs:
run: vendor/bin/phpunit
- name: Send coverage report to Codecov
if: ${{ success() && matrix.coverage == true && github.event.repository.fork == false }}
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
if: ${{ success() && matrix.coverage == true }}
uses: codecov/codecov-action@v4
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:

View File

@ -27,7 +27,7 @@
- Protects against header injection attacks
- Error messages in over 50 languages!
- DKIM and S/MIME signing support
- Compatible with PHP 5.5 and later, including PHP 8.5
- Compatible with PHP 5.5 and later, including PHP 8.4
- Namespaced to prevent name clashes
- Much more!
@ -48,7 +48,7 @@ This software is distributed under the [LGPL 2.1](https://www.gnu.org/licenses/o
PHPMailer is available on [Packagist](https://packagist.org/packages/phpmailer/phpmailer) (using semantic versioning), and installation via [Composer](https://getcomposer.org) is the recommended way to install PHPMailer. Just add this line to your `composer.json` file:
```json
"phpmailer/phpmailer": "^7.0.0"
"phpmailer/phpmailer": "^6.10.0"
```
or run

View File

@ -1 +1 @@
7.0.2
6.10.0

View File

@ -1,45 +1,5 @@
# PHPMailer Change Log
## Version 7.0.2 (January 9th, 2026)
* Fixes for sendmail parameter problems in WordPress, thanks to @SirLouen
* Reduce memory consumption when sending large attachments by @RobinvanderVliet
## Version 7.0.1 (November 25th, 2025)
* Use From domain when generating CIDs in msgHTML.
* Update to PHPCompatibility 10, resolve numerous PHPCS issues in PHP 8.5.
* Revise GitHub actions for PHP 8.5 and experimental 8.6 tests.
* Switch gmail example from the deprecated IMAP extension to use `directorytree/imapengine` for IMAP uploads.
* Set `htmlspecialchars()` flags explicitly and consistently.
* Convert XOAUTH2 token exceptions into PHPMailer Exceptions. The original exception is available as an inner exception.
* Deprecate VERSION constants in POP3 and SMTP classes.
* Remove dependency on `roave/security-advisories`; it's now built into composer 2.9.
* Update Dutch, Esperanto, and Norwegian translations.
## Version 7.0.0 (October 15th, 2025)
This is exactly the same as 6.11.1 but bumps the major version number to indicate the presence of a BC break in child classes. Specifically, `lang()`, `setLanguage()`, and `$language` are now static, and should be called statically.
## Version 6.12.0 (October 15th, 2025)
This is exactly the same as 6.10.0, reverting all the changes in 6.11.0 and 6.11.1, which inadvertently introduced a BC break affecting child classes. 6.11.1 has been re-released as 7.0.0.
## Version 6.11.1 (September 30th, 2025)
* Avoid function signature problems with the deprecation of `$useimap` in `parseAddresses`.
## Version 6.11.0 (September 29th, 2025)
* Add support for [RFC4954](https://www.rfc-editor.org/rfc/rfc4954#section-4) two-part authentication for large XOAUTH2 tokens.
* Also support empty tokens.
* Avoid bogus static analyser deprecation warnings in `setFrom`.
* Make language loading entirely static, thanks to @SirLouen.
* Emit warnings when `parseAddresses()` is used without the IMAP extension.
* Handle `mb_decode_mimeheader` changes from PHP 8.3+.
* Deprecate the charset param to parseAddresses.
* Fix PHP 8.5 linting issue.
* Don't use `-t` switch when calling qmail.
* Checking for interrupted system calls now works in languages other than English.
* Add support for extracting gmail transaction IDs after sending.
* For consistency, the protected `ReplyTo` property has been changed to match the format used for other address arrays.
* Fix line length issues when using S/MIME signing.
* Pin action runners to exact versions to avoid unexpected upstream changes.
## Version 6.10.0 (April 24th, 2025)
* Add support for [RFC 6530 SMTPUTF8](https://www.rfc-editor.org/rfc/rfc6530), permitting use of UTF-8 Unicode characters everywhere, thanks to @arnt and ICANN. See `SMTPUTF8.md` for details.
* More reliable checking for multibyte support.

View File

@ -42,25 +42,22 @@
"doctrine/annotations": "^1.2.6 || ^1.13.3",
"php-parallel-lint/php-console-highlighter": "^1.0.0",
"php-parallel-lint/php-parallel-lint": "^1.3.2",
"phpcompatibility/php-compatibility": "^10.0.0@dev",
"squizlabs/php_codesniffer": "^3.13.5",
"phpcompatibility/php-compatibility": "^9.3.5",
"roave/security-advisories": "dev-latest",
"squizlabs/php_codesniffer": "^3.7.2",
"yoast/phpunit-polyfills": "^1.0.4"
},
"suggest": {
"decomplexity/SendOauth2": "Adapter for using XOAUTH2 authentication",
"ext-imap": "Needed to support advanced email address parsing according to RFC822",
"ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
"ext-openssl": "Needed for secure SMTP sending and DKIM signing",
"greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication",
"hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
"league/oauth2-google": "Needed for Google XOAUTH2 authentication",
"psr/log": "For optional PSR-3 debug logging",
"symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)",
"thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication",
"directorytree/imapengine": "For uploading sent messages via IMAP, see gmail example"
"symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)"
},
"minimum-stability": "dev",
"prefer-stable": true,
"autoload": {
"psr-4": {
"PHPMailer\\PHPMailer\\": "src/"
@ -74,7 +71,6 @@
"license": "LGPL-2.1-only",
"scripts": {
"check": "./vendor/bin/phpcs",
"style": "./vendor/bin/phpcbf",
"test": "./vendor/bin/phpunit --no-coverage",
"coverage": "./vendor/bin/phpunit",
"lint": [

View File

@ -83,24 +83,26 @@ if (!$mail->send()) {
echo 'Message sent!';
//Section 2: IMAP
//Uncomment these to save your message in the 'Sent Mail' folder.
#save_mail($mail->getSentMIMEMessage());
#if (save_mail($mail)) {
# echo "Message saved!";
#}
}
//Section 2: IMAP
//This example uses the directorytree/imapengine IMAP library: https://imapengine.com
//Earlier versions of this code used the deprecated PHP imap_* functions.
function save_mail($message)
//IMAP commands requires the PHP IMAP Extension, found at: https://php.net/manual/en/imap.setup.php
//Function to call which uses the PHP imap_*() functions to save messages: https://php.net/manual/en/book.imap.php
//You can use imap_getmailboxes($imapStream, '/imap/ssl', '*' ) to get a list of available folders or labels, this can
//be useful if you are trying to get this working on a non-Gmail IMAP server.
function save_mail($mail)
{
$mailbox = new \DirectoryTree\ImapEngine\Mailbox([
'host' => 'imap.gmail.com',
'port' => 993,
'encryption' => 'ssl',
'username' => 'user@example.com',
'password' => 'password',
]);
//You can change 'Sent Mail' to any other folder or tag
$path = '{imap.gmail.com:993/imap/ssl}[Gmail]/Sent Mail';
// Find the "sent" messages folder yours may have a different name.
$folder = $mailbox->folders()->find('Sent Mail');
//Tell your server to open an IMAP connection using the same username and password as you used for SMTP
$imapStream = imap_open($path, $mail->Username, $mail->Password);
$folder->messages()->append($message);
$result = imap_append($imapStream, $path, $mail->getSentMIMEMessage());
imap_close($imapStream);
return $result;
}

View File

@ -8,7 +8,7 @@
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
error_reporting(E_ALL);
error_reporting(E_STRICT | E_ALL);
date_default_timezone_set('Etc/UTC');
@ -51,10 +51,7 @@ foreach ($result as $row) {
try {
$mail->addAddress($row['email'], $row['full_name']);
} catch (Exception $e) {
printf(
'Invalid address skipped: %s<br>',
htmlspecialchars($row['email'], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401)
);
echo 'Invalid address skipped: ' . htmlspecialchars($row['email']) . '<br>';
continue;
}
if (!empty($row['photo'])) {
@ -69,11 +66,8 @@ foreach ($result as $row) {
try {
$mail->send();
printf(
'Message sent to : %s (%s)<br>',
htmlspecialchars($row['full_name'], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401),
htmlspecialchars($row['email'], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401)
);
echo 'Message sent to :' . htmlspecialchars($row['full_name']) . ' (' .
htmlspecialchars($row['email']) . ')<br>';
//Mark it as sent in the DB
mysqli_query(
$mysql,
@ -81,11 +75,7 @@ foreach ($result as $row) {
mysqli_real_escape_string($mysql, $row['email']) . "'"
);
} catch (Exception $e) {
printf(
'Mailer Error (%s) %s<br>',
htmlspecialchars($row['email'], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401),
$mail->ErrorInfo
);
echo 'Mailer Error (' . htmlspecialchars($row['email']) . ') ' . $mail->ErrorInfo . '<br>';
//Reset the connection to abort sending this message
//The loop will continue trying to send to the rest of the list
$mail->getSMTPInstance()->reset();

View File

@ -54,7 +54,7 @@ if (array_key_exists('userfile', $_FILES)) {
<input type="submit" value="Send File">
</form>
<?php } else {
echo htmlspecialchars($msg, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401);
echo htmlspecialchars($msg);
} ?>
</body>
</html>

View File

@ -54,7 +54,7 @@ if (array_key_exists('userfile', $_FILES)) {
<input type="submit" value="Send Files">
</form>
<?php } else {
echo htmlspecialchars($msg, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401);
echo htmlspecialchars($msg);
} ?>
</body>
</html>

View File

@ -178,5 +178,5 @@ if (!isset($_GET['code'])) {
);
//Use this to interact with an API on the users behalf
//Use this to get a new access token if the old one expires
echo 'Refresh Token: ', htmlspecialchars($token->getRefreshToken(), ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401);
echo 'Refresh Token: ', htmlspecialchars($token->getRefreshToken());
}

View File

@ -34,6 +34,3 @@ $PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() fejlede.';
$PHPMAILER_LANG['smtp_detail'] = 'Detalje: ';
$PHPMAILER_LANG['smtp_error'] = 'SMTP server fejl: ';
$PHPMAILER_LANG['variable_set'] = 'Kunne ikke definere eller nulstille variablen: ';
$PHPMAILER_LANG['no_smtputf8'] = 'Serveren understøtter ikke SMTPUTF8 som påkrævet for at sende til Unicode adresser';
$PHPMAILER_LANG['imap_recommended'] = 'Brug af forenklet adresseparser anbefales ikke. Installer PHP IMAP udvidelsen for fuld RFC822 parsing.';
$PHPMAILER_LANG['deprecated_argument'] = 'Udfaset argument: ';

View File

@ -3,35 +3,24 @@
/**
* Esperanto PHPMailer language file: refer to English translation for definitive list
* @package PHPMailer
* @author Robin van der Vliet <info@robinvandervliet.com>
*/
$PHPMAILER_LANG['authenticate'] = 'SMTP-eraro: Ne eblis aŭtentigi.';
$PHPMAILER_LANG['buggy_php'] = 'Via versio de PHP estas trafita de cimo, kiu povas kaŭzi difektitajn mesaĝojn. Por ripari tion, ŝanĝu al sendado per SMTP, malŝaltu la opcion mail.add_x_header en via php.ini, ŝanĝu al MacOS aŭ Linux, aŭ ĝisdatigu vian PHP al versio 7.0.17+ aŭ 7.1.3+.';
$PHPMAILER_LANG['connect_host'] = 'SMTP-eraro: Ne eblis konektiĝi al la SMTP-gastiganto.';
$PHPMAILER_LANG['data_not_accepted'] = 'SMTP-eraro: Datumoj ne akceptitaj.';
$PHPMAILER_LANG['empty_message'] = 'Mesaĝokorpo malplena';
$PHPMAILER_LANG['authenticate'] = 'Eraro de servilo SMTP : aŭtentigo malsukcesis.';
$PHPMAILER_LANG['connect_host'] = 'Eraro de servilo SMTP : konektado al servilo malsukcesis.';
$PHPMAILER_LANG['data_not_accepted'] = 'Eraro de servilo SMTP : neĝustaj datumoj.';
$PHPMAILER_LANG['empty_message'] = 'Teksto de mesaĝo mankas.';
$PHPMAILER_LANG['encoding'] = 'Nekonata kodoprezento: ';
$PHPMAILER_LANG['execute'] = 'Ne eblis plenumi: ';
$PHPMAILER_LANG['extension_missing'] = 'Kromprogramo mankas: ';
$PHPMAILER_LANG['file_access'] = 'Ne eblis aliri la dosieron: ';
$PHPMAILER_LANG['file_open'] = 'Dosiera eraro: Ne eblis malfermi la dosieron: ';
$PHPMAILER_LANG['from_failed'] = 'La sekva(j) sendinto(j) malsukcesis: ';
$PHPMAILER_LANG['instantiate'] = 'Ne eblis funkciigi la retpoŝtan funkcion.';
$PHPMAILER_LANG['invalid_address'] = 'Nevalida adreso: ';
$PHPMAILER_LANG['invalid_header'] = 'Nevalida kaplinia nomo aŭ valoro';
$PHPMAILER_LANG['invalid_hostentry'] = 'Nevalida enigo de gastiganto: ';
$PHPMAILER_LANG['invalid_host'] = 'Nevalida gastiganto: ';
$PHPMAILER_LANG['mailer_not_supported'] = ' retpoŝtilo ne estas subtenata.';
$PHPMAILER_LANG['provide_address'] = 'Vi devas provizi almenaŭ unu retpoŝtadreson de ricevonto.';
$PHPMAILER_LANG['recipients_failed'] = 'SMTP-eraro: La sekva(j) ricevonto(j) malsukcesis: ';
$PHPMAILER_LANG['signing'] = 'Subskriba eraro: ';
$PHPMAILER_LANG['smtp_code'] = 'SMTP-kodo: ';
$PHPMAILER_LANG['smtp_code_ex'] = 'Pliaj SMTP-informoj: ';
$PHPMAILER_LANG['smtp_connect_failed'] = 'La SMTP-konektiĝo malsukcesis.';
$PHPMAILER_LANG['smtp_detail'] = 'Informoj: ';
$PHPMAILER_LANG['smtp_error'] = 'Eraro de SMTP-servilo: ';
$PHPMAILER_LANG['variable_set'] = 'Ne eblas agordi aŭ reagordi la variablon: ';
$PHPMAILER_LANG['no_smtputf8'] = 'La servilo ne subtenas SMTPUTF8, kiu estas bezonata por sendi al Unicode-adresoj.';
$PHPMAILER_LANG['imap_recommended'] = 'Uzado de la simpligita adresanalizilo ne estas rekomendita. Instalu la IMAP-kromprogramon por PHP por plena RFC822-analizado.';
$PHPMAILER_LANG['deprecated_argument'] = 'Malrekomendita argumento: ';
$PHPMAILER_LANG['execute'] = 'Lanĉi rulumadon ne eblis: ';
$PHPMAILER_LANG['file_access'] = 'Aliro al dosiero ne sukcesis: ';
$PHPMAILER_LANG['file_open'] = 'Eraro de dosiero: malfermo neeblas: ';
$PHPMAILER_LANG['from_failed'] = 'Jena adreso de sendinto malsukcesis: ';
$PHPMAILER_LANG['instantiate'] = 'Genero de retmesaĝa funkcio neeblis.';
$PHPMAILER_LANG['invalid_address'] = 'Retadreso ne validas: ';
$PHPMAILER_LANG['mailer_not_supported'] = ' mesaĝilo ne subtenata.';
$PHPMAILER_LANG['provide_address'] = 'Vi devas tajpi almenaŭ unu recevontan retadreson.';
$PHPMAILER_LANG['recipients_failed'] = 'Eraro de servilo SMTP : la jenaj poŝtrecivuloj kaŭzis eraron: ';
$PHPMAILER_LANG['signing'] = 'Eraro de subskribo: ';
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP konektado malsukcesis.';
$PHPMAILER_LANG['smtp_error'] = 'Eraro de servilo SMTP : ';
$PHPMAILER_LANG['variable_set'] = 'Variablo ne pravalorizeblas aŭ ne repravalorizeblas: ';
$PHPMAILER_LANG['extension_missing'] = 'Mankas etendo: ';

View File

@ -9,7 +9,7 @@
*/
$PHPMAILER_LANG['authenticate'] = 'Error SMTP: Imposible autentificar.';
$PHPMAILER_LANG['buggy_php'] = 'Tu versión de PHP ha sido afectada por un bug que puede resultar en mensajes corruptos. Para arreglarlo, cambia a enviar usando SMTP, deshabilita la opción mail.add_x_header en tu php.ini, cambia a MacOS o Linux, o actualiza tu PHP a la versión 7.0.17+ o 7.1.3+.';
$PHPMAILER_LANG['buggy_php'] = 'Tu versión de PHP está afectada por un bug que puede resultar en mensajes corruptos. Para arreglarlo, cambia a enviar usando SMTP, deshabilita la opción mail.add_x_header en tu php.ini, cambia a MacOS o Linux, o actualiza tu PHP a la versión 7.0.17+ o 7.1.3+.';
$PHPMAILER_LANG['connect_host'] = 'Error SMTP: Imposible conectar al servidor SMTP.';
$PHPMAILER_LANG['data_not_accepted'] = 'Error SMTP: Datos no aceptados.';
$PHPMAILER_LANG['empty_message'] = 'El cuerpo del mensaje está vacío.';
@ -18,7 +18,7 @@ $PHPMAILER_LANG['execute'] = 'Imposible ejecutar: ';
$PHPMAILER_LANG['extension_missing'] = 'Extensión faltante: ';
$PHPMAILER_LANG['file_access'] = 'Imposible acceder al archivo: ';
$PHPMAILER_LANG['file_open'] = 'Error de Archivo: Imposible abrir el archivo: ';
$PHPMAILER_LANG['from_failed'] = 'La siguiente dirección de remitente falló: ';
$PHPMAILER_LANG['from_failed'] = 'La(s) siguiente(s) direcciones de remitente fallaron: ';
$PHPMAILER_LANG['instantiate'] = 'Imposible crear una instancia de la función Mail.';
$PHPMAILER_LANG['invalid_address'] = 'Imposible enviar: dirección de email inválido: ';
$PHPMAILER_LANG['invalid_header'] = 'Nombre o valor de encabezado no válido';
@ -34,5 +34,3 @@ $PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() falló.';
$PHPMAILER_LANG['smtp_detail'] = 'Detalle: ';
$PHPMAILER_LANG['smtp_error'] = 'Error del servidor SMTP: ';
$PHPMAILER_LANG['variable_set'] = 'No se pudo configurar la variable: ';
$PHPMAILER_LANG['imap_recommended'] = 'No se recomienda usar el analizador de direcciones simplificado. Instala la extensión IMAP de PHP para un análisis RFC822 más completo.';
$PHPMAILER_LANG['deprecated_argument'] = 'Argumento obsoleto: ';

View File

@ -3,21 +3,20 @@
/**
* Norwegian Bokmål PHPMailer language file: refer to English translation for definitive list
* @package PHPMailer
* @author Wera AS <wordpress@wera.no>
*/
$PHPMAILER_LANG['authenticate'] = 'SMTP-feil: Kunne ikke autentisere.';
$PHPMAILER_LANG['buggy_php'] = 'Din versjon av PHP er påvirket av en feil som kan føre til ødelagte meldinger. For å løse problemet kan du bytte til sending via SMTP, deaktivere mail.add_x_header-alternativet i php.ini, bytte til MacOS eller Linux, eller oppgradere PHP til versjon 7.0.17+ eller 7.1.3+.';
$PHPMAILER_LANG['authenticate'] = 'SMTP-feil: Kunne ikke autentiseres.';
$PHPMAILER_LANG['buggy_php'] = 'Din versjon av PHP er berørt av en feil som kan føre til ødelagte meldinger. For å løse problemet kan du bytte til SMTP, deaktivere alternativet mail.add_x_header i php.ini, bytte til MacOS eller Linux eller oppgradere PHP til versjon 7.0.17+ eller 7.1.3+.';
$PHPMAILER_LANG['connect_host'] = 'SMTP-feil: Kunne ikke koble til SMTP-vert.';
$PHPMAILER_LANG['data_not_accepted'] = 'SMTP-feil: data ikke akseptert.';
$PHPMAILER_LANG['empty_message'] = 'Meldingsinnholdet er tomt';
$PHPMAILER_LANG['empty_message'] = 'Meldingstekst mangler';
$PHPMAILER_LANG['encoding'] = 'Ukjent koding: ';
$PHPMAILER_LANG['execute'] = 'Kunne ikke utføres: ';
$PHPMAILER_LANG['extension_missing'] = 'Utvidelse mangler: ';
$PHPMAILER_LANG['file_access'] = 'Kunne ikke få tilgang til filen: ';
$PHPMAILER_LANG['file_open'] = 'Feil i fil: Kunne ikke åpne filen: ';
$PHPMAILER_LANG['from_failed'] = 'Følgende avsenderadresse mislyktes: ';
$PHPMAILER_LANG['instantiate'] = 'Kunne ikke starte e-postfunksjonen.';
$PHPMAILER_LANG['from_failed'] = 'Følgende Fra-adresse mislyktes: ';
$PHPMAILER_LANG['instantiate'] = 'Kunne ikke instansiere e-postfunksjonen.';
$PHPMAILER_LANG['invalid_address'] = 'Ugyldig adresse: ';
$PHPMAILER_LANG['invalid_header'] = 'Ugyldig headernavn eller verdi';
$PHPMAILER_LANG['invalid_hostentry'] = 'Ugyldig vertsinngang: ';
@ -32,6 +31,3 @@
$PHPMAILER_LANG['smtp_detail'] = 'Detaljer: ';
$PHPMAILER_LANG['smtp_error'] = 'SMTP-serverfeil: ';
$PHPMAILER_LANG['variable_set'] = 'Kan ikke angi eller tilbakestille variabel: ';
$PHPMAILER_LANG['no_smtputf8'] = 'Serveren støtter ikke SMTPUTF8, som er nødvendig for å sende til Unicode-adresser.';
$PHPMAILER_LANG['imap_recommended'] = 'Det anbefales ikke å bruke forenklet adresseanalyse. Installer PHP IMAP-utvidelsen for full RFC822-analyse.';
$PHPMAILER_LANG['deprecated_argument'] = 'Avviklet argument: ';

View File

@ -4,11 +4,10 @@
* Dutch PHPMailer language file: refer to PHPMailer.php for definitive list.
* @package PHPMailer
* @author Tuxion <team@tuxion.nl>
* @author Robin van der Vliet <info@robinvandervliet.com>
*/
$PHPMAILER_LANG['authenticate'] = 'SMTP-fout: authenticatie mislukt.';
$PHPMAILER_LANG['buggy_php'] = 'PHP-versie gedetecteerd die onderhevig is aan een bug die kan resulteren in gecorrumpeerde berichten. Om dit te voorkomen, gebruik SMTP voor het verzenden van berichten, zet de optie mail.add_x_header in uw php.ini uit, gebruik MacOS of Linux, of pas de gebruikte PHP-versie aan naar versie 7.0.17+ or 7.1.3+.';
$PHPMAILER_LANG['buggy_php'] = 'PHP versie gededecteerd die onderhavig is aan een bug die kan resulteren in gecorrumpeerde berichten. Om dit te voorkomen, gebruik SMTP voor het verzenden van berichten, zet de mail.add_x_header optie in uw php.ini file uit, gebruik MacOS of Linux, of pas de gebruikte PHP versie aan naar versie 7.0.17+ or 7.1.3+.';
$PHPMAILER_LANG['connect_host'] = 'SMTP-fout: kon niet verbinden met SMTP-host.';
$PHPMAILER_LANG['data_not_accepted'] = 'SMTP-fout: data niet geaccepteerd.';
$PHPMAILER_LANG['empty_message'] = 'Berichttekst is leeg';
@ -17,22 +16,19 @@ $PHPMAILER_LANG['execute'] = 'Kon niet uitvoeren: ';
$PHPMAILER_LANG['extension_missing'] = 'Extensie afwezig: ';
$PHPMAILER_LANG['file_access'] = 'Kreeg geen toegang tot bestand: ';
$PHPMAILER_LANG['file_open'] = 'Bestandsfout: kon bestand niet openen: ';
$PHPMAILER_LANG['from_failed'] = 'Het volgende afzenderadres is mislukt: ';
$PHPMAILER_LANG['from_failed'] = 'Het volgende afzendersadres is mislukt: ';
$PHPMAILER_LANG['instantiate'] = 'Kon mailfunctie niet initialiseren.';
$PHPMAILER_LANG['invalid_address'] = 'Ongeldig adres: ';
$PHPMAILER_LANG['invalid_header'] = 'Ongeldige headernaam of -waarde';
$PHPMAILER_LANG['invalid_header'] = 'Ongeldige header naam of waarde';
$PHPMAILER_LANG['invalid_hostentry'] = 'Ongeldige hostentry: ';
$PHPMAILER_LANG['invalid_host'] = 'Ongeldige host: ';
$PHPMAILER_LANG['mailer_not_supported'] = ' mailer wordt niet ondersteund.';
$PHPMAILER_LANG['provide_address'] = 'Er moet minstens één ontvanger worden opgegeven.';
$PHPMAILER_LANG['recipients_failed'] = 'SMTP-fout: de volgende ontvangers zijn mislukt: ';
$PHPMAILER_LANG['signing'] = 'Signeerfout: ';
$PHPMAILER_LANG['smtp_code'] = 'SMTP-code: ';
$PHPMAILER_LANG['smtp_code_ex'] = 'Aanvullende SMTP-informatie: ';
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP-verbinding mislukt.';
$PHPMAILER_LANG['smtp_code'] = 'SMTP code: ';
$PHPMAILER_LANG['smtp_code_ex'] = 'Aanvullende SMTP informatie: ';
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Verbinding mislukt.';
$PHPMAILER_LANG['smtp_detail'] = 'Detail: ';
$PHPMAILER_LANG['smtp_error'] = 'SMTP-serverfout: ';
$PHPMAILER_LANG['variable_set'] = 'Kan de volgende variabele niet instellen of herstellen: ';
$PHPMAILER_LANG['no_smtputf8'] = 'De server ondersteunt geen SMTPUTF8 dat nodig is om naar Unicode-adressen te sturen.';
$PHPMAILER_LANG['imap_recommended'] = 'Het gebruik van de vereenvoudigde adresparser is niet aanbevolen. Installeer de IMAP-extensie voor PHP voor volledige RFC822-ondersteuning.';
$PHPMAILER_LANG['deprecated_argument'] = 'Verouderd argument: ';
$PHPMAILER_LANG['variable_set'] = 'Kan de volgende variabele niet instellen of resetten: ';

View File

@ -5,29 +5,29 @@
* @package PHPMailer
*/
$PHPMAILER_LANG['authenticate'] = 'Błąd SMTP: nie udało się przeprowadzić uwierzytelnienia.';
$PHPMAILER_LANG['buggy_php'] = 'Używana wersja PHP zawiera błąd, który może powodować uszkodzenie wiadomości. Aby temu zapobiec, użyj wysyłki przez SMTP, wyłącz opcję mail.add_x_header w php.ini, przejdź na macOS lub Linux, lub zaktualizuj PHP do wersji 7.0.17+ albo 7.1.3+.';
$PHPMAILER_LANG['connect_host'] = 'Błąd SMTP: nie udało się połączyć z serwerem (hostem).';
$PHPMAILER_LANG['data_not_accepted'] = 'Błąd SMTP: dane wiadomości nie zostały przyjęte przez serwer.';
$PHPMAILER_LANG['empty_message'] = 'Nie można wysłać pustej wiadomości.';
$PHPMAILER_LANG['encoding'] = 'Nieobsługiwane kodowanie znaków: ';
$PHPMAILER_LANG['execute'] = 'Nie udało się uruchomić polecenia: ';
$PHPMAILER_LANG['extension_missing'] = 'Brak wymaganego rozszerzenia PHP: ';
$PHPMAILER_LANG['authenticate'] = 'Błąd SMTP: Nie można przeprowadzić uwierzytelnienia.';
$PHPMAILER_LANG['buggy_php'] = 'Twoja wersja PHP zawiera błąd, który może powodować uszkodzenie wiadomości. Aby go naprawić, przełącz się na wysyłanie za pomocą SMTP, wyłącz opcję mail.add_x_header w php.ini, przełącz się na MacOS lub Linux lub zaktualizuj PHP do wersji 7.0.17+ lub 7.1.3+.';
$PHPMAILER_LANG['connect_host'] = 'Błąd SMTP: Nie można połączyć się z wybranym hostem.';
$PHPMAILER_LANG['data_not_accepted'] = 'Błąd SMTP: Dane nie zostały przyjęte.';
$PHPMAILER_LANG['empty_message'] = 'Wiadomość jest pusta.';
$PHPMAILER_LANG['encoding'] = 'Błędny sposób kodowania znaków: ';
$PHPMAILER_LANG['execute'] = 'Nie można uruchomić: ';
$PHPMAILER_LANG['extension_missing'] = 'Brakujące rozszerzenie: ';
$PHPMAILER_LANG['file_access'] = 'Brak dostępu do pliku: ';
$PHPMAILER_LANG['file_open'] = 'Nie udało się otworzyć pliku: ';
$PHPMAILER_LANG['from_failed'] = 'Nieprawidłowy adres nadawcy: ';
$PHPMAILER_LANG['instantiate'] = 'Nie można zainicjować funkcji mail(). Sprawdź konfigurację serwera.';
$PHPMAILER_LANG['invalid_address'] = 'Nie można wysłać wiadomości. Nieprawidłowy adres odbiorcy: ';
$PHPMAILER_LANG['invalid_header'] = 'Nieprawidłowa nazwa lub wartość nagłówka.';
$PHPMAILER_LANG['file_open'] = 'Nie można otworzyć pliku: ';
$PHPMAILER_LANG['from_failed'] = 'Następujący adres nadawcy jest nieprawidłowy lub nie istnieje: ';
$PHPMAILER_LANG['instantiate'] = 'Nie można wywołać funkcji mail(). Sprawdź konfigurację serwera.';
$PHPMAILER_LANG['invalid_address'] = 'Nie można wysłać wiadomości, ' . 'następujący adres odbiorcy jest nieprawidłowy lub nie istnieje: ';
$PHPMAILER_LANG['invalid_header'] = 'Nieprawidłowa nazwa lub wartość nagłówka';
$PHPMAILER_LANG['invalid_hostentry'] = 'Nieprawidłowy wpis hosta: ';
$PHPMAILER_LANG['invalid_host'] = 'Nieprawidłowa nazwa hosta: ';
$PHPMAILER_LANG['provide_address'] = 'Musisz podać co najmniej jeden prawidłowy adres e-mail odbiorcy.';
$PHPMAILER_LANG['invalid_host'] = 'Nieprawidłowy host: ';
$PHPMAILER_LANG['provide_address'] = 'Należy podać prawidłowy adres email odbiorcy.';
$PHPMAILER_LANG['mailer_not_supported'] = 'Wybrana metoda wysyłki wiadomości nie jest obsługiwana.';
$PHPMAILER_LANG['recipients_failed'] = 'Błąd SMTP: nie udało się wysłać do następujących odbiorców: ';
$PHPMAILER_LANG['signing'] = 'Błąd podpisywania wiadomości cyfrowo: ';
$PHPMAILER_LANG['smtp_code'] = 'Kod odpowiedzi SMTP: ';
$PHPMAILER_LANG['smtp_code_ex'] = 'Dodatkowe informacje serwera SMTP: ';
$PHPMAILER_LANG['smtp_connect_failed'] = 'Nie udało się nawiązać połączenia za pomocą SMTP Connect().';
$PHPMAILER_LANG['smtp_detail'] = 'Szczegóły błędu: ';
$PHPMAILER_LANG['smtp_error'] = 'Błąd serwera SMTP: ';
$PHPMAILER_LANG['recipients_failed'] = 'Błąd SMTP: Następujący odbiorcy są nieprawidłowi lub nie istnieją: ';
$PHPMAILER_LANG['signing'] = 'Błąd podpisywania wiadomości: ';
$PHPMAILER_LANG['smtp_code'] = 'Kod SMTP: ';
$PHPMAILER_LANG['smtp_code_ex'] = 'Dodatkowe informacje SMTP: ';
$PHPMAILER_LANG['smtp_connect_failed'] = 'Wywołanie funkcji SMTP Connect() zostało zakończone niepowodzeniem.';
$PHPMAILER_LANG['smtp_detail'] = 'Szczegóły: ';
$PHPMAILER_LANG['smtp_error'] = 'Błąd SMTP: ';
$PHPMAILER_LANG['variable_set'] = 'Nie można ustawić lub zmodyfikować zmiennej: ';

View File

@ -27,26 +27,16 @@
<exclude name="PSR2.Methods.MethodDeclaration.Underscore"/>
<exclude name="PSR12.Properties.ConstantVisibility.NotFound"/>
</rule>
<rule ref="PHPCompatibility"/>
<!--
#############################################################################
SELECTIVE EXCLUSIONS
Exclude specific files for specific sniffs and/or exclude sub-groups in sniffs.
#############################################################################
-->
<rule ref="PHPCompatibility">
<exclude name="PHPCompatibility.Constants.NewConstants.stream_crypto_method_tlsv1_1_clientFound"/>
<exclude name="PHPCompatibility.Constants.NewConstants.stream_crypto_method_tlsv1_2_clientFound"/>
<exclude name="PHPCompatibility.Constants.RemovedConstants.intl_idna_variant_2003Deprecated"/>
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.random_bytesFound"/>
<exclude name="PHPCompatibility.IniDirectives.RemovedIniDirectives.mbstring_func_overloadDeprecated"/>
<exclude name="PHPCompatibility.ParameterValues.NewIDNVariantDefault.NotSet"/>
</rule>
<rule ref="Generic.Files.LineLength.TooLong">
<exclude-pattern>*/language/phpmailer\.lang*\.php$</exclude-pattern>
</rule>
<!-- Excludes related to linting ignore comment for one specific test file. -->
<rule ref="PSR12.Files.OpenTag.NotAlone">
<exclude-pattern>*/test/Fixtures/LocalizationTest/phpmailer.lang-yz\.php</exclude-pattern>
</rule>
<rule ref="PSR12.Files.FileHeader.SpacingAfterBlock">
<exclude-pattern>*/test/Fixtures/LocalizationTest/phpmailer.lang-yz\.php</exclude-pattern>
</rule>
</ruleset>

View File

@ -561,9 +561,9 @@ class PHPMailer
* string $body the email body
* string $from email address of sender
* string $extra extra information of possible use
* 'smtp_transaction_id' => last smtp transaction id
* "smtp_transaction_id' => last smtp transaction id
*
* @var callable|callable-string
* @var string
*/
public $action_function = '';
@ -711,7 +711,7 @@ class PHPMailer
*
* @var array
*/
protected static $language = [];
protected $language = [];
/**
* The number of errors encountered.
@ -768,7 +768,7 @@ class PHPMailer
*
* @var string
*/
const VERSION = '7.0.2';
const VERSION = '6.10.0';
/**
* Error severity: message only, continue processing.
@ -876,7 +876,6 @@ class PHPMailer
private function mailPassthru($to, $subject, $body, $header, $params)
{
//Check overloading of mail function to avoid double-encoding
// phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.mbstring_func_overloadDeprecatedRemoved
if ((int)ini_get('mbstring.func_overload') & 1) {
$subject = $this->secureHeader($subject);
} else {
@ -988,54 +987,6 @@ class PHPMailer
$this->Mailer = 'mail';
}
/**
* Extract sendmail path and parse to deal with known parameters.
*
* @param string $sendmailPath The sendmail path as set in php.ini
*
* @return string The sendmail path without the known parameters
*/
private function parseSendmailPath($sendmailPath)
{
$sendmailPath = trim((string)$sendmailPath);
if ($sendmailPath === '') {
return $sendmailPath;
}
$parts = preg_split('/\s+/', $sendmailPath);
if (empty($parts)) {
return $sendmailPath;
}
$command = array_shift($parts);
$remainder = [];
// Parse only -t, -i, -oi and -f parameters.
for ($i = 0; $i < count($parts); ++$i) {
$part = $parts[$i];
if (preg_match('/^-(i|oi|t)$/', $part, $matches)) {
continue;
}
if (preg_match('/^-f(.*)$/', $part, $matches)) {
$address = $matches[1];
if ($address === '' && isset($parts[$i + 1]) && strpos($parts[$i + 1], '-') !== 0) {
$address = $parts[++$i];
}
$this->Sender = $address;
continue;
}
$remainder[] = $part;
}
// The params that are not parsed are added back to the command.
if (!empty($remainder)) {
$command .= ' ' . implode(' ', $remainder);
}
return $command;
}
/**
* Send messages using $Sendmail.
*/
@ -1044,9 +995,10 @@ class PHPMailer
$ini_sendmail_path = ini_get('sendmail_path');
if (false === stripos($ini_sendmail_path, 'sendmail')) {
$ini_sendmail_path = '/usr/sbin/sendmail';
$this->Sendmail = '/usr/sbin/sendmail';
} else {
$this->Sendmail = $ini_sendmail_path;
}
$this->Sendmail = $this->parseSendmailPath($ini_sendmail_path);
$this->Mailer = 'sendmail';
}
@ -1058,9 +1010,10 @@ class PHPMailer
$ini_sendmail_path = ini_get('sendmail_path');
if (false === stripos($ini_sendmail_path, 'qmail')) {
$ini_sendmail_path = '/var/qmail/bin/qmail-inject';
$this->Sendmail = '/var/qmail/bin/qmail-inject';
} else {
$this->Sendmail = $ini_sendmail_path;
}
$this->Sendmail = $this->parseSendmailPath($ini_sendmail_path);
$this->Mailer = 'qmail';
}
@ -1149,7 +1102,7 @@ class PHPMailer
//At-sign is missing.
$error_message = sprintf(
'%s (%s): %s',
self::lang('invalid_address'),
$this->lang('invalid_address'),
$kind,
$address
);
@ -1234,7 +1187,7 @@ class PHPMailer
if (!in_array($kind, ['to', 'cc', 'bcc', 'Reply-To'])) {
$error_message = sprintf(
'%s: %s',
self::lang('Invalid recipient kind'),
$this->lang('Invalid recipient kind'),
$kind
);
$this->setError($error_message);
@ -1248,7 +1201,7 @@ class PHPMailer
if (!static::validateAddress($address)) {
$error_message = sprintf(
'%s (%s): %s',
self::lang('invalid_address'),
$this->lang('invalid_address'),
$kind,
$address
);
@ -1267,16 +1220,12 @@ class PHPMailer
return true;
}
} else {
foreach ($this->ReplyTo as $replyTo) {
if (0 === strcasecmp($replyTo[0], $address)) {
return false;
}
}
$this->ReplyTo[] = [$address, $name];
} elseif (!array_key_exists(strtolower($address), $this->ReplyTo)) {
$this->ReplyTo[strtolower($address)] = [$address, $name];
return true;
}
return false;
}
@ -1289,38 +1238,38 @@ class PHPMailer
* @see https://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
*
* @param string $addrstr The address list string
* @param null $useimap Unused. Argument has been deprecated in PHPMailer 6.11.0.
* Previously this argument determined whether to use
* the IMAP extension to parse the list and accepted a boolean value.
* @param bool $useimap Whether to use the IMAP extension to parse the list
* @param string $charset The charset to use when decoding the address list string.
*
* @return array
*/
public static function parseAddresses($addrstr, $useimap = null, $charset = self::CHARSET_ISO88591)
public static function parseAddresses($addrstr, $useimap = true, $charset = self::CHARSET_ISO88591)
{
if ($useimap !== null) {
trigger_error(self::lang('deprecated_argument') . '$useimap', E_USER_DEPRECATED);
}
$addresses = [];
if (function_exists('imap_rfc822_parse_adrlist')) {
if ($useimap && function_exists('imap_rfc822_parse_adrlist')) {
//Use this built-in parser if it's available
// phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.imap_rfc822_parse_adrlistRemoved -- wrapped in function_exists()
$list = imap_rfc822_parse_adrlist($addrstr, '');
// Clear any potential IMAP errors to get rid of notices being thrown at end of script.
// phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.imap_errorsRemoved -- wrapped in function_exists()
imap_errors();
foreach ($list as $address) {
if (
'.SYNTAX-ERROR.' !== $address->host &&
static::validateAddress($address->mailbox . '@' . $address->host)
) {
//Decode the name part if it's present and maybe encoded
//Decode the name part if it's present and encoded
if (
property_exists($address, 'personal')
&& is_string($address->personal)
&& $address->personal !== ''
property_exists($address, 'personal') &&
//Check for a Mbstring constant rather than using extension_loaded, which is sometimes disabled
defined('MB_CASE_UPPER') &&
preg_match('/^=\?.*\?=$/s', $address->personal)
) {
$address->personal = static::decodeHeader($address->personal, $charset);
$origCharset = mb_internal_encoding();
mb_internal_encoding($charset);
//Undo any RFC2047-encoded spaces-as-underscores
$address->personal = str_replace('_', '=20', $address->personal);
//Decode the name
$address->personal = mb_decode_mimeheader($address->personal);
mb_internal_encoding($origCharset);
}
$addresses[] = [
@ -1331,51 +1280,40 @@ class PHPMailer
}
} else {
//Use this simpler parser
$addresses = static::parseSimplerAddresses($addrstr, $charset);
}
return $addresses;
}
/**
* Parse a string containing one or more RFC822-style comma-separated email addresses
* with the form "display name <address>" into an array of name/address pairs.
* Uses a simpler parser that does not require the IMAP extension but doesnt support
* the full RFC822 spec. For full RFC822 support, use the PHP IMAP extension.
*
* @param string $addrstr The address list string
* @param string $charset The charset to use when decoding the address list string.
*
* @return array
*/
protected static function parseSimplerAddresses($addrstr, $charset)
{
// Emit a runtime notice to recommend using the IMAP extension for full RFC822 parsing
trigger_error(self::lang('imap_recommended'), E_USER_NOTICE);
$addresses = [];
$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 (static::validateAddress($address)) {
$addresses[] = [
'name' => '',
'address' => $address,
];
}
} else {
$parsed = static::parseEmailString($address);
$email = $parsed['email'];
if (static::validateAddress($email)) {
$name = static::decodeHeader($parsed['name'], $charset);
$addresses[] = [
//Remove any surrounding quotes and spaces from the name
'name' => trim($name, '\'" '),
'address' => $email,
];
$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 (static::validateAddress($address)) {
$addresses[] = [
'name' => '',
'address' => $address,
];
}
} else {
list($name, $email) = explode('<', $address);
$email = trim(str_replace('>', '', $email));
$name = trim($name);
if (static::validateAddress($email)) {
//Check for a Mbstring constant rather than using extension_loaded, which is sometimes disabled
//If this name is encoded, decode it
if (defined('MB_CASE_UPPER') && preg_match('/^=\?.*\?=$/s', $name)) {
$origCharset = mb_internal_encoding();
mb_internal_encoding($charset);
//Undo any RFC2047-encoded spaces-as-underscores
$name = str_replace('_', '=20', $name);
//Decode the name
$name = mb_decode_mimeheader($name);
mb_internal_encoding($origCharset);
}
$addresses[] = [
//Remove any surrounding quotes and spaces from the name
'name' => trim($name, '\'" '),
'address' => $email,
];
}
}
}
}
@ -1383,42 +1321,6 @@ class PHPMailer
return $addresses;
}
/**
* Parse a string containing an email address with an optional name
* and divide it into a name and email address.
*
* @param string $input The email with name.
*
* @return array{name: string, email: string}
*/
private static function parseEmailString($input)
{
$input = trim((string)$input);
if ($input === '') {
return ['name' => '', 'email' => ''];
}
$pattern = '/^\s*(?:(?:"([^"]*)"|\'([^\']*)\'|([^<]*?))\s*)?<\s*([^>]+)\s*>\s*$/';
if (preg_match($pattern, $input, $matches)) {
$name = '';
// Double quotes including special scenarios.
if (isset($matches[1]) && $matches[1] !== '') {
$name = $matches[1];
// Single quotes including special scenarios.
} elseif (isset($matches[2]) && $matches[2] !== '') {
$name = $matches[2];
// Simplest scenario, name and email are in the format "Name <email>".
} elseif (isset($matches[3])) {
$name = trim($matches[3]);
}
return ['name' => $name, 'email' => trim($matches[4])];
}
return ['name' => '', 'email' => $input];
}
/**
* Set the From and FromName properties.
*
@ -1432,10 +1334,6 @@ class PHPMailer
*/
public function setFrom($address, $name = '', $auto = true)
{
if (is_null($name)) {
//Helps avoid a deprecation warning in the preg_replace() below
$name = '';
}
$address = trim((string)$address);
$name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
//Don't validate now addresses with IDN. Will be done in send().
@ -1447,7 +1345,7 @@ class PHPMailer
) {
$error_message = sprintf(
'%s (From): %s',
self::lang('invalid_address'),
$this->lang('invalid_address'),
$address
);
$this->setError($error_message);
@ -1634,11 +1532,9 @@ class PHPMailer
);
} elseif (defined('INTL_IDNA_VARIANT_2003')) {
//Fall back to this old, deprecated/removed encoding
// phpcs:ignore PHPCompatibility.Constants.RemovedConstants.intl_idna_variant_2003DeprecatedRemoved
$punycode = idn_to_ascii($domain, $errorcode, \INTL_IDNA_VARIANT_2003);
} else {
//Fall back to a default we don't know about
// phpcs:ignore PHPCompatibility.ParameterValues.NewIDNVariantDefault.NotSet
$punycode = idn_to_ascii($domain, $errorcode);
}
if (false !== $punycode) {
@ -1705,7 +1601,7 @@ class PHPMailer
&& ini_get('mail.add_x_header') === '1'
&& stripos(PHP_OS, 'WIN') === 0
) {
trigger_error(self::lang('buggy_php'), E_USER_WARNING);
trigger_error($this->lang('buggy_php'), E_USER_WARNING);
}
try {
@ -1735,7 +1631,7 @@ class PHPMailer
call_user_func_array([$this, 'addAnAddress'], $params);
}
if (count($this->to) + count($this->cc) + count($this->bcc) < 1) {
throw new Exception(self::lang('provide_address'), self::STOP_CRITICAL);
throw new Exception($this->lang('provide_address'), self::STOP_CRITICAL);
}
//Validate From, Sender, and ConfirmReadingTo addresses
@ -1752,7 +1648,7 @@ class PHPMailer
if (!static::validateAddress($this->{$address_kind})) {
$error_message = sprintf(
'%s (%s): %s',
self::lang('invalid_address'),
$this->lang('invalid_address'),
$address_kind,
$this->{$address_kind}
);
@ -1774,7 +1670,7 @@ class PHPMailer
$this->setMessageType();
//Refuse to send an empty message unless we are specifically allowing it
if (!$this->AllowEmpty && empty($this->Body)) {
throw new Exception(self::lang('empty_message'), self::STOP_CRITICAL);
throw new Exception($this->lang('empty_message'), self::STOP_CRITICAL);
}
//Trim subject consistently
@ -1906,27 +1802,23 @@ class PHPMailer
//PHP config has a sender address we can use
$this->Sender = ini_get('sendmail_from');
}
$sendmailArgs = [];
// CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
// Also don't add the -f automatically unless it has been set either via Sender
// or sendmail_path. Otherwise it can introduce new problems.
// @see http://github.com/PHPMailer/PHPMailer/issues/2298
//CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
if (!empty($this->Sender) && static::validateAddress($this->Sender) && self::isShellSafe($this->Sender)) {
$sendmailArgs[] = '-f' . $this->Sender;
if ($this->Mailer === 'qmail') {
$sendmailFmt = '%s -f%s';
} else {
$sendmailFmt = '%s -oi -f%s -t';
}
} else {
//allow sendmail to choose a default envelope sender. It may
//seem preferable to force it to use the From header as with
//SMTP, but that introduces new problems (see
//<https://github.com/PHPMailer/PHPMailer/issues/2298>), and
//it has historically worked this way.
$sendmailFmt = '%s -oi -t';
}
// Qmail doesn't accept all the sendmail parameters
// @see https://github.com/PHPMailer/PHPMailer/issues/3189
if ($this->Mailer !== 'qmail') {
$sendmailArgs[] = '-i';
$sendmailArgs[] = '-t';
}
$resultArgs = (empty($sendmailArgs) ? '' : ' ' . implode(' ', $sendmailArgs));
$sendmail = trim(escapeshellcmd($this->Sendmail) . $resultArgs);
$sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender);
$this->edebug('Sendmail path: ' . $this->Sendmail);
$this->edebug('Sendmail command: ' . $sendmail);
$this->edebug('Envelope sender: ' . $this->Sender);
@ -1936,35 +1828,33 @@ class PHPMailer
foreach ($this->SingleToArray as $toAddr) {
$mail = @popen($sendmail, 'w');
if (!$mail) {
throw new Exception(self::lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
}
$this->edebug("To: {$toAddr}");
fwrite($mail, 'To: ' . $toAddr . "\n");
fwrite($mail, $header);
fwrite($mail, $body);
$result = pclose($mail);
$addrinfo = static::parseAddresses($toAddr, null, $this->CharSet);
foreach ($addrinfo as $addr) {
$this->doCallback(
($result === 0),
[[$addr['address'], $addr['name']]],
$this->cc,
$this->bcc,
$this->Subject,
$body,
$this->From,
[]
);
}
$addrinfo = static::parseAddresses($toAddr, true, $this->CharSet);
$this->doCallback(
($result === 0),
[[$addrinfo['address'], $addrinfo['name']]],
$this->cc,
$this->bcc,
$this->Subject,
$body,
$this->From,
[]
);
$this->edebug("Result: " . ($result === 0 ? 'true' : 'false'));
if (0 !== $result) {
throw new Exception(self::lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
}
}
} else {
$mail = @popen($sendmail, 'w');
if (!$mail) {
throw new Exception(self::lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
}
fwrite($mail, $header);
fwrite($mail, $body);
@ -1981,7 +1871,7 @@ class PHPMailer
);
$this->edebug("Result: " . ($result === 0 ? 'true' : 'false'));
if (0 !== $result) {
throw new Exception(self::lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
}
}
@ -2110,8 +2000,7 @@ class PHPMailer
$this->Sender = ini_get('sendmail_from');
}
if (!empty($this->Sender) && static::validateAddress($this->Sender)) {
$phpmailer_path = ini_get('sendmail_path');
if (self::isShellSafe($this->Sender) && strpos($phpmailer_path, ' -f') === false) {
if (self::isShellSafe($this->Sender)) {
$params = sprintf('-f%s', $this->Sender);
}
$old_from = ini_get('sendmail_from');
@ -2121,19 +2010,17 @@ class PHPMailer
if ($this->SingleTo && count($toArr) > 1) {
foreach ($toArr as $toAddr) {
$result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
$addrinfo = static::parseAddresses($toAddr, null, $this->CharSet);
foreach ($addrinfo as $addr) {
$this->doCallback(
$result,
[[$addr['address'], $addr['name']]],
$this->cc,
$this->bcc,
$this->Subject,
$body,
$this->From,
[]
);
}
$addrinfo = static::parseAddresses($toAddr, true, $this->CharSet);
$this->doCallback(
$result,
[[$addrinfo['address'], $addrinfo['name']]],
$this->cc,
$this->bcc,
$this->Subject,
$body,
$this->From,
[]
);
}
} else {
$result = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
@ -2143,7 +2030,7 @@ class PHPMailer
ini_set('sendmail_from', $old_from);
}
if (!$result) {
throw new Exception(self::lang('instantiate'), self::STOP_CRITICAL);
throw new Exception($this->lang('instantiate'), self::STOP_CRITICAL);
}
return true;
@ -2229,12 +2116,12 @@ class PHPMailer
$header = static::stripTrailingWSP($header) . static::$LE . static::$LE;
$bad_rcpt = [];
if (!$this->smtpConnect($this->SMTPOptions)) {
throw new Exception(self::lang('smtp_connect_failed'), self::STOP_CRITICAL);
throw new Exception($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
}
//If we have recipient addresses that need Unicode support,
//but the server doesn't support it, stop here
if ($this->UseSMTPUTF8 && !$this->smtp->getServerExt('SMTPUTF8')) {
throw new Exception(self::lang('no_smtputf8'), self::STOP_CRITICAL);
throw new Exception($this->lang('no_smtputf8'), self::STOP_CRITICAL);
}
//Sender already validated in preSend()
if ('' === $this->Sender) {
@ -2246,7 +2133,7 @@ class PHPMailer
$this->smtp->xclient($this->SMTPXClient);
}
if (!$this->smtp->mail($smtp_from)) {
$this->setError(self::lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
$this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
throw new Exception($this->ErrorInfo, self::STOP_CRITICAL);
}
@ -2268,7 +2155,7 @@ class PHPMailer
//Only send the DATA command if we have viable recipients
if ((count($this->all_recipients) > count($bad_rcpt)) && !$this->smtp->data($header . $body)) {
throw new Exception(self::lang('data_not_accepted'), self::STOP_CRITICAL);
throw new Exception($this->lang('data_not_accepted'), self::STOP_CRITICAL);
}
$smtp_transaction_id = $this->smtp->getLastTransactionID();
@ -2299,7 +2186,7 @@ class PHPMailer
foreach ($bad_rcpt as $bad) {
$errstr .= $bad['to'] . ': ' . $bad['error'];
}
throw new Exception(self::lang('recipients_failed') . $errstr, self::STOP_CONTINUE);
throw new Exception($this->lang('recipients_failed') . $errstr, self::STOP_CONTINUE);
}
return true;
@ -2353,7 +2240,7 @@ class PHPMailer
$hostinfo
)
) {
$this->edebug(self::lang('invalid_hostentry') . ' ' . trim($hostentry));
$this->edebug($this->lang('invalid_hostentry') . ' ' . trim($hostentry));
//Not a valid host entry
continue;
}
@ -2365,7 +2252,7 @@ class PHPMailer
//Check the host name is a valid name or IP address before trying to use it
if (!static::isValidHost($hostinfo[2])) {
$this->edebug(self::lang('invalid_host') . ' ' . $hostinfo[2]);
$this->edebug($this->lang('invalid_host') . ' ' . $hostinfo[2]);
continue;
}
$prefix = '';
@ -2385,7 +2272,7 @@ class PHPMailer
if (static::ENCRYPTION_STARTTLS === $secure || static::ENCRYPTION_SMTPS === $secure) {
//Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled
if (!$sslext) {
throw new Exception(self::lang('extension_missing') . 'openssl', self::STOP_CRITICAL);
throw new Exception($this->lang('extension_missing') . 'openssl', self::STOP_CRITICAL);
}
}
$host = $hostinfo[2];
@ -2437,7 +2324,7 @@ class PHPMailer
$this->oauth
)
) {
throw new Exception(self::lang('authenticate'));
throw new Exception($this->lang('authenticate'));
}
return true;
@ -2487,7 +2374,7 @@ class PHPMailer
*
* @return bool Returns true if the requested language was loaded, false otherwise.
*/
public static function setLanguage($langcode = 'en', $lang_path = '')
public function setLanguage($langcode = 'en', $lang_path = '')
{
//Backwards compatibility for renamed language codes
$renamed_langcodes = [
@ -2536,9 +2423,6 @@ class PHPMailer
'smtp_error' => 'SMTP server error: ',
'variable_set' => 'Cannot set or reset variable: ',
'no_smtputf8' => 'Server does not support SMTPUTF8 needed to send to Unicode addresses',
'imap_recommended' => 'Using simplified address parser is not recommended. ' .
'Install the PHP IMAP extension for full RFC822 parsing.',
'deprecated_argument' => 'Deprecated Argument: ',
];
if (empty($lang_path)) {
//Calculate an absolute path so it can work if CWD is not here
@ -2605,7 +2489,7 @@ class PHPMailer
}
}
}
self::$language = $PHPMAILER_LANG;
$this->language = $PHPMAILER_LANG;
return $foundlang; //Returns false if language not found
}
@ -2617,11 +2501,11 @@ class PHPMailer
*/
public function getTranslations()
{
if (empty(self::$language)) {
self::setLanguage(); // Set the default language.
if (empty($this->language)) {
$this->setLanguage(); // Set the default language.
}
return self::$language;
return $this->language;
}
/**
@ -3012,7 +2896,6 @@ class PHPMailer
$bytes = '';
if (function_exists('random_bytes')) {
try {
// phpcs:ignore PHPCompatibility.FunctionUse.NewFunctions.random_bytesFound -- Wrapped in function_exists.
$bytes = random_bytes($len);
} catch (\Exception $e) {
//Do nothing
@ -3045,6 +2928,10 @@ class PHPMailer
//Create unique IDs and preset boundaries
$this->setBoundaries();
if ($this->sign_key_file) {
$body .= $this->getMailMIME() . static::$LE;
}
$this->setWordWrap();
$bodyEncoding = $this->Encoding;
@ -3076,12 +2963,6 @@ class PHPMailer
if (static::ENCODING_BASE64 !== $altBodyEncoding && static::hasLineLongerThanMax($this->AltBody)) {
$altBodyEncoding = static::ENCODING_QUOTED_PRINTABLE;
}
if ($this->sign_key_file) {
$this->Encoding = $bodyEncoding;
$body .= $this->getMailMIME() . static::$LE;
}
//Use this as a preamble in all multipart message types
$mimepre = '';
switch ($this->message_type) {
@ -3263,12 +3144,12 @@ class PHPMailer
if ($this->isError()) {
$body = '';
if ($this->exceptions) {
throw new Exception(self::lang('empty_message'), self::STOP_CRITICAL);
throw new Exception($this->lang('empty_message'), self::STOP_CRITICAL);
}
} elseif ($this->sign_key_file) {
try {
if (!defined('PKCS7_TEXT')) {
throw new Exception(self::lang('extension_missing') . 'openssl');
throw new Exception($this->lang('extension_missing') . 'openssl');
}
$file = tempnam(sys_get_temp_dir(), 'srcsign');
@ -3306,7 +3187,7 @@ class PHPMailer
$body = $parts[1];
} else {
@unlink($signed);
throw new Exception(self::lang('signing') . openssl_error_string());
throw new Exception($this->lang('signing') . openssl_error_string());
}
} catch (Exception $exc) {
$body = '';
@ -3451,7 +3332,7 @@ class PHPMailer
) {
try {
if (!static::fileIsAccessible($path)) {
throw new Exception(self::lang('file_access') . $path, self::STOP_CONTINUE);
throw new Exception($this->lang('file_access') . $path, self::STOP_CONTINUE);
}
//If a MIME type is not specified, try to work it out from the file name
@ -3464,7 +3345,7 @@ class PHPMailer
$name = $filename;
}
if (!$this->validateEncoding($encoding)) {
throw new Exception(self::lang('encoding') . $encoding);
throw new Exception($this->lang('encoding') . $encoding);
}
$this->attachment[] = [
@ -3625,11 +3506,11 @@ class PHPMailer
{
try {
if (!static::fileIsAccessible($path)) {
throw new Exception(self::lang('file_open') . $path, self::STOP_CONTINUE);
throw new Exception($this->lang('file_open') . $path, self::STOP_CONTINUE);
}
$file_buffer = file_get_contents($path);
if (false === $file_buffer) {
throw new Exception(self::lang('file_open') . $path, self::STOP_CONTINUE);
throw new Exception($this->lang('file_open') . $path, self::STOP_CONTINUE);
}
$file_buffer = $this->encodeString($file_buffer, $encoding);
@ -3682,9 +3563,9 @@ class PHPMailer
$encoded = $this->encodeQP($str);
break;
default:
$this->setError(self::lang('encoding') . $encoding);
$this->setError($this->lang('encoding') . $encoding);
if ($this->exceptions) {
throw new Exception(self::lang('encoding') . $encoding);
throw new Exception($this->lang('encoding') . $encoding);
}
break;
}
@ -3790,42 +3671,6 @@ class PHPMailer
return trim(static::normalizeBreaks($encoded));
}
/**
* Decode an RFC2047-encoded header value
* Attempts multiple strategies so it works even when the mbstring extension is disabled.
*
* @param string $value The header value to decode
* @param string $charset The target charset to convert to, defaults to ISO-8859-1 for BC
*
* @return string The decoded header value
*/
public static function decodeHeader($value, $charset = self::CHARSET_ISO88591)
{
if (!is_string($value) || $value === '') {
return '';
}
// Detect the presence of any RFC2047 encoded-words
$hasEncodedWord = (bool) preg_match('/=\?.*\?=/s', $value);
if ($hasEncodedWord && defined('MB_CASE_UPPER')) {
$origCharset = mb_internal_encoding();
// Always decode to UTF-8 to provide a consistent, modern output encoding.
mb_internal_encoding($charset);
if (PHP_VERSION_ID < 80300) {
// Undo any RFC2047-encoded spaces-as-underscores.
$value = str_replace('_', '=20', $value);
} else {
// PHP 8.3+ already interprets underscores as spaces. Remove additional
// linear whitespace between adjacent encoded words to avoid double spacing.
$value = preg_replace('/(\?=)\s+(=\?)/', '$1$2', $value);
}
// Decode the header value
$value = mb_decode_mimeheader($value);
mb_internal_encoding($origCharset);
}
return $value;
}
/**
* Check if a string contains multi-byte characters.
*
@ -3995,7 +3840,7 @@ class PHPMailer
}
if (!$this->validateEncoding($encoding)) {
throw new Exception(self::lang('encoding') . $encoding);
throw new Exception($this->lang('encoding') . $encoding);
}
//Append to $attachment array
@ -4054,7 +3899,7 @@ class PHPMailer
) {
try {
if (!static::fileIsAccessible($path)) {
throw new Exception(self::lang('file_access') . $path, self::STOP_CONTINUE);
throw new Exception($this->lang('file_access') . $path, self::STOP_CONTINUE);
}
//If a MIME type is not specified, try to work it out from the file name
@ -4063,7 +3908,7 @@ class PHPMailer
}
if (!$this->validateEncoding($encoding)) {
throw new Exception(self::lang('encoding') . $encoding);
throw new Exception($this->lang('encoding') . $encoding);
}
$filename = (string) static::mb_pathinfo($path, PATHINFO_BASENAME);
@ -4129,7 +3974,7 @@ class PHPMailer
}
if (!$this->validateEncoding($encoding)) {
throw new Exception(self::lang('encoding') . $encoding);
throw new Exception($this->lang('encoding') . $encoding);
}
//Append to $attachment array
@ -4386,7 +4231,7 @@ class PHPMailer
}
if (strpbrk($name . $value, "\r\n") !== false) {
if ($this->exceptions) {
throw new Exception(self::lang('invalid_header'));
throw new Exception($this->lang('invalid_header'));
}
return false;
@ -4410,15 +4255,15 @@ class PHPMailer
if ('smtp' === $this->Mailer && null !== $this->smtp) {
$lasterror = $this->smtp->getError();
if (!empty($lasterror['error'])) {
$msg .= ' ' . self::lang('smtp_error') . $lasterror['error'];
$msg .= ' ' . $this->lang('smtp_error') . $lasterror['error'];
if (!empty($lasterror['detail'])) {
$msg .= ' ' . self::lang('smtp_detail') . $lasterror['detail'];
$msg .= ' ' . $this->lang('smtp_detail') . $lasterror['detail'];
}
if (!empty($lasterror['smtp_code'])) {
$msg .= ' ' . self::lang('smtp_code') . $lasterror['smtp_code'];
$msg .= ' ' . $this->lang('smtp_code') . $lasterror['smtp_code'];
}
if (!empty($lasterror['smtp_code_ex'])) {
$msg .= ' ' . self::lang('smtp_code_ex') . $lasterror['smtp_code_ex'];
$msg .= ' ' . $this->lang('smtp_code_ex') . $lasterror['smtp_code_ex'];
}
}
}
@ -4543,21 +4388,21 @@ class PHPMailer
*
* @return string
*/
protected static function lang($key)
protected function lang($key)
{
if (count(self::$language) < 1) {
self::setLanguage(); //Set the default language
if (count($this->language) < 1) {
$this->setLanguage(); //Set the default language
}
if (array_key_exists($key, self::$language)) {
if (array_key_exists($key, $this->language)) {
if ('smtp_connect_failed' === $key) {
//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 self::$language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting';
return $this->language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting';
}
return self::$language[$key];
return $this->language[$key];
}
//Return the key as a fallback
@ -4572,7 +4417,7 @@ class PHPMailer
*/
private function getSmtpErrorMessage($base_key)
{
$message = self::lang($base_key);
$message = $this->lang($base_key);
$error = $this->smtp->getError();
if (!empty($error['error'])) {
$message .= ' ' . $error['error'];
@ -4616,7 +4461,7 @@ class PHPMailer
//Ensure name is not empty, and that neither name nor value contain line breaks
if (empty($name) || strpbrk($name . $value, "\r\n") !== false) {
if ($this->exceptions) {
throw new Exception(self::lang('invalid_header'));
throw new Exception($this->lang('invalid_header'));
}
return false;
@ -4647,10 +4492,10 @@ class PHPMailer
* Converts data-uri images into embedded attachments.
* If you don't want to apply these transformations to your HTML, just set Body and AltBody directly.
*
* @param string $message HTML message string
* @param string $basedir Absolute path to a base directory to prepend to relative paths to images
* @param bool|callable $advanced Whether to use the internal HTML to text converter
* or your own custom converter
* @param string $message HTML message string
* @param string $basedir Absolute path to a base directory to prepend to relative paths to images
* @param bool|callable $advanced Whether to use the internal HTML to text converter
* or your own custom converter
* @return string The transformed message body
*
* @throws Exception
@ -4659,12 +4504,6 @@ class PHPMailer
*/
public function msgHTML($message, $basedir = '', $advanced = false)
{
$cid_domain = 'phpmailer.0';
if (filter_var($this->From, FILTER_VALIDATE_EMAIL)) {
//prepend with a character to create valid RFC822 string in order to validate
$cid_domain = substr($this->From, strrpos($this->From, '@') + 1);
}
preg_match_all('/(?<!-)(src|background)=["\'](.*)["\']/Ui', $message, $images);
if (array_key_exists(2, $images)) {
if (strlen($basedir) > 1 && '/' !== substr($basedir, -1)) {
@ -4686,7 +4525,7 @@ class PHPMailer
}
//Hash the decoded data, not the URL, so that the same data-URI image used in multiple places
//will only be embedded once, even if it used a different encoding
$cid = substr(hash('sha256', $data), 0, 32) . '@' . $cid_domain; //RFC2392 S 2
$cid = substr(hash('sha256', $data), 0, 32) . '@phpmailer.0'; //RFC2392 S 2
if (!$this->cidExists($cid)) {
$this->addStringEmbeddedImage(
@ -4720,7 +4559,7 @@ class PHPMailer
$directory = '';
}
//RFC2392 S 2
$cid = substr(hash('sha256', $url), 0, 32) . '@' . $cid_domain;
$cid = substr(hash('sha256', $url), 0, 32) . '@phpmailer.0';
if (strlen($basedir) > 1 && '/' !== substr($basedir, -1)) {
$basedir .= '/';
}
@ -5015,7 +4854,7 @@ class PHPMailer
return true;
}
$this->setError(self::lang('variable_set') . $name);
$this->setError($this->lang('variable_set') . $name);
return false;
}
@ -5153,7 +4992,7 @@ class PHPMailer
{
if (!defined('PKCS7_TEXT')) {
if ($this->exceptions) {
throw new Exception(self::lang('extension_missing') . 'openssl');
throw new Exception($this->lang('extension_missing') . 'openssl');
}
return '';
@ -5168,14 +5007,12 @@ class PHPMailer
}
if (openssl_sign($signHeader, $signature, $privKey, 'sha256WithRSAEncryption')) {
if (\PHP_MAJOR_VERSION < 8) {
// phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.openssl_pkey_freeDeprecated
openssl_pkey_free($privKey);
}
return base64_encode($signature);
}
if (\PHP_MAJOR_VERSION < 8) {
// phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.openssl_pkey_freeDeprecated
openssl_pkey_free($privKey);
}

View File

@ -45,9 +45,8 @@ class POP3
* The POP3 PHPMailer Version number.
*
* @var string
* @deprecated This constant will be removed in PHPMailer 8.0. Use `PHPMailer::VERSION` instead.
*/
const VERSION = '7.0.2';
const VERSION = '6.10.0';
/**
* Default POP3 port number.

View File

@ -34,9 +34,8 @@ class SMTP
* The PHPMailer SMTP version number.
*
* @var string
* @deprecated This constant will be removed in PHPMailer 8.0. Use `PHPMailer::VERSION` instead.
*/
const VERSION = '7.0.2';
const VERSION = '6.10.0';
/**
* SMTP line break constant.
@ -206,7 +205,6 @@ class SMTP
'Haraka' => '/[\d]{3} Message Queued \((.*)\)/',
'ZoneMTA' => '/[\d]{3} Message queued as (.*)/',
'Mailjet' => '/[\d]{3} OK queued as (.*)/',
'Gsmtp' => '/[\d]{3} 2\.0\.0 OK (.*) - gsmtp/',
];
/**
@ -495,9 +493,7 @@ class SMTP
//PHP 5.6.7 dropped inclusion of TLS 1.1 and 1.2 in STREAM_CRYPTO_METHOD_TLS_CLIENT
//so add them back in manually if we can
if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
// phpcs:ignore PHPCompatibility.Constants.NewConstants.stream_crypto_method_tlsv1_2_clientFound
$crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
// phpcs:ignore PHPCompatibility.Constants.NewConstants.stream_crypto_method_tlsv1_1_clientFound
$crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
}
@ -636,48 +632,11 @@ class SMTP
if (null === $OAuth) {
return false;
}
try {
$oauth = $OAuth->getOauth64();
} catch (\Exception $e) {
// We catch all exceptions and convert them to PHPMailer exceptions to be able to
// handle them correctly later
throw new Exception("SMTP authentication error", 0, $e);
}
/*
* An SMTP command line can have a maximum length of 512 bytes, including the command name,
* so the base64-encoded OAUTH token has a maximum length of:
* 512 - 13 (AUTH XOAUTH2) - 2 (CRLF) = 497 bytes
* If the token is longer than that, the command and the token must be sent separately as described in
* https://www.rfc-editor.org/rfc/rfc4954#section-4
*/
if ($oauth === '') {
//Sending an empty auth token is legitimate, but it must be encoded as '='
//to indicate it's not a 2-part command
if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 =', 235)) {
return false;
}
} elseif (strlen($oauth) <= 497) {
//Authenticate using a token in the initial-response part
if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 ' . $oauth, 235)) {
return false;
}
} else {
//The token is too long, so we need to send it in two parts.
//Send the auth command without a token and expect a 334
if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2', 334)) {
return false;
}
//Send the token
if (!$this->sendCommand('OAuth TOKEN', $oauth, [235, 334])) {
return false;
}
//If the server answers with 334, send an empty line and wait for a 235
if (
substr($this->last_reply, 0, 3) === '334'
&& $this->sendCommand('AUTH End', '', 235)
) {
return false;
}
$oauth = $OAuth->getOauth64();
//Start authentication
if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 ' . $oauth, 235)) {
return false;
}
break;
default:
@ -770,25 +729,6 @@ class SMTP
}
}
private function iterateLines($s)
{
$start = 0;
$length = strlen($s);
for ($i = 0; $i < $length; $i++) {
$c = $s[$i];
if ($c === "\n" || $c === "\r") {
yield substr($s, $start, $i - $start);
if ($c === "\r" && $i + 1 < $length && $s[$i + 1] === "\n") {
$i++;
}
$start = $i + 1;
}
}
yield substr($s, $start);
}
/**
* Send an SMTP DATA command.
* Issues a data command and sends the msg_data to the server,
@ -817,16 +757,15 @@ class SMTP
* NOTE: this does not count towards line-length limit.
*/
//Iterate over lines with normalized line breaks
$lines = $this->iterateLines($msg_data);
//Normalize line breaks before exploding
$lines = explode("\n", str_replace(["\r\n", "\r"], "\n", $msg_data));
/* To distinguish between a complete RFC822 message and a plain message body, we check if the first field
* of the first line (':' separated) does not contain a space then it _should_ be a header, and we will
* process all lines before a blank line as headers.
*/
$first_line = $lines->current();
$field = substr($first_line, 0, strpos($first_line, ':'));
$field = substr($lines[0], 0, strpos($lines[0], ':'));
$in_headers = false;
if (!empty($field) && strpos($field, ' ') === false) {
$in_headers = true;
@ -1370,16 +1309,7 @@ class SMTP
//stream_select returns false when the `select` system call is interrupted
//by an incoming signal, try the select again
if (
stripos($message, 'interrupted system call') !== false ||
(
// on applications with a different locale than english, the message above is not found because
// it's translated. So we also check for the SOCKET_EINTR constant which is defined under
// Windows and UNIX-like platforms (if available on the platform).
defined('SOCKET_EINTR') &&
stripos($message, 'stream_select(): Unable to select [' . SOCKET_EINTR . ']') !== false
)
) {
if (stripos($message, 'interrupted system call') !== false) {
$this->edebug(
'SMTP -> get_lines(): retrying stream_select',
self::DEBUG_LOWLEVEL

View File

@ -1,31 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIUPVCD/ME/tR7lrcNY0eLMignHqywwDQYJKoZIhvcNAQEL
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNTA5MTExOTI4MDdaFw0zNTA5
MDkxOTI4MDdaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEB
AQUAA4ICDwAwggIKAoICAQDHDtSUM73CqVfUt5hhBIbz56ENE746CqgqCqYpKypQ
frCDbcaRWagg9JOy4k9BChB4/B8wZilF9vsmfFoIa0H+LmQWQLN1pVx2tuSWI9rw
CdmTm6cXFZCxleOQMFxzmzV53gK9y2YRxAYL/hm6mcWp6Rblv0SqyxBz+GPJLLrr
cVRIgkktEia7ENA56DWpLoi49xYUwnDN3o+PwtrPGEzwsH/25zhEyS1LlcfRM3pY
W9UGX8HtU1LB94dWoVWNvISFvjicCWhVsuNw1Z0tIko499iEQG+zezbmh++n9a2G
bkCaI6dFZL5pHakmKOTYKyZ1sprE4799KDSTd8hlPfHboC4ClWqIiI6ou3kEpJln
sdsNZP5vPHrDgjuW/oE+zsQjmkaJiWaZphpthyYkR32Xu7HPvtQT4MHfkrs/SFE0
43ml8CqrGSa+IjSjI+HXMwsf0mRmEtK7PcqVLhdSWAGjMNPjJ+er/O+PX3ZAWrbl
GzJfYU5LAk1ES/8uKpB+TjAXDL8xyM0+aP0axEeU57SyTNqbVfimrA250KZ+Q3hk
dpTWlTEjCXhxGHXdiJJwFPyanCNstFuKgNHTbmdRTMKIQ+Wmu5EgUSH2GcRZg9oO
t2veQP3EIc9dIxzijUFETWuBqzi80D6rKJJ1KowJE0rdh7owI/SCHNOYgjSN5a0G
XQIDAQABo1MwUTAdBgNVHQ4EFgQUzSwRCSiJnYQsy99FkcsdWzHJjIwwHwYDVR0j
BBgwFoAUzSwRCSiJnYQsy99FkcsdWzHJjIwwDwYDVR0TAQH/BAUwAwEB/zANBgkq
hkiG9w0BAQsFAAOCAgEAVZApbeRypzpwv2d8B/kPcIRcq5Kot0HhTDr9CNvGqU0G
TwQrVyIVAzi0uX+Ki7flj3+bo1br9xR/ocKbnTbEA3ofCxEbf0KGEjiwvB7tAg22
UeFBxdAZG2IJcwwmY779IHKmjmFgrWGbXTirrN2a3i5TYU/nrTp7yY3GFQFujt5q
hQXBnkEvubS3n9ImdA0ByWCgmYiS08v8HGgsgGs9xVe1idkDkD+5I1imCADvUh7I
0ZksoB/XpdHRaqTRF0h6G2EUXznOG7x04uG4tiHkim1W4IkBBVTLxp6iul9n8GAe
QoZadHGaPIeytwl7A986Qo78WIltxZC+SBjJeQJG7/qHt/MvB8dBXZ49zg1SmHeV
ZtBWdtC0LBGcLoImm9m7DCyA9xMqSKSoOqmzXTlWcKQnPi3MeI5dqfWzuvk9LyLg
71hXXF4EnTgZpHw1ZWJBI47jEfsH2G0c7X46HPYjD4XcDCChNG81d0xQpZMbq5J7
jy6PSbE/iGghEOuiF1NpQsrAnlf0UAzA27bUPyX0NFOmQmAejc8b6NqIljSQE/Xm
MOZlE4RpIa63EzzDo1fas8hhUhtz3loYysHN+nmw4N0BRjVenxatJXiunIbsDkzJ
VeBTrddQlqszd0qOlGCpJM0uhHuVDPntHKmFLo7O32aH2TgvYakpp54Xd+4xIqM=
-----END CERTIFICATE-----

View File

@ -1,52 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQDHDtSUM73CqVfU
t5hhBIbz56ENE746CqgqCqYpKypQfrCDbcaRWagg9JOy4k9BChB4/B8wZilF9vsm
fFoIa0H+LmQWQLN1pVx2tuSWI9rwCdmTm6cXFZCxleOQMFxzmzV53gK9y2YRxAYL
/hm6mcWp6Rblv0SqyxBz+GPJLLrrcVRIgkktEia7ENA56DWpLoi49xYUwnDN3o+P
wtrPGEzwsH/25zhEyS1LlcfRM3pYW9UGX8HtU1LB94dWoVWNvISFvjicCWhVsuNw
1Z0tIko499iEQG+zezbmh++n9a2GbkCaI6dFZL5pHakmKOTYKyZ1sprE4799KDST
d8hlPfHboC4ClWqIiI6ou3kEpJlnsdsNZP5vPHrDgjuW/oE+zsQjmkaJiWaZphpt
hyYkR32Xu7HPvtQT4MHfkrs/SFE043ml8CqrGSa+IjSjI+HXMwsf0mRmEtK7PcqV
LhdSWAGjMNPjJ+er/O+PX3ZAWrblGzJfYU5LAk1ES/8uKpB+TjAXDL8xyM0+aP0a
xEeU57SyTNqbVfimrA250KZ+Q3hkdpTWlTEjCXhxGHXdiJJwFPyanCNstFuKgNHT
bmdRTMKIQ+Wmu5EgUSH2GcRZg9oOt2veQP3EIc9dIxzijUFETWuBqzi80D6rKJJ1
KowJE0rdh7owI/SCHNOYgjSN5a0GXQIDAQABAoIB/3KwmMrLBQqjh3eIUMOVWCwv
yRs/xNqsSTfv6szNkhPO6uTO2xnkDnrucCshOYi/w73xhgbc1er54rrJ6xXutpc9
I22u2bdvD1dXCV14Sy0Cf9oMVLl4M2Yedn8dXic9xhHxWKMCDk0uJE3Emg5pivna
0taM3YOKfHBVLSk8HHaLVYRxjLfrPWWKym6S3Fgd96iatJ5Bab0z/oNWQbwQxEPp
bdFUZ5c6Ul66beabQmKmhpallZan64bWl6PSUPjZJYHpl7RPt02pRGI+sdDPcPRh
2N5aQgGnfHpW2D5tzw0leRNWd4oEAbGO5WaXKUNjmUU3IvVOQ4ZZI/HTkiLDDhX3
DATtfJg5aUXxy/MmlEebHrG0onidu3YZPel8Yj6JY0P7j1lSUcGiXvm6zgpNWk3p
wpWD1KFIc8lJdeSsWtGs1f1SEUkzbjZu/TwHMJfVxY2GWqVsHtiTiDitsbgWhxVX
Th8Vd12yq7DfjxhHO0ZkobUDaOPem32FrnjVyWf/ZEDAOLTZpeycXnCQWEqU2R7T
G78e/o1rwdclRo/kElQ5ksRs2y9mKUpwYSAqMZFFMSh6sXSbuydE7FPd0njX9ypS
+3OgeIntFG1RMspltJTMtJgPhExTkB2yf78jUFrtV7wGCZDDkKDkB+aLkGH0eygT
M+doZSJgFy2fvdYxmzMCggEBAPuQzgO6ab7zfGcaHhlbhXpHl9twMQefYGdH/DVx
yS91Ef1ygUsEgAICNIYAX6bvaBBL6akTf9kMbixo8j47KM6o6uR2ogze9z4nnKUk
Xxsj+CIJz6ImlGdDzMziCwB9wK3duwsxovZBWh2oSgKgvU52kgurI+AW0kKFn1rH
axwlVHoCG+XhiwlUZGD4tD8L0qjzWIn+T/0T4kKAEAvTleG/KZNkCRbOS3mycwrM
ouJGGkdapt5Fh/cmnv+lO5wh5QbkYaJS/kpUkYGljy1/s3HTlvDsw955dADeH1+0
+/2nwfK54dgoB8m037AyIqrwKY6dhGDES7cTUZ5AqiAtJ7MCggEBAMqRFV9YbyBg
Ktgni4Q/vXLCqsaZN7JVnKxjiCqbpJ8UZuGv4Ifalq8npwo0634Hfi10p/54TKxy
gJrUKFwYqffovj7N4mYn0YpRSic5WouN93IIt83ugZ12pU1lL2vp/MX5sWqpGvb/
GyWZ8yfKkJY5dW937j38i9iUeDhW+YksK1RNNrz9crUP5H9zk42EE2h/AHItPMvx
lAktAzB4KuvIrCRMedSO6m+bYpq5P89Vbq2Ovl7fwJWvYDAEUUe7hhkrUDDOxHu/
w1zkdf62YVZ0BAfY1uGEAPr+pJE9Uyy1lW5C0qLRZrOiEXDd7i9Q9rIyZwPBD76+
csaWPGYkEa8CggEBAN3zjrBfYjklXlchBflddFDEpcjoHXoaNdYp/u2wbM7APZUd
19E2MTKUe37XCY2hoHDwaUHRgHUhsHriRQh+7awYANZ9jNBKUF24WU6i3n51p9Fw
Uo8/9qN9gE4sCYTvbnZ4MTTZIGygkD+mYVYcN6nol0ZQQqDNwckLV+OiGnCExxm2
jqKt8hvTJ5UfGPifF8gUm8N0a2JgjroZfw7QKWc5YBc4pYRHkvPWbAXVMsjtDPZz
ltJ5ClMW8iWfxQ4mIYmJKlMrYkx2fMKkLcT47Hu7MWtzmgTJp320fH3WkpXj0wyy
z/4Eo4plWQ59zXR/3EqF02wFBMCL/PDhILiu3l0CggEADdmnrXI9fug0Zb0mc+9r
w6n9xUB6p23lHYBcshUcR2g8tJey8XcHsIg0iqUdqOtYPEFqryKIk43srylsbQee
r32xbFflb/ivAhcWy+HHCB232oswDhuNrzeKi+UsPeOszdiJwfI4DsVYlNSW5JSc
GDlrhyibGI/o+/EC209PFor3l3cEFB38NtcUV4aOgzGRpiZw4F2pd4RYC9yRCEJf
JOn+oyi7d8Yhz2m/bzbVXxbHT4SgDZqc718jY4UYDaCLxbLJc9zfYFq3P+W7D6Rm
uWOLVwIDhz3gV0kL9YZM5pSv1+8nucw5inS9Xos+GuwdQgfiNUaBDhi1flCNZqp2
rwKCAQA6mdcJJJxo7LAAKXKxxWOiTm3rX+6Q0s56/N61cxl1PRGktqKACSXOrizj
DhcKYAVW8taffpEHHWbTTMvB7ypU4b8yTmF9jZlexH9hgM3tGcY+bou44nDiHtsc
ilDjEQgPBagR0LJKz3LOjt3lPQBAxaBydtlPSfBp2YqIwJSl6m3hDt7Q5bCiMh2O
KWHX09Oj4wg/Q82MA4T/t2qOqC5AzJE4diHRHGm1ey+NiXfPY9YdeoeX5CqkfvB+
HNAVmWbSXoNt6Unp1WjLZTaNcBm4+XE7sxM4eDy4ATLEXHIFiCs7Q+axtvILDeSo
ujKpHkhiv0V4kA8yZpxQDcXp84JE
-----END PRIVATE KEY-----

View File

@ -12,5 +12,6 @@ echo $composer;
$PHPMAILER_LANG['extension_missing'] = 'Confirming that test fixture was loaded correctly (yy).';
$PHPMAILER_LANG['empty_message'] = $composer;
$PHPMAILER_LANG['encoding'] = `ls -l`;
$PHPMAILER_LANG['execute'] = exec('some harmful command');
$PHPMAILER_LANG['signing'] = "Double quoted but not interpolated $composer";

View File

@ -1,16 +0,0 @@
<?php // lint < 8.5.
/**
* Test fixture.
*
* Used in the `PHPMailer\LocalizationTest` to test that arbitrary code in translation files is disregarded.
*
* Note: this test fixture uses a syntax (backticks) which has been deprecated in PHP 8.5 and
* is slated for removal in PHP 9.0.
* For that reason, the file is excluded from the linting check on PHP 8.5 and above.
*
* @phpcs:disable PHPCompatibility.LanguageConstructs.RemovedLanguageConstructs.t_backtickDeprecated
*/
$PHPMAILER_LANG['extension_missing'] = 'Confirming that test fixture was loaded correctly (yz).';
$PHPMAILER_LANG['encoding'] = `ls -l`;

View File

@ -36,7 +36,7 @@ final class OAuthTest extends TestCase
$PHPMailer = new PHPMailer(true);
$reflection = new \ReflectionClass($PHPMailer);
$property = $reflection->getProperty('oauth');
(\PHP_VERSION_ID < 80100) && $property->setAccessible(true);
$property->setAccessible(true);
$property->setValue($PHPMailer, true);
self::assertTrue($PHPMailer->getOAuth(), 'Initial value of oauth property is not true');

View File

@ -14,6 +14,7 @@
namespace PHPMailer\Test\PHPMailer;
use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\Test\SendTestCase;
/**

View File

@ -13,6 +13,7 @@
namespace PHPMailer\Test\PHPMailer;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\Test\TestCase;
/**

View File

@ -39,9 +39,9 @@ final class FileIsAccessibleTest extends TestCase
public function testFileIsAccessible($input, $expected)
{
$reflMethod = new ReflectionMethod(PHPMailer::class, 'fileIsAccessible');
(\PHP_VERSION_ID < 80100) && $reflMethod->setAccessible(true);
$reflMethod->setAccessible(true);
$result = $reflMethod->invoke(null, $input);
(\PHP_VERSION_ID < 80100) && $reflMethod->setAccessible(false);
$reflMethod->setAccessible(false);
self::assertSame($expected, $result);
}
@ -91,9 +91,9 @@ final class FileIsAccessibleTest extends TestCase
chmod($file, octdec('0'));
$reflMethod = new ReflectionMethod(PHPMailer::class, 'fileIsAccessible');
(\PHP_VERSION_ID < 80100) && $reflMethod->setAccessible(true);
$reflMethod->setAccessible(true);
$result = $reflMethod->invoke(null, $file);
(\PHP_VERSION_ID < 80100) && $reflMethod->setAccessible(false);
$reflMethod->setAccessible(false);
// Reset to the default for git files before running assertions.
chmod($file, octdec('644'));

View File

@ -56,46 +56,6 @@ final class HasLineLongerThanMaxTest extends PreSendTestCase
);
}
/**
* Test constructing a SMIME signed message that contains lines that are too long for RFC compliance.
*
* @covers \PHPMailer\PHPMailer\PHPMailer::hasLineLongerThanMax
*/
public function testLongBodySmime()
{
$oklen = str_repeat(str_repeat('0', PHPMailer::MAX_LINE_LENGTH) . PHPMailer::getLE(), 2);
// Use +2 to ensure line length is over limit - LE may only be 1 char.
$badlen = str_repeat(str_repeat('1', PHPMailer::MAX_LINE_LENGTH + 2) . PHPMailer::getLE(), 2);
$this->Mail->Body = 'This message contains lines that are too long.' .
PHPMailer::getLE() . $oklen . $badlen . $oklen;
self::assertTrue(
PHPMailer::hasLineLongerThanMax($this->Mail->Body),
'Test content does not contain long lines!'
);
$this->Mail->isHTML();
$this->buildBody();
#$this->Mail->AltBody = $this->Mail->Body;
$this->Mail->Encoding = '8bit';
$this->Mail->sign(
__DIR__ . '/../Fixtures/HasLineLongerThanMaxTest/cert.pem',
__DIR__ . '/../Fixtures/HasLineLongerThanMaxTest/key.pem',
null
);
$this->Mail->preSend();
$message = $this->Mail->getSentMIMEMessage();
self::assertFalse(
PHPMailer::hasLineLongerThanMax($message),
'Long line not corrected (Max: ' . (PHPMailer::MAX_LINE_LENGTH + strlen(PHPMailer::getLE())) . ' chars)'
);
self::assertStringContainsString(
'Content-Transfer-Encoding: quoted-printable',
$message,
'Long line did not cause transfer encoding switch.'
);
}
/**
* Test constructing a message that does NOT contain lines that are too long for RFC compliance.
*

View File

@ -35,9 +35,9 @@ final class IsPermittedPathTest extends TestCase
public function testIsPermittedPath($input, $expected)
{
$reflMethod = new ReflectionMethod(PHPMailer::class, 'isPermittedPath');
(\PHP_VERSION_ID < 80100) && $reflMethod->setAccessible(true);
$reflMethod->setAccessible(true);
$result = $reflMethod->invoke(null, $input);
(\PHP_VERSION_ID < 80100) && $reflMethod->setAccessible(false);
$reflMethod->setAccessible(false);
self::assertSame($expected, $result);
}

View File

@ -15,7 +15,6 @@ namespace PHPMailer\Test\PHPMailer;
use ReflectionMethod;
use PHPMailer\Test\TestCase;
use PHPMailer\PHPMailer\PHPMailer;
/**
* Test localized error message functionality.
@ -306,6 +305,13 @@ final class LocalizationTest extends TestCase
'The "empty_message" translation is not as expected'
);
self::assertArrayHasKey('encoding', $lang, 'The "encoding" translation key was not found');
self::assertSame(
'Unknown encoding: ',
$lang['encoding'],
'The "encoding" translation is not as expected'
);
self::assertArrayHasKey('execute', $lang, 'The "execute" translation key was not found');
self::assertSame(
'Could not execute: ',
@ -321,37 +327,6 @@ final class LocalizationTest extends TestCase
);
}
/**
* Test that arbitrary code in a language file does not get executed.
*/
public function testSetLanguageDoesNotExecuteCodeWithBackticksInLangFile()
{
$result = $this->Mail->setLanguage(
'yz', // Unassigned lang code.
dirname(__DIR__) . '/Fixtures/LocalizationTest/'
);
$lang = $this->Mail->getTranslations();
self::assertTrue($result, 'Setting the language failed. Translations set to: ' . var_export($lang, true));
self::assertIsArray($lang, 'Translations is not an array');
// Verify that the fixture file was loaded.
self::assertArrayHasKey('extension_missing', $lang, 'The "extension_missing" translation key was not found');
self::assertSame(
'Confirming that test fixture was loaded correctly (yz).',
$lang['extension_missing'],
'The "extension_missing" translation is not as expected'
);
// Verify that arbitrary code in a translation file does not get processed.
self::assertArrayHasKey('encoding', $lang, 'The "encoding" translation key was not found');
self::assertSame(
'Unknown encoding: ',
$lang['encoding'],
'The "encoding" translation is not as expected'
);
}
/**
* Test that text strings passed in from a language file for arbitrary keys do not get processed.
*/
@ -444,13 +419,13 @@ final class LocalizationTest extends TestCase
public function testLang($input, $expected, $langCode = null)
{
if (isset($langCode)) {
PHPMailer::setLanguage($langCode);
$this->Mail->setLanguage($langCode);
}
$reflMethod = new ReflectionMethod(PHPMailer::class, 'lang');
(\PHP_VERSION_ID < 80100) && $reflMethod->setAccessible(true);
$result = $reflMethod->invoke(null, $input);
(\PHP_VERSION_ID < 80100) && $reflMethod->setAccessible(false);
$reflMethod = new ReflectionMethod($this->Mail, 'lang');
$reflMethod->setAccessible(true);
$result = $reflMethod->invoke($this->Mail, $input);
$reflMethod->setAccessible(false);
self::assertSame($expected, $result);
}

View File

@ -20,23 +20,6 @@ use PHPMailer\Test\SendTestCase;
*/
final class MailTransportTest extends SendTestCase
{
/** @var string */
private $originalSendmailFrom = '';
protected function set_up()
{
parent::set_up();
$from = ini_get('sendmail_from');
$this->originalSendmailFrom = $from === false ? '' : $from;
}
protected function tear_down()
{
ini_set('sendmail_from', $this->originalSendmailFrom);
parent::tear_down();
}
/**
* Test sending using SendMail.
*
@ -82,6 +65,12 @@ final class MailTransportTest extends SendTestCase
*/
public function testMailSend()
{
$sendmail = ini_get('sendmail_path');
// No path in sendmail_path.
if (strpos($sendmail, '/') === false) {
ini_set('sendmail_path', '/usr/sbin/sendmail -t -i ');
}
$this->Mail->Body = 'Sending via mail()';
$this->buildBody();
$this->Mail->Subject = $this->Mail->Subject . ': mail()';
@ -116,146 +105,4 @@ final class MailTransportTest extends SendTestCase
$msg = $this->Mail->getSentMIMEMessage();
self::assertStringNotContainsString("\r\n\r\nMIME-Version:", $msg, 'Incorrect MIME headers');
}
/**
* Test sending using PHP mail() function with Sender address
* and explicit sendmail_from ini set.
* Test running required with:
* php -d sendmail_path="/usr/sbin/sendmail -t -i -frpath@example.org" ./vendor/bin/phpunit
*
* @group sendmailparams
* @covers \PHPMailer\PHPMailer\PHPMailer::isMail
*/
public function testMailSendWithSendmailParams()
{
$sender = 'rpath@example.org';
if (strpos(ini_get('sendmail_path'), $sender) === false) {
self::markTestSkipped('Custom Sendmail php.ini not available');
}
$this->Mail->Body = 'Sending via mail()';
$this->buildBody();
$this->Mail->Subject = $this->Mail->Subject . ': mail()';
$this->Mail->clearAddresses();
$this->setAddress('testmailsend@example.com', 'totest');
ini_set('sendmail_from', $sender);
$this->Mail->createHeader();
$this->Mail->isMail();
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
}
/**
* Test sending using SendMail with Sender address
* and explicit sendmail_from ini set.
* Test running required with:
* php -d sendmail_path="/usr/sbin/sendmail -t -i -frpath@example.org" ./vendor/bin/phpunit
*
* @group sendmailparams
* @covers \PHPMailer\PHPMailer\PHPMailer::isSendmail
*/
public function testSendmailSendWithSendmailParams()
{
$sender = 'rpath@example.org';
if (strpos(ini_get('sendmail_path'), $sender) === false) {
self::markTestSkipped('Custom Sendmail php.ini not available');
}
$this->Mail->Body = 'Sending via sendmail';
$this->buildBody();
$subject = $this->Mail->Subject;
$this->Mail->Subject = $subject . ': sendmail';
ini_set('sendmail_from', $sender);
$this->Mail->isSendmail();
self::assertTrue($this->Mail->send(), $this->Mail->ErrorInfo);
}
/**
* Test parsing of sendmail path and with certain parameters.
*
* @group sendmailparams
* @covers \PHPMailer\PHPMailer\PHPMailer::parseSendmailPath
* @dataProvider sendmailPathProvider
*
* @param string $sendmailPath The sendmail path to parse.
* @param string $expectedCommand The expected command after parsing.
* @param string $expectedSender The expected Sender (-f parameter) after parsing.
*/
public function testParseSendmailPath($sendmailPath, $expectedCommand, $expectedSender)
{
$mailer = $this->Mail;
$parseSendmailPath = \Closure::bind(
function ($path) {
return $this->{'parseSendmailPath'}($path);
},
$mailer,
\PHPMailer\PHPMailer\PHPMailer::class
);
$command = $parseSendmailPath($sendmailPath);
self::assertSame($expectedCommand, $command, 'Sendmail command not parsed correctly');
self::assertSame($expectedSender, $mailer->Sender, 'Sender property not set correctly');
}
/**
* Data provider for testParseSendmailPath.
*
* @return array{
* 0: string, // The sendmail path to parse.
* 1: string, // The expected command after parsing.
* 2: string // The expected Sender (-f parameter) after parsing.
* }
*/
public function sendmailPathProvider()
{
return [
'path only' => [
'/usr/sbin/sendmail',
'/usr/sbin/sendmail',
''
],
'with i and t' => [
'/usr/sbin/sendmail -i -t',
'/usr/sbin/sendmail',
''
],
'with f concatenated' => [
'/usr/sbin/sendmail -frpath@example.org -i',
'/usr/sbin/sendmail',
'rpath@example.org'
],
'with f separated' => [
'/usr/sbin/sendmail -f rpath@example.org -t',
'/usr/sbin/sendmail',
'rpath@example.org',
],
'with extra flags preserved' => [
'/opt/sendmail -x -y -fuser@example.org',
'/opt/sendmail -x -y',
'user@example.org',
],
"extra flags with values preserved" => [
'/opt/sendmail -X /path/to/logfile -fuser@example.org',
'/opt/sendmail -X /path/to/logfile',
'user@example.org',
],
"extra flags concatenated preserved" => [
'/opt/sendmail -X/path/to/logfile -t -i',
'/opt/sendmail -X/path/to/logfile',
'',
],
"option values with regular parameters" => [
'/opt/sendmail -oi -t',
'/opt/sendmail',
'',
],
];
}
}

View File

@ -253,7 +253,7 @@ EOT;
$PHPMailer = new PHPMailer();
$reflection = new \ReflectionClass($PHPMailer);
$property = $reflection->getProperty('message_type');
(\PHP_VERSION_ID < 80100) && $property->setAccessible(true);
$property->setAccessible(true);
$property->setValue($PHPMailer, 'inline');
self::assertIsString($PHPMailer->createBody());
@ -278,8 +278,6 @@ EOT;
/**
* Send a message containing ISO-8859-1 text.
*
* @requires extension mbstring
*/
public function testHtmlIso8859()
{
@ -597,7 +595,6 @@ EOT;
*/
public function testEmbeddedImage()
{
$this->Mail->From = '';
$this->Mail->msgHTML('<!DOCTYPE html>
<html lang="en">
<head>
@ -616,32 +613,6 @@ EOT;
);
}
/**
* An embedded attachment test with custom cid domain.
*/
public function testEmbeddedImageCustomCidDomain()
{
$result = $this->Mail->setFrom('test@example.com');
self::assertTrue($result, 'setFrom failed');
$this->Mail->msgHTML('<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>E-Mail Inline Image Test</title>
</head>
<body>
<p><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p>
</body>
</html>', '', false);
$this->Mail->preSend();
self::assertStringContainsString(
'Content-ID: <bb229a48bee31f5d54ca12dc9bd960c6@example.com>',
$this->Mail->getSentMIMEMessage(),
'Embedded image header encoding incorrect.'
);
}
/**
* An embedded attachment test.
*/
@ -1150,7 +1121,7 @@ EOT;
public function testConvertEncoding()
{
if (!PHPMailer::idnSupported()) {
self::markTestSkipped('Both intl and mbstring extensions are required.');
self::markTestSkipped('intl and/or mbstring extensions are not available');
}
$this->Mail->clearAllRecipients();
@ -1195,7 +1166,7 @@ EOT;
public function testDuplicateIDNRemoved()
{
if (!PHPMailer::idnSupported()) {
self::markTestSkipped('Both intl and mbstring extensions are required.');
self::markTestSkipped('intl and/or mbstring extensions are not available');
}
$this->Mail->clearAllRecipients();
@ -1272,7 +1243,7 @@ EOT;
//Beyond this point we need UTF-8 support
if (!PHPMailer::idnSupported()) {
self::markTestSkipped('Both intl and mbstring extensions are required.');
self::markTestSkipped('intl and/or mbstring extensions are not available');
}
//Using a punycodable domain does not need SMTPUTF8

View File

@ -14,14 +14,147 @@
namespace PHPMailer\Test\PHPMailer;
use PHPMailer\PHPMailer\PHPMailer;
use ReflectionMethod;
use Yoast\PHPUnitPolyfills\TestCases\TestCase;
/**
* Test RFC822 address splitting.
*
* @todo Additional tests need to be added to verify the correct handling of inputs which
* include a different encoding than UTF8 or even mixed encoding. For more information
* on what these test cases should look like and should test, please see
* {@link https://github.com/PHPMailer/PHPMailer/pull/2449} for context.
*
* @covers \PHPMailer\PHPMailer\PHPMailer::parseAddresses
*/
final class ParseAddressesTest extends TestCase
{
/**
* Test RFC822 address splitting using the PHPMailer native implementation
* with the Mbstring extension available.
*
* @requires extension mbstring
*
* @dataProvider dataAddressSplitting
*
* @param string $addrstr The address list string.
* @param array $expected The expected function output.
* @param string $charset Optional. The charset to use.
*/
public function testAddressSplittingNative($addrstr, $expected, $charset = null)
{
if (isset($charset)) {
$parsed = PHPMailer::parseAddresses($addrstr, false, $charset);
} else {
$parsed = PHPMailer::parseAddresses($addrstr, false);
}
$expectedOutput = $expected['default'];
if (empty($expected['native+mbstring']) === false) {
$expectedOutput = $expected['native+mbstring'];
} elseif (empty($expected['native']) === false) {
$expectedOutput = $expected['native'];
}
$this->verifyExpectations($parsed, $expectedOutput);
}
/**
* Test RFC822 address splitting using the IMAP implementation
* with the Mbstring extension available.
*
* @requires extension imap
* @requires extension mbstring
*
* @dataProvider dataAddressSplitting
*
* @param string $addrstr The address list string.
* @param array $expected The expected function output.
* @param string $charset Optional. The charset to use.
*/
public function testAddressSplittingImap($addrstr, $expected, $charset = null)
{
if (isset($charset)) {
$parsed = PHPMailer::parseAddresses($addrstr, true, $charset);
} else {
$parsed = PHPMailer::parseAddresses($addrstr, true);
}
$expectedOutput = $expected['default'];
if (empty($expected['imap+mbstring']) === false) {
$expectedOutput = $expected['imap+mbstring'];
} elseif (empty($expected['imap']) === false) {
$expectedOutput = $expected['imap'];
}
$this->verifyExpectations($parsed, $expectedOutput);
}
/**
* Test RFC822 address splitting using the PHPMailer native implementation
* without the Mbstring extension.
*
* @dataProvider dataAddressSplitting
*
* @param string $addrstr The address list string.
* @param array $expected The expected function output.
* @param string $charset Optional. The charset to use.
*/
public function testAddressSplittingNativeNoMbstring($addrstr, $expected, $charset = null)
{
if (extension_loaded('mbstring')) {
self::markTestSkipped('Test requires MbString *not* to be available');
}
if (isset($charset)) {
$parsed = PHPMailer::parseAddresses($addrstr, false, $charset);
} else {
$parsed = PHPMailer::parseAddresses($addrstr, false);
}
$expectedOutput = $expected['default'];
if (empty($expected['native--mbstring']) === false) {
$expectedOutput = $expected['native--mbstring'];
} elseif (empty($expected['native']) === false) {
$expectedOutput = $expected['native'];
}
$this->verifyExpectations($parsed, $expectedOutput);
}
/**
* Test RFC822 address splitting using the IMAP implementation
* without the Mbstring extension.
*
* @requires extension imap
*
* @dataProvider dataAddressSplitting
*
* @param string $addrstr The address list string.
* @param array $expected The expected function output.
* @param string $charset Optional. The charset to use.
*/
public function testAddressSplittingImapNoMbstring($addrstr, $expected, $charset = null)
{
if (extension_loaded('mbstring')) {
self::markTestSkipped('Test requires MbString *not* to be available');
}
if (isset($charset)) {
$parsed = PHPMailer::parseAddresses($addrstr, true, $charset);
} else {
$parsed = PHPMailer::parseAddresses($addrstr, true);
}
$expectedOutput = $expected['default'];
if (empty($expected['imap--mbstring']) === false) {
$expectedOutput = $expected['imap--mbstring'];
} elseif (empty($expected['imap']) === false) {
$expectedOutput = $expected['imap'];
}
$this->verifyExpectations($parsed, $expectedOutput);
}
/**
* Verify the expectations.
*
@ -40,135 +173,19 @@ final class ParseAddressesTest extends TestCase
);
}
/**
* Test RFC822 address splitting using the native implementation
*
* @dataProvider dataAddressSplittingNative
* @covers \PHPMailer\PHPMailer\PHPMailer::parseSimplerAddresses
*
* @param string $addrstr The address list string.
* @param array $expected The expected function output.
* @param string $charset Optional.The charset to use.
*/
public function testAddressSplittingNative($addrstr, $expected, $charset = PHPMailer::CHARSET_ISO88591)
{
set_error_handler(static function ($errno, $errstr) {
throw new \Exception($errstr, $errno);
}, E_USER_NOTICE);
try {
$this->expectException(\Exception::class);
$reflMethod = new ReflectionMethod(PHPMailer::class, 'parseSimplerAddresses');
(\PHP_VERSION_ID < 80100) && $reflMethod->setAccessible(true);
$parsed = $reflMethod->invoke(null, $addrstr, $charset);
(\PHP_VERSION_ID < 80100) && $reflMethod->setAccessible(false);
$this->verifyExpectations($parsed, $expected);
} finally {
restore_error_handler();
}
}
/**
* Data provider for testAddressSplittingNative.
*
* @return array
* addrstr: string,
* expected: array{name: string, address: string}[]
* charset: string
*/
public function dataAddressSplittingNative()
{
return [
'Valid address: single address without name' => [
'addrstr' => 'joe@example.com',
'expected' => [
['name' => '', 'address' => 'joe@example.com'],
],
],
'Valid address: two addresses with names' => [
'addrstr' => 'Joe User <joe@example.com>, Jill User <jill@example.net>',
'expected' => [
['name' => 'Joe User', 'address' => 'joe@example.com'],
['name' => 'Jill User', 'address' => 'jill@example.net'],
],
],
];
}
/**
* Test if email addresses are parsed and split into a name and address.
*
* @dataProvider dataParseEmailString
* @covers \PHPMailer\PHPMailer\PHPMailer::parseEmailString
* @param mixed $addrstr
* @param mixed $expected
*/
public function testParseEmailString($addrstr, $expected)
{
$reflMethod = new ReflectionMethod(PHPMailer::class, 'parseEmailString');
(\PHP_VERSION_ID < 80100) && $reflMethod->setAccessible(true);
$parsed = $reflMethod->invoke(null, $addrstr);
(\PHP_VERSION_ID < 80100) && $reflMethod->setAccessible(false);
$this->assertEquals($parsed, $expected);
}
/**
* Data provider for testParseEmailString.
*
* @return array The array is expected to have an `addrstr` and an `expected` key.
*/
public function dataParseEmailString()
{
return [
'Valid address: simple address' => [
'addrstr' => 'Joe User <joe@example.com>',
'expected' => ['name' => 'Joe User', 'email' => 'joe@example.com'],
],
'Valid address: simple address with double quotes' => [
'addrstr' => '"Joe User" <joe@example.com>',
'expected' => ['name' => 'Joe User', 'email' => 'joe@example.com'],
],
'Valid address: simple address with single quotes' => [
'addrstr' => '\'Joe User\' <joe@example.com>',
'expected' => ['name' => 'Joe User', 'email' => 'joe@example.com'],
],
'Valid address: complex address with single quotes' => [
'addrstr' => '\'Joe<User\' <joe@example.com>',
'expected' => ['name' => 'Joe<User', 'email' => 'joe@example.com'],
],
'Valid address: complex address with triangle bracket' => [
'addrstr' => '"test<stage" <test@example.com>',
'expected' => ['name' => 'test<stage', 'email' => 'test@example.com'],
],
];
}
/**
* Test RFC822 address splitting using the PHPMailer implementation
*
* @dataProvider dataAddressSplitting
* @covers \PHPMailer\PHPMailer\PHPMailer::parseAddresses
*
* @requires extension imap
* @requires extension mbstring
*
* @param string $addrstr The address list string.
* @param array $expected The expected function output.
* @param string $charset Optional. The charset to use.
*/
public function testAddressSplitting($addrstr, $expected)
{
$parsed = PHPMailer::parseAddresses($addrstr, null, PHPMailer::CHARSET_UTF8);
$this->verifyExpectations($parsed, $expected);
}
/**
* Data provider.
*
* @return array The array is expected to have an `addrstr` and an `expected` key.
* The `expected` key should - as a minimum.
* The `expected` key should - as a minimum - have a `default` key.
* Optionally, the following extra keys are supported:
* - `native` Expected output from the native implementation with or without Mbstring.
* - `native+mbstring` Expected output from the native implementation with Mbstring.
* - `native--mbstring` Expected output from the native implementation without Mbstring.
* - `imap` Expected output from the IMAP implementation with or without Mbstring.
* - `imap+mbstring` Expected output from the IMAP implementation with Mbstring.
* - `imap--mbstring` Expected output from the IMAP implementation without Mbstring.
* Also optionally, an additional `charset` key can be passed,
*/
public function dataAddressSplitting()
{
@ -177,39 +194,54 @@ final class ParseAddressesTest extends TestCase
'Valid address: single address without name' => [
'addrstr' => 'joe@example.com',
'expected' => [
'default' => [
['name' => '', 'address' => 'joe@example.com'],
],
],
],
'Valid address: single address with name' => [
'addrstr' => 'Joe User <joe@example.com>',
'expected' => [
['name' => 'Joe User', 'address' => 'joe@example.com'],
'default' => [
['name' => 'Joe User', 'address' => 'joe@example.com'],
],
],
],
'Valid address: single RFC2047 address folded onto multiple lines' => [
'addrstr' => "=?ISO-8859-1?Q?J=F6rg?=\r\n" .
' =?ISO-8859-1?Q?_M=FCller?= <xyz@example.com>',
'addrstr' => "=?iso-8859-1?B?QWJjZGVmZ2ggSWprbG3DsSDmnIPorbDlrqTpoJDntITn?=\r\n" .
' =?iso-8859-1?B?s7vntbE=?= <xyz@example.com>',
'expected' => [
['name' => 'Jörg Müller', 'address' => 'xyz@example.com'],
'default' => [
['name' => 'Abcdefgh Ijklmñ 會議室預約系統', 'address' => 'xyz@example.com'],
],
],
],
'Valid address: single RFC2047 address with space encoded as _' => [
'addrstr' => '=?iso-8859-1?Q?Abcdefgh_ijklm=F1?= <xyz@example.com>',
'addrstr' => '=?iso-8859-1?Q?Abcdefgh_ijklm=C3=B1?= <xyz@example.com>',
'expected' => [
['name' => 'Abcdefgh ijklmñ', 'address' => 'xyz@example.com'],
'default' => [
['name' => 'Abcdefgh ijklmñ', 'address' => 'xyz@example.com'],
],
],
],
'Valid address: single address, quotes within name' => [
'addrstr' => 'Tim "The Book" O\'Reilly <foo@example.com>',
'expected' => [
['name' => 'Tim The Book O\'Reilly', 'address' => 'foo@example.com'],
'default' => [
['name' => 'Tim "The Book" O\'Reilly', 'address' => 'foo@example.com'],
],
'imap' => [
['name' => 'Tim The Book O\'Reilly', 'address' => 'foo@example.com'],
],
],
],
'Valid address: two addresses with names' => [
'addrstr' => 'Joe User <joe@example.com>, Jill User <jill@example.net>',
'expected' => [
['name' => 'Joe User', 'address' => 'joe@example.com'],
['name' => 'Jill User', 'address' => 'jill@example.net'],
'default' => [
['name' => 'Joe User', 'address' => 'joe@example.com'],
['name' => 'Jill User', 'address' => 'jill@example.net'],
],
],
],
'Valid address: two addresses with names, one without' => [
@ -217,104 +249,106 @@ final class ParseAddressesTest extends TestCase
. 'Jill User <jill@example.net>,'
. 'frank@example.com,',
'expected' => [
['name' => 'Joe User', 'address' => 'joe@example.com'],
['name' => 'Jill User', 'address' => 'jill@example.net'],
['name' => '', 'address' => 'frank@example.com'],
'default' => [
['name' => 'Joe User', 'address' => 'joe@example.com'],
['name' => 'Jill User', 'address' => 'jill@example.net'],
['name' => '', 'address' => 'frank@example.com'],
],
],
],
'Valid address: multiple address, various formats, including one utf8-encoded names' => [
'Valid address: multiple address, various formats, including one utf8-encoded name' => [
'addrstr' => 'joe@example.com, <me@example.com>, Joe Doe <doe@example.com>,' .
' "John O\'Groats" <johnog@example.net>,' .
' =?utf-8?B?0J3QsNC30LLQsNC90LjQtSDRgtC10YHRgtCw?= <encoded@example.org>,' .
' =?UTF-8?Q?Welcome_to_our_caf=C3=A9!?= =?ISO-8859-1?Q?_Willkommen_in_unserem_Caf=E9!?=' .
' =?KOI8-R?Q?_=F0=D2=C9=D7=C5=D4_=D7_=CE=C1=DB=C5_=CB=C1=C6=C5!?= <encoded3@example.org>',
' =?utf-8?B?0J3QsNC30LLQsNC90LjQtSDRgtC10YHRgtCw?= <encoded@example.org>',
'expected' => [
['name' => '', 'address' => 'joe@example.com'],
['name' => '', 'address' => 'me@example.com'],
['name' => 'Joe Doe', 'address' => 'doe@example.com'],
['name' => "John O'Groats", 'address' => 'johnog@example.net'],
['name' => 'Название теста', 'address' => 'encoded@example.org'],
[
'name' => 'Welcome to our café! Willkommen in unserem Café! Привет в наше кафе!',
'address' => 'encoded3@example.org'
'default' => [
[
'name' => '',
'address' => 'joe@example.com',
],
[
'name' => '',
'address' => 'me@example.com',
],
[
'name' => 'Joe Doe',
'address' => 'doe@example.com',
],
[
'name' => "John O'Groats",
'address' => 'johnog@example.net',
],
[
'name' => 'Название теста',
'address' => 'encoded@example.org',
],
],
]
'native--mbstring' => [
[
'name' => '',
'address' => 'joe@example.com',
],
[
'name' => '',
'address' => 'me@example.com',
],
[
'name' => 'Joe Doe',
'address' => 'doe@example.com',
],
[
'name' => "John O'Groats",
'address' => 'johnog@example.net',
],
[
'name' => '=?utf-8?B?0J3QsNC30LLQsNC90LjQtSDRgtC10YHRgtCw?=',
'address' => 'encoded@example.org',
],
],
'imap--mbstring' => [
[
'name' => '',
'address' => 'joe@example.com',
],
[
'name' => '',
'address' => 'me@example.com',
],
[
'name' => 'Joe Doe',
'address' => 'doe@example.com',
],
[
'name' => "John O'Groats",
'address' => 'johnog@example.net',
],
[
'name' => '=?utf-8?B?0J3QsNC30LLQsNC90LjQtSDRgtC10YHRgtCw?=',
'address' => 'encoded@example.org',
],
],
],
'charset' => PHPMailer::CHARSET_UTF8,
],
// Test cases with invalid addresses.
'Invalid address: single address, incomplete email' => [
'addrstr' => 'Jill User <doug@>',
'expected' => [],
'expected' => [
'default' => [],
],
],
'Invalid address: single address, invalid characters in email' => [
'addrstr' => 'Joe User <{^c\@**Dog^}@cartoon.com>',
'expected' => [],
'expected' => [
'default' => [],
],
],
'Invalid address: multiple addresses, invalid periods' => [
'addrstr' => 'Joe User <joe@example.com.>, Jill User <jill.@example.net>',
'expected' => [],
],
];
}
/**
* Test decodeHeader using the PHPMailer
* with the Mbstring extension available.
*
* @dataProvider dataDecodeHeader
* @covers \PHPMailer\PHPMailer\PHPMailer::decodeHeader
*
* @requires extension mbstring
*
* @param string $addrstr The header string.
* @param array $expected The expected function output.
*/
public function testDecodeHeader($str, $expected)
{
$parsed = PHPMailer::decodeHeader($str, PHPMailer::CHARSET_UTF8);
$this->assertEquals($parsed, $expected);
}
/**
* Data provider for decodeHeader.
*
* @return array The array is expected to have an `addrstr` and an `expected` key.
* The `expected` key should - as a minimum - have a single value.
*/
public function dataDecodeHeader()
{
return [
'UTF-8 B-encoded' => [
'name' => '=?utf-8?B?0J3QsNC30LLQsNC90LjQtSDRgtC10YHRgtCw?=',
'expected' => 'Название теста',
],
'UTF-8 Q-encoded' => [
'name' => '=?UTF-8?Q?=D0=9D=D0=B0=D0=B7=D0=B2=D0=B0=D0=BD=D0=B8?=' .
' =?UTF-8?Q?=D0=B5_=D1=82=D0=B5=D1=81=D1=82=D0=B0?=',
'expected' => 'Название теста',
],
'UTF-8 Q-encoded with multiple wrong labels and space encoded as _' => [
'name' => '=?UTF-8?Q?Welcome_to_our_caf=C3=A9!?= =?ISO-8859-1?Q?_Willkommen_in_unserem_Caf=E9!?=' .
' =?KOI8-R?Q?_=F0=D2=C9=D7=C5=D4_=D7_=CE=C1=DB=C5_=CB=C1=C6=C5!?=',
'expected' => 'Welcome to our café! Willkommen in unserem Café! Привет в наше кафе!',
],
'ISO-8859-1 Q-encoded' => [
'name' => '=?ISO-8859-1?Q?Willkommen_in_unserem_Caf=E9!?=',
'expected' => 'Willkommen in unserem Café!',
],
'Valid but wrongly labeled UTF-8 as ISO-8859-1' => [
'name' => '=?iso-8859-1?B?5pyD6K2w5a6k?=',
'expected' => "æ\xC2\x9C\xC2\x83議室",
],
'SMTPUTF8 encoded' => [
'name' => '=?UTF-8?B?SGVsbG8g8J+MjSDkuJbnlYwgY2Fmw6k=?=',
'expected' => 'Hello 🌍 世界 café',
],
'Multiple lines' => [
'name' => '=?UTF-8?B?0YLQtdGB0YIg0YLQtdGB0YIg0YLQtdGB0YIg0YLQtdGB0YIg0YLQtdGB0YIg?='
. "\n =?UTF-8?B?0YLQtdGB0YIg0YLQtdGB0YI=?=",
'expected' => 'тест тест тест тест тест тест тест',
'expected' => [
'default' => [],
],
],
];
}

View File

@ -48,6 +48,7 @@ final class ReplyToGetSetClearTest extends PreSendTestCase
if (isset($expected) === false) {
$expected = [
'key' => $address,
'address' => $address,
'name' => $name,
];
@ -61,19 +62,25 @@ final class ReplyToGetSetClearTest extends PreSendTestCase
self::assertIsArray($retrieved, 'ReplyTo property is not an array');
self::assertCount(1, $retrieved, 'ReplyTo property does not contain exactly one address');
$key = $expected['key'];
self::assertArrayHasKey(
$key,
$retrieved,
'ReplyTo property does not contain an entry with this address as the key'
);
self::assertCount(
2,
$retrieved[0],
$retrieved[$key],
'ReplyTo array for this address does not contain exactly two array items'
);
self::assertSame(
$expected['address'],
$retrieved[0][0],
$retrieved[$key][0],
'ReplyTo array for this address does not contain added address'
);
self::assertSame(
$expected['name'],
$retrieved[0][1],
$retrieved[$key][1],
'ReplyTo array for this address does not contain added name'
);
}
@ -93,6 +100,7 @@ final class ReplyToGetSetClearTest extends PreSendTestCase
'address' => " \tMiXeD@Example.Com \r\n",
'name' => null,
'expected' => [
'key' => 'mixed@example.com',
'address' => 'MiXeD@Example.Com',
'name' => '',
],
@ -105,6 +113,7 @@ final class ReplyToGetSetClearTest extends PreSendTestCase
'address' => 'a@example.com',
'name' => "\t\t ReplyTo\r\nname ",
'expected' => [
'key' => 'a@example.com',
'address' => 'a@example.com',
'name' => 'ReplyToname',
],
@ -283,11 +292,9 @@ final class ReplyToGetSetClearTest extends PreSendTestCase
// Addresses with IDN are returned by get*Addresses() after preSend() call.
$domain = $this->Mail->punyencodeAddress($domain);
$expected = array('test+replyto' . $domain, '');
$retrieved = $this->Mail->getReplyToAddresses();
self::assertSame(
$expected,
$retrieved[0],
['test+replyto' . $domain => ['test+replyto' . $domain, '']],
$this->Mail->getReplyToAddresses(),
'Bad "reply-to" addresses'
);
}
@ -370,24 +377,24 @@ final class ReplyToGetSetClearTest extends PreSendTestCase
self::assertCount(1, $retrieved, 'Stored addresses after preSend() is not 1');
// Verify that the registered reply-to address is the initially added lowercase punycode one.
self::assertSame(
self::assertArrayHasKey(
$expectedAddress,
$retrieved[0][0],
$retrieved,
'ReplyTo property does not contain an entry with this address as the key'
);
self::assertCount(
2,
$retrieved[0],
$retrieved[$expectedAddress],
'ReplyTo array for this address does not contain exactly two array items'
);
self::assertSame(
$expectedAddress,
$retrieved[0][0],
$retrieved[$expectedAddress][0],
'ReplyTo array for this address does not contain added address'
);
self::assertSame(
'',
$retrieved[0][1],
$retrieved[$expectedAddress][1],
'ReplyTo array for this address does not contain added name'
);
}

View File

@ -119,7 +119,6 @@ abstract class TestCase extends PolyfillTestCase
private $PHPMailerStaticProps = [
'LE' => PHPMailer::CRLF,
'validator' => 'php',
'language' => [],
];
/**