忘れないように記録しとこ

カバの樹

Codeigniterのmailライブラリで送ったメールが、Gmailアプリで文字化ける

2017年11月24日

環境

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系なんて化石を使うなって話ですね。

今日はこの辺でー

  • B!