MIME headers aren't encoded properly when using ISO-2022-JP (7bit) CharSet
Author: kosekiCreated Oct 31, 2020Updated Nov 2, 2020
Please check these things before submitting your issue:
- Read the error message you're seeing - it often tells you what is wrong, and may contain useful links & instructions
- Make sure you're using the latest version of PHPMailer
- Check that your problem is not dealt with in the troubleshooting guide, especially if you're having problems connecting to Gmail or GoDaddy
- Include sufficient code to reproduce your problem
- If you're having an SMTP issue, include the debug output generated with
SMTPDebug = 2set - If you have a question about how to use PHPMailer (rather than reporting a bug in it), tag a question on Stack Overflow with
phpmailer, but search first!
Problem description
In the PHPMailer.php, there is a code that set $charset = "us-ascii" if the input string does not have 8-bit characters.
https://github.com/PHPMailer/PHPMailer/blob/3dffb3e4ee97b82a63eeac9ec2d03b164becc451/src/PHPMailer.php#L3282-L3286
In Japan, 7-bit charset ISO-2022-JP has been used historically.
The has8bitChars($str) method returns false when the ISO-2022-JP string are passed.
<?php
require 'vendor/autoload.php';
use PHPMailer\PHPMailer\PHPMailer;
$mail = new PHPMailer();
$str = mb_convert_encoding('テスト', 'ISO-2022-JP');
var_dump($mail->has8bitChars($str)); // ==> false
As a result, PHPMailer generates us-ascii MIME headers when the ISO-2022-JP charset is set. For example:
Subject: =?us-ascii?Q?=1B$B%F%9%H=1B(B?=
Code to reproduce
<?php
require 'vendor/autoload.php';
use PHPMailer\PHPMailer\PHPMailer;
$mail = new PHPMailer();
$mail->CharSet = 'ISO-2022-JP';
$mail->setFrom('[email protected]');
$mail->addAddress('[email protected]');
$mail->Body = 'test';
$input = 'テスト';
$expected = mb_encode_mimeheader($input, $mail->CharSet);
if (isset($argv[1])) {
$str = $input;
} else {
$str = mb_convert_encoding($input, $mail->CharSet);
}
$mail->Subject = $str;
// Get whole message as string.
$mail->preSend();
$message = $mail->getSentMIMEMessage();
// echo $message;
preg_match('{^Subject: (.+?\n(?: =.+?\n)*)}m', $message, $m);
$encoded = $m[1];
$decoded = mb_decode_mimeheader($encoded);
$hex = preg_replace('{..}', '\0 ', strtoupper(bin2hex($decoded)));
echo "Expected: " . $expected . "\n";
echo "Encoded: " . $encoded. "\n";
echo "Decoded(raw): " . $decoded. "\n";
echo "Decoded(hex): " . $hex . "\n";
The result is:
$ php test.php
Expected: =?ISO-2022-JP?B?GyRCJUYlOSVIGyhC?=
Encoded: =?us-ascii?Q?=1B$B%F%9%H=1B(B?=
Decoded(raw): %F%9%H
Decoded(hex): 1B 24 42 25 46 25 39 25 48 1B 28 42
I believe that the mb_convert_encoding($str, 'ISO-2022-JP') is required for each header fields. For example:
$mail->Subject = mb_convert_encoding('テスト', 'ISO-2022-JP');
But it also doesn't work without the conversion.
$ php test.php --skip-conversion
Expected: =?ISO-2022-JP?B?GyRCJUYlOSVIGyhC?=
Encoded: =?ISO-2022-JP?B?44OG44K544OI?=
Decoded(raw): ?????ケ???
Decoded(hex): 3F 3F 3F 3F 3F EF BD B9 3F 3F 3F
Tested environment
- PHPMailer 6.1.8
- PHP 7.0.32
Related issues
- #1945
Source: PHPMailer/PHPMailer