目次
環境
Codeingiter: 2.x系
はじめに
先日、クライアントから一部の環境でメールが文字化けると連絡が入りました。
確認してみると、Gmailアプリで受け取ったメールに該当の現象が起きました。
「ふぁ?!」となる状況ながら調査しました。
原因
調査して分かったのは、Codeigniter 2.x系で送ったメールにこれが起きるようでした。
Codeigniter 3.x系では問題ないようです。(ライブラリの中身がまったくの別物)
■原因の箇所
private function _prep_q_encoding($str, $from = FALSE)
{
$str = str_replace(array("\r", "\n"), array('', ''), $str);
// Line length must not exceed 76 characters, so we adjust for
// a space, 7 extra characters =??Q??=, and the charset that we will add to each line
$limit = 75 - 7 - strlen($this->charset);
// these special characters must be converted too
$convert = array('_', '=', '?');
if ($from === TRUE)
{
$convert[] = ',';
$convert[] = ';';
}
$output = '';
$temp = '';
for ($i = 0, $length = strlen($str); $i < $length; $i++)
{
// Grab the next character
$char = substr($str, $i, 1);
$ascii = ord($char);
// convert ALL non-printable ASCII characters and our specials
if ($ascii < 32 OR $ascii > 126 OR in_array($char, $convert))
{
$char = '='.dechex($ascii);
}
// handle regular spaces a bit more compactly than =20
if ($ascii == 32)
{
$char = '_';
}
// If we're at the character limit, add the line to the output,
// reset our temp variable, and keep on chuggin'
if ((strlen($temp) + strlen($char)) >= $limit)
{
$output .= $temp.$this->crlf;
$temp = '';
}
// Add the character to our temporary line
$temp .= $char;
}
$str = $output.$temp;
// wrap each line with the shebang, charset, and transfer encoding
// the preceding space on successive lines is required for header "folding"
$str = trim(preg_replace('/^(.*)$/m', ' =?'.$this->charset.'?Q?$1?=', $str));
return $str;
}
対応
以下のサイトを参考にしました。
https://www.bricoleur.co.jp/blog/archives/3480
https://qiita.com/seihowlow24/items/ca4b8fa00fab7a8160ee
qiita の記事は、かなり近かったのですが、管理人の環境では対応できませんでした。
■対応ソース
class MY_Email extends CI_Email {
function __construct()
{
parent::__construct();
}
function message($body)
{
if (strtolower($this->charset) == 'iso-2022-jp')
{
$this->_body = mb_convert_encoding(stripslashes(rtrim(str_replace("\r", "", $body))), 'ISO-2022-JP', 'UTF-8');
}
else
{
$this->_body = stripslashes(rtrim(str_replace("\r", "", $body)));
}
return $this;
}
public function subject($subject)
{
$this->_headers['Subject'] = $subject;
return $this;
}
}
$this->load->library('email');
$config['wordwrap'] = FALSE;
$config['charset'] = 'ISO-2022-jp';
$this->email->initialize($config);
$subject = '件名';
$subject = "=?iso-2022-jp?B?".base64_encode(mb_convert_encoding($subject,"JIS","UTF-8"))."?=";
$this->email->from('info@hoge.com');
$this->email->to(set_value('mail'));
$this->email->subject($subject);
$this->email->message('本文');
$this->email->send();
いかがでしょうか?
正直、今回の対応のしかたには納得していません。
もっと良いやり方があったら教えてください。
そもそも2系なんて化石を使うなって話ですね。
今日はこの辺でー