【PHP】Zend_Mailを使ってメールを受信する(POP3)(日本語対応)

Zend FrameworkZend_Mailを使って、メールの受信を実装したときのメモ。

Zend_MailはGoogle先生に聞いてみると、ソースをいじらないと日本語に対応できないというお答えが返ってくるので、ちょっと嫌な感じはしたけど、実際やってみたらソースに手を加えずに受信も送信もできた。

Zend Frameworkのバージョンは1.9.2

メール受信するサンプルコードは次のような感じ。

$mail = new Zend_Mail_Storage_Pop3(array('host'     => 'localhost',
                                         'user'     => 'test',
                                         'password' => 'test'));

echo $mail->countMessages() . " messages found\n";
foreach ($mail as $message) {
    echo "Mail from '{$message->from}': {$message->subject}\n";
}

この辺は公式マニュアルを読んだ方が分かりやすい。

件名が文字化けするのは内部エンコードに問題があるらしいので、次のような感じでデコードする。

    /**
     * メールの件名をdecodeする
     *
     * @param  string $sSubject エンコードされた件名
     * @param  string $sEncode  最後にエンコードする文字コード
     * @return string           デコードした件名
     */
    public static function decodeSubject($sSubject, $sEncode = 'UTF-8')
    {
        $sReturn = '';
        //内部エンコーディングをJISにしないと文字化けする
        $sTemp = mb_internal_encoding();
        mb_internal_encoding('JIS');
        $sReturn = mb_decode_mimeheader($sSubject);
        mb_internal_encoding($sTemp);
        //指定した文字コードでエンコードし直す
        if (strlen($sEncode) > 0) {
            $sReturn = mb_convert_encoding($sReturn, $sEncode, 'JIS');
        }
        return $sReturn;
    }

メール本文を取得するときは次のような感じ。

    /**
     * メールの本文を取得(decode)する
     *
     * @param  object $objMessage Zend_Mail_Message
     * @param  string $sEncode    最後にエンコードする文字コード
     * @return string             デコードした本文
     */
    public static function getContent($objMessage, $sEncode = 'UTF-8')
    {
        $sReturn = '';
        $iCount = $objMessage->countParts();
        if ($iCount > 0) {
            for ($i=1; $i<=$iCount; $i++ ){
                $objPart = $objMessage->getPart($i);
                // テキスト部分のみ抽出する
                if (strtok($objPart->contentType, ';') == 'text/plain')  {
                    $sReturn = $objPart->getContent();
                    break;
                }
            }
        } else {
            // テキスト部分のみ抽出する(softbank携帯は件名と画像だけの場合Multipartにならない場合がある)
            if (strtok($objMessage->contentType, ';') == 'text/plain')  {
                $sReturn = $objMessage->getContent();
            }
        }
        $sReturn = mb_convert_encoding($sReturn, $sEncode, 'ISO-2022-JP');
        return $sReturn;
    }

from句からメールアドレスだけを取り出すときはPEARのMailパッケージに含まれているRFC822を使うと簡単にできるらしい。

こんな感じ。

    /**
     * メールアドレスを解析して生のメールアドレス配列で返す
     *
     * @param  string $sAddress メールアドレス
     * @return array            メールアドレスを格納した配列
     */
    public static function getAddressList($sAddress)
    {
        $aReturn = array();
        $aList = Mail_RFC822::parseAddressList($sAddress);
        foreach ($aList as $objItem) {
            $aReturn[] = $objItem->mailbox . '@' . $objItem->host;
        }
        return $aReturn;
    }

メールに添付されている画像を抜き出すのも作ったけど、それはまた今度。

次回はZend_Mailを使ってメールを送信。

ちなみにメールサーバーにメールがあるかどうかはtelnetで接続して、コマンドを発行すれば分かる。詳細は前の記事を参考に。

よく使うpop3コマンドは

user <ユーザーアカウント>
pass <パスワード>
list
top 1 10
dele 1
quit

listでメールボックスの一覧を表示して、topコマンドで先頭の10行を表示。deleコマンドはメールの削除。

 

<2009/10/27 追記>
quoted_printable_decodeで受信したメッセージをデコードしてたけど、いらないみたい。