~がメールで消える

~がメールで消える

- Haruhiko Okumura の投稿
返信数: 9
メール配送にISO-2022-JPを指定すると,
~(U+FF5E,fullwidth tilde)
がメール配送で消えるという問題があったようです。
〜(U+301C,wave dash)
なら大丈夫です。

対応策として,lib/textlib.class.php の冒頭のiconvとmbstringの順序を逆にしました。
Haruhiko Okumura への返信

Re: ~がメールで消える

- Tatsuya Shirai の投稿
当方の環境でも全く同じ現象が発生しました.
奥村先生のご指摘の通り,以下のようにlib/textlib.class.phpを修正し,正しく「~」が送信されることも確認しました.

/// If mbstring is available, lets Typo3 library use it for convert
// if (extension_loaded('iconv')) {
if (extension_loaded('mbstring')) {
// $GLOBALS['TYPO3_CONF_VARS']['SYS']['t3lib_cs_convMethod'] = 'iconv';
$GLOBALS['TYPO3_CONF_VARS']['SYS']['t3lib_cs_convMethod'] = 'mbstring';
/// Else if ICONV is available, lets Typo3 library use it
// } else if (extension_loaded('mbstring')) {
} else if (extension_loaded('iconv')) {
// $GLOBALS['TYPO3_CONF_VARS']['SYS']['t3lib_cs_convMethod'] = 'mbstring';
$GLOBALS['TYPO3_CONF_VARS']['SYS']['t3lib_cs_convMethod'] = 'iconv';
Haruhiko Okumura への返信

Re: ~がメールで消える

- Haruhiko Okumura の投稿
今気づいたのですが,mbstringを使うと,phpmailerからのメールの宛先が To: Array <xxx@yyy.zzz> のように Array となるようです。どうしてかはわかりません。
Haruhiko Okumura への返信

Re: ~がメールで消える

- Tatsuya Shirai の投稿

全く気付かなかったですね.
mb_send_mail()を使用しているのではなく,mail()を使用していそうですね.

lib/phpmailer/class.phpmailer.php
のfunction Send()が入り口になっているようです.

メール送信にsendimailを使用するか,smtpサーバを使用するか,
// Choose the mailer
switch($this->Mailer)
{
case "sendmail":
$result = $this->SendmailSend($header, $body);
break;
case "mail":
$result = $this->MailSend($header, $body);
break;
case "smtp":
$result = $this->SmtpSend($header, $body);
break;
default:
$this->SetError($this->Mailer . $this->Lang("mailer_not_supported"));
$result = false;
break;
}
切り分けている.当方はsmtpを使用していますので,SmtpSend()を使用しているはずです.

送信先は,Recipientで,$to, $cc, $bccのようなArray()に入れていますので,これの処理が正しく機能していないようですね.
// Attempt to send attach all recipients
for($i = 0; $i < count($this->to); $i++)
{
if(!$this->smtp->Recipient($this->to[$i][0]))
$bad_rcpt[] = $this->to[$i][0];
}
for($i = 0; $i < count($this->cc); $i++)
{
if(!$this->smtp->Recipient($this->cc[$i][0]))
$bad_rcpt[] = $this->cc[$i][0];
}
for($i = 0; $i < count($this->bcc); $i++)
{
if(!$this->smtp->Recipient($this->bcc[$i][0]))
$bad_rcpt[] = $this->bcc[$i][0];
}

ちなにみ$to, $cc, $bccはこのように初期化.
function ClearAllRecipients() {
$this->to = array();
$this->cc = array();
$this->bcc = array();
}

Recipientの元になるアドレスと名前は,
function AddAddress($address, $name = "") {
$cur = count($this->to);
$this->to[$cur][0] = trim($address);
$this->to[$cur][1] = $name;
}
で配列に入れており,この$nameが"Array()"ということ?
Tatsuya Shirai への返信

Re: ~がメールで消える

- Tatsuya Shirai の投稿
ダラダラと書いてすみません.

$toはarray()で,$to[i][0] がemailアドレスで,$to[i][1]が差出人名です.
lib/phpmailer/class.phpmailer.php中の,
function AddrFormat($addr) {
if(empty($addr[1]))
$formatted = $addr[0];
else
{
$formatted = $this->EncodeHeader($addr[1], 'phrase') . " <" .
$addr[0] . ">";
}

return $formatted;
}

この辺りが非常に怪しい.ここでいう$addrは$to[i]ですので,$addr[0]がemailアドレスで,$addr[1]が差出人名です.もし差出人名が不明の場合は xxx@yyy.zzz のみ,差出人名が入力されているならば,白井達也<xxx@yyy.zzz>の形式にして返す関数です.EncodeHeader()がミソか,それともそれ以前に$addr[1]の中身がおかしいのか,という気がします.

しかし,From:は正しく機能していることから考えると,(もしAddrFormat()がFrom:に対しても使用されているならば)ここでは無いかも知れません.

いま確認したところ,ここが(間接的ではあれ)関係しているのは事実ですね.赤で示した行を,
$formatted = $this->EncodeHeader($addr[1], 'phrase') . " <" .
から
$formatted = "TEST" . " <" .
とすると,送信されたメールの送信者(From:),受信者(To:)共に名前が"TEST"となりました.ちなみに,届いたメールのヘッダーは,
To: TEST <shirai.shirai@nifty.com>
From: TEST <shirai@mech.suzuka-ct.ac.jp>
こうなりました.Fromは正しくは,”白井達也”ですし,細工を加えなければ,
To: Array <shirai.shirai@nifty.com>
From: 白井 達也 <shirai@mech.suzuka-ct.ac.jp>
この通りですので,マルチバイトになった結果,EncodeHeader()が誤動作しているというよりも,そもそも$to[0][1]に正しく名前が入っていないようです.


ちなみに,AddFormat()は,function AddrAppend()で呼ばれています.
そしてAddrAppend()はfunction CreateHeader()で呼ばれているようです.
CreateHeader()はSend()から呼ばれている.
ポイントとなるのは,$this->to? どこで代入されているのだろうか.
lib/phpmailer/class.phpmailer.phpの中では無いですね.

Tatsuya Shirai への返信

Re: ~がメールで消える

- Tatsuya Shirai の投稿
lib/moodlelib.phpのfunction email_to_user()の中ほど,
foreach ($mail->to as $key => $to) {
$mail->to[$key][1] = $textlib->convert($to, 'utf-8', $mail->CharSet); //To Names
}
ここがかなり可能性として濃厚ですね.$mail->to[$key][1] = "This is Test";とすると,
To: This is Test <shirai.shirai@nifty.com>
From: 白井 達也 <shirai@mech.suzuka-ct.ac.jp>
のようになりました.$textlib->convert()が"Array"を返す,ということがあるのでしょうか???

調べてみたところ,
textlibクラスのinstanceの中の,convert()は,実際にはtypo3csのconv()を使用していますね.
lib/typo3/class.t3lib_cs.phpだとすると,その中にあるfunction conv()は,
function conv($str,$fromCS,$toCS,$useEntityForNoChar=0) {
if ($fromCS==$toCS) return $str;

// PHP-libs don't support fallback to SGML entities, but UTF-8 handles everything
if ($toCS=='utf-8' || !$useEntityForNoChar) {
switch($GLOBALS['TYPO3_CONF_VARS']['SYS']['t3lib_cs_convMethod']) {
case 'mbstring':
$conv_str = mb_convert_encoding($str,$toCS,$fromCS);
if (false !== $conv_str) return $conv_str; // returns false for unsupported charsets
break;

case 'iconv':
$conv_str = iconv($fromCS,$toCS.'//IGNORE',$str);
if (false !== $conv_str) return $conv_str;
break;

case 'recode':
$conv_str = recode_string($fromCS.'..'.$toCS,$str);
if (false !== $conv_str) return $conv_str;
break;
}
// fallback to TYPO3 conversion
}

if ($fromCS!='utf-8') $str=$this->utf8_encode($str,$fromCS);
if ($toCS!='utf-8') $str=$this->utf8_decode($str,$toCS,$useEntityForNoChar);
return $str;
}

青い部分は,まさに今回,「~」問題のための変更の影響が生じる箇所で,以前は"iconv"のcaseが使用されていたのが,"mbstring"を使用するように変更されたということで,ズバリ,元の修正の箇所まで辿りつきました.しかし,なぜ$to[i][[1]が"Array"になるのかは...分かりません.

よーく,もう一度,moodlelib.phpのemail_to_user()を見てみたところ,
$mail->FromName = $textlib->convert($mail->FromName, 'utf-8', $mail->CharSet); //From Name
のように,差出人の名前もtextlib->convert()を使用していますので,もしtypo3_csに問題があるならば,こちらもおかしくなるはずですね.そう考えるとこれも原因では無さそうです.やはり $mail->to[$key][1]が正しく代入されていない公算が高いです.
Tatsuya Shirai への返信

Re: ~がメールで消える

- Tatsuya Shirai の投稿
発見しました.
バグです...

lib/moodlelib.phpのfunction email_to_user()の中ほど,moodle1.8.1+ですと,3465行目.

if (in_array($charset, $charsets)) {
/// Save the new mail charset
$mail->CharSet = $charset;
/// And convert some strings
$mail->FromName = $textlib->convert($mail->FromName, 'utf-8', $mail->CharSet); //From Name
foreach ($mail->ReplyTo as $key => $rt) { //ReplyTo Names
// $mail->ReplyTo[$key][1] = $textlib->convert($rt, 'utf-8', $mail->CharSet);
$mail->ReplyTo[$key][1] = $textlib->convert($rt[1], 'utf-8', $mail->CharSet);
}
$mail->Subject = $textlib->convert($mail->Subject, 'utf-8', $mail->CharSet); //Subject
foreach ($mail->to as $key => $to) {
// $mail->to[$key][1] = $textlib->convert($to, 'utf-8', $mail->CharSet); //To Names
$mail->to[$key][1] = $textlib->convert($to[1], 'utf-8', $mail->CharSet); //To Names
}
$mail->Body = $textlib->convert($mail->Body, 'utf-8', $mail->CharSet); //Body
$mail->AltBody = $textlib->convert($mail->AltBody, 'utf-8', $mail->CharSet); //Subject
}
これです.$toは配列です.$mail->to[i][j]をforeach()で分割したものが$toですので,$to[0]が電子メールアドレス,$to[1]が差出人名です.$to自体が配列ですから,それをmb_string_convert()したら"Array"と言われても不思議ではないですね.直接関係ありませんが,ReplyToも同じバグを抱えています(上の修正箇所).moodelTrackerにも報告しておきます.

Tatsuya Shirai への返信

Re: ~がメールで消える

- Tatsuya Shirai の投稿
まだ捨てていなかったゴミ箱のメールを調べてみると,
7月3日以前は,
To: shirai@mech.suzuka-ct.ac.jp
From: mechMoodle <moodle@mech.suzuka-ct.ac.jp>
のようにTo:に差出人名がそもそも入っていませんでした.
iconvからmbstringに変えた後は,
To: Array <shirai@mech.suzuka-ct.ac.jp>
From: mechMoodle <moodle@mech.suzuka-ct.ac.jp>
となっています.これはtypo3で使用している文字コード変換関数が,
iconv用からmbstring用に変ったことに起因しているのでしょうね.mb_convert_encoding()は引数にArray()を受け取ると"Array"を返すように機能が強化されているということであれば,納得です.mbstringよりもiconvを優先する環境では差出人名が表示されないだけで,気付いていなかった,つまり,もしかしたかなり古いバグだったのではないでしょうか.これはマルチバイト環境でしか発生しないバグですし.


Tatsuya Shirai への返信

Re: ~がメールで消える

- Haruhiko Okumura の投稿
どうもありがとうございます。m(_ _)m
うちのほうもさっそく直しました。

P.S. SSS2007のMoodle講習会,よろしくお願いいたします。m(_ _)m