php imap - get body and make plain text

后端 未结 6 1878
故里飘歌
故里飘歌 2020-12-30 02:18

I am using the PHP imap function to get emails from a POP3 mailbox and insert the data into a MySQL database.

Here is the PHP code:

$inbox = imap_ope         


        
相关标签:
6条回答
  • 2020-12-30 02:43

    Regarding the blank emails, check the encoding of the mail.

    If it is a binary encoded mail then you will get blank mails when you try to insert them into a mysql text field.

    Try shifting every mail to UTF-8 and then insert it

    iconv(mb_detect_encoding($mail_content, mb_detect_order(), true), "UTF-8", $mail_content);

    0 讨论(0)
  • 2020-12-30 02:48
    function getmsg($mbox,$mid) {
        // input $mbox = IMAP stream, $mid = message id
        // output all the following:
        global $charset,$htmlmsg,$plainmsg,$attachments;
        $htmlmsg = $plainmsg = $charset = '';
        $attachments = array();
    
        // HEADER
        $h = imap_header($mbox,$mid);
        // add code here to get date, from, to, cc, subject...
    
        // BODY
        $s = imap_fetchstructure($mbox,$mid);
        if (!$s->parts)  // simple
            getpart($mbox,$mid,$s,0);  // pass 0 as part-number
        else {  // multipart: cycle through each part
            foreach ($s->parts as $partno0=>$p)
                getpart($mbox,$mid,$p,$partno0+1);
        }
    }
    
    function getpart($mbox,$mid,$p,$partno) {
        // $partno = '1', '2', '2.1', '2.1.3', etc for multipart, 0 if simple
        global $htmlmsg,$plainmsg,$charset,$attachments;
    
        // DECODE DATA
        $data = ($partno)?
            imap_fetchbody($mbox,$mid,$partno):  // multipart
            imap_body($mbox,$mid);  // simple
        // Any part may be encoded, even plain text messages, so check everything.
        if ($p->encoding==4)
            $data = quoted_printable_decode($data);
        elseif ($p->encoding==3)
            $data = base64_decode($data);
    
        // PARAMETERS
        // get all parameters, like charset, filenames of attachments, etc.
        $params = array();
        if ($p->parameters)
            foreach ($p->parameters as $x)
                $params[strtolower($x->attribute)] = $x->value;
        if ($p->dparameters)
            foreach ($p->dparameters as $x)
                $params[strtolower($x->attribute)] = $x->value;
    
        // ATTACHMENT
        // Any part with a filename is an attachment,
        // so an attached text file (type 0) is not mistaken as the message.
        if ($params['filename'] || $params['name']) {
            // filename may be given as 'Filename' or 'Name' or both
            $filename = ($params['filename'])? $params['filename'] : $params['name'];
            // filename may be encoded, so see imap_mime_header_decode()
            $attachments[$filename] = $data;  // this is a problem if two files have same name
        }
    
        // TEXT
        if ($p->type==0 && $data) {
            // Messages may be split in different parts because of inline attachments,
            // so append parts together with blank row.
            if (strtolower($p->subtype)=='plain')
                $plainmsg. = trim($data) ."\n\n";
            else
                $htmlmsg. = $data ."<br><br>";
            $charset = $params['charset'];  // assume all parts are same charset
        }
    
        // EMBEDDED MESSAGE
        // Many bounce notifications embed the original message as type 2,
        // but AOL uses type 1 (multipart), which is not handled here.
        // There are no PHP functions to parse embedded messages,
        // so this just appends the raw source to the main message.
        elseif ($p->type==2 && $data) {
            $plainmsg. = $data."\n\n";
        }
    
        // SUBPART RECURSION
        if ($p->parts) {
            foreach ($p->parts as $partno0=>$p2)
                getpart($mbox,$mid,$p2,$partno.'.'.($partno0+1));  // 1.2, 1.2.1, etc.
        }
    }
    

    Reference (First user contributed note): http://php.net/manual/en/function.imap-fetchstructure.php

    0 讨论(0)
  • 2020-12-30 02:51

    I made an entire class some years ago, and I'm still using it when I need to get contents from emails. It will help you fetch all email bodies (sometimes you have html and plain text) in a readable format, and get all attached files, just ready to be saved somewhere or sent to a website user.

    It is not really optimized so on a big mailbox you may have troubles; but the purpose of this class was to access emails in a readable format to put them on a widget of a website. I let you play with the sample below to get how it works.

    ImapReader.class.php Here is the source code.

    <?php
    
    class ImapReader
    {
    
        private $host;
        private $port;
        private $user;
        private $pass;
        private $box;
        private $box_list;
        private $errors;
        private $connected;
        private $list;
        private $deleted;
    
        const FROM = 0;
        const TO = 1;
        const REPLY_TO = 2;
        const SUBJECT = 3;
        const CONTENT = 4;
        const ATTACHMENT = 5;
    
        public function __construct($host = null, $port = '143', $user = null, $pass = null)
        {
            $this->host = $host;
            $this->port = $port;
            $this->user = $user;
            $this->pass = $pass;
            $this->box = null;
            $this->box_list = null;
            $this->errors = array ();
            $this->connected = false;
            $this->list = null;
            $this->deleted = false;
        }
    
        public function __destruct()
        {
            if ($this->isConnected())
            {
                $this->disconnect();
            }
        }
    
        public function changeServer($host = null, $port = '143', $user = null, $pass = null)
        {
            if ($this->isConnected())
            {
                $this->disconnect();
            }
            $this->host = $host;
            $this->port = $port;
            $this->user = $user;
            $this->pass = $pass;
            $this->box_list = null;
            $this->errors = array ();
            $this->list = null;
            return $this;
        }
    
        public function canConnect()
        {
            return (($this->connected == false) && (is_string($this->host)) && (!empty($this->host))
               && (is_numeric($this->port)) && ($this->port >= 1) && ($this->port <= 65535)
               && (is_string($this->user)) && (!empty($this->user)) && (is_string($this->pass)) && (!empty($this->pass)));
        }
    
        public function connect()
        {
            if ($this->canConnect())
            {
                $this->box = @imap_open("{{$this->host}:{$this->port}/imap/ssl/novalidate-cert}INBOX", $this->user,
                      $this->pass);
                if ($this->box !== false)
                {
                    $this->_connected();
                }
                else
                {
                    $this->errors = array_merge($this->errors, imap_errors());
                }
            }
            return $this;
        }
    
        public function boxList()
        {
            if (is_null($this->box_list))
            {
                $list = imap_getsubscribed($this->box, "{{$this->host}:{$this->port}}", "*");
                $this->box_list = array ();
                foreach ($list as $box)
                {
                    $this->box_list[] = $box->name;
                }
            }
            return $this->box_list;
        }
    
        public function fetchAllHeaders($mbox)
        {
            if ($this->isConnected())
            {
                $test = imap_reopen($this->box, "{$mbox}");
                if (!$test)
                {
                    return false;
                }
                $num_msgs = imap_num_msg($this->box);
                $this->list = array ();
                for ($id = 1; ($id <= $num_msgs); $id++)
                {
                    $this->list[] = $this->_fetchHeader($mbox, $id);
                }
                return true;
            }
            return false;
        }
    
        public function fetchSearchHeaders($mbox, $criteria)
        {
            if ($this->isConnected())
            {
                $test = imap_reopen($this->box, "{$mbox}");
                if (!$test)
                {
                    return false;
                }
                $msgs = imap_search($this->box, $criteria);
                if ($msgs)
                {
                    foreach ($msgs as $id)
                    {
                        $this->list[] = $this->_fetchHeader($mbox, $id);
                    }
                }
                return true;
            }
            return false;
        }
    
        public function isConnected()
        {
            return $this->connected;
        }
    
        public function disconnect()
        {
            if ($this->connected)
            {
                if ($this->deleted)
                {
                    imap_expunge($this->box);
                    $this->deleted = false;
                }
                imap_close($this->box);
                $this->connected = false;
                $this->box = null;
            }
            return $this;
        }
    
        /**
         * Took from khigashi dot oang at gmail dot com at php.net
         * with replacement of ereg family functions by preg's ones.
         *
         * @param string $str
         * @return string
         */
        private function _fix($str)
        {
            if (preg_match("/=\?.{0,}\?[Bb]\?/", $str))
            {
                $str = preg_split("/=\?.{0,}\?[Bb]\?/", $str);
                while (list($key, $value) = each($str))
                {
                    if (preg_match("/\?=/", $value))
                    {
                        $arrTemp = preg_split("/\?=/", $value);
                        $arrTemp[0] = base64_decode($arrTemp[0]);
                        $str[$key] = join("", $arrTemp);
                    }
                }
                $str = join("", $str);
            }
    
            if (preg_match("/=\?.{0,}\?Q\?/", $str))
            {
                $str = quoted_printable_decode($str);
                $str = preg_replace("/=\?.{0,}\?[Qq]\?/", "", $str);
                $str = preg_replace("/\?=/", "", $str);
            }
            return trim($str);
        }
    
        private function _connected()
        {
            $this->connected = true;
            return $this;
        }
    
        public function getErrors()
        {
            $errors = $this->errors;
            $this->errors = array ();
            return $errors;
        }
    
        public function count()
        {
            if (is_null($this->list))
            {
                return 0;
            }
            return count($this->list);
        }
    
        public function get($nbr = null)
        {
            if (is_null($nbr))
            {
                return $this->list;
            }
            if ((is_array($this->list)) && (isset($this->list[$nbr])))
            {
                return $this->list[$nbr];
            }
            return null;
        }
    
        public function fetch($nbr = null)
        {
            return $this->_callById('_fetch', $nbr);
        }
    
        private function _fetchHeader($mbox, $id)
        {
            $header = imap_header($this->box, $id);
            if (!is_object($header))
            {
                continue;
            }
            $mail = new stdClass();
            $mail->id = $id;
            $mail->mbox = $mbox;
            $mail->timestamp = (isset($header->udate)) ? ($header->udate) : ('');
            $mail->date = date("d/m/Y H:i:s", (isset($header->udate)) ? ($header->udate) : (''));
            $mail->from = $this->_fix(isset($header->fromaddress) ? ($header->fromaddress) : (''));
            $mail->to = $this->_fix(isset($header->toaddress) ? ($header->toaddress) : (''));
            $mail->reply_to = $this->_fix(isset($header->reply_toaddress) ? ($header->reply_toaddress) : (''));
            $mail->subject = $this->_fix(isset($header->subject) ? ($header->subject) : (''));
            $mail->content = array ();
            $mail->attachments = array ();
            $mail->deleted = false;
            return $mail;
        }
    
        private function _fetch($mail)
        {
            $test = imap_reopen($this->box, "{$mail->mbox}");
            if (!$test)
            {
                return $mail;
            }
            $structure = imap_fetchstructure($this->box, $mail->id);
            if ((!isset($structure->parts)) || (!is_array($structure->parts)))
            {
                $body = imap_body($this->box, $mail->id);
                $content = new stdClass();
                $content->type = 'content';
                $content->mime = $this->_fetchType($structure);
                $content->charset = $this->_fetchParameter($structure->parameters, 'charset');
                $content->data = $this->_decode($body, $structure->type);
                $content->size = strlen($content->data);
                $mail->content[] = $content;
                return $mail;
            }
            else
            {
                $parts = $this->_fetchPartsStructureRoot($mail, $structure);
                foreach ($parts as $part)
                {
                    $content = new stdClass();
                    $content->type = null;
                    $content->data = null;
                    $content->mime = $this->_fetchType($part->data);
                    if ((isset($part->data->disposition))
                       && ((strcmp('attachment', $part->data->disposition) == 0)
                       || (strcmp('inline', $part->data->disposition) == 0)))
                    {
                        $content->type = $part->data->disposition;
                        $content->name = null;
                        if (isset($part->data->dparameters))
                        {
                            $content->name = $this->_fetchParameter($part->data->dparameters, 'filename');
                        }
                        if (is_null($content->name))
                        {
                            if (isset($part->data->parameters))
                            {
                                $content->name = $this->_fetchParameter($part->data->parameters, 'name');
                            }
                        }
                        $mail->attachments[] = $content;
                    }
                    else if ($part->data->type == 0)
                    {
                        $content->type = 'content';
                        $content->charset = null;
                        if (isset($part->data->parameters))
                        {
                            $content->charset = $this->_fetchParameter($part->data->parameters, 'charset');
                        }
                        $mail->content[] = $content;
                    }
                    $body = imap_fetchbody($this->box, $mail->id, $part->no);
                    if (isset($part->data->encoding))
                    {
                        $content->data = $this->_decode($body, $part->data->encoding);
                    }
                    else
                    {
                        $content->data = $body;
                    }
                    $content->size = strlen($content->data);
                }
            }
            return $mail;
        }
    
        private function _fetchPartsStructureRoot($mail, $structure)
        {
            $parts = array ();
            if ((isset($structure->parts)) && (is_array($structure->parts)) && (count($structure->parts) > 0))
            {
                foreach ($structure->parts as $key => $data)
                {
                    $this->_fetchPartsStructure($mail, $data, ($key + 1), $parts);
                }
            }
            return $parts;
        }
    
        private function _fetchPartsStructure($mail, $structure, $prefix, &$parts)
        {
            if ((isset($structure->parts)) && (is_array($structure->parts)) && (count($structure->parts) > 0))
            {
                foreach ($structure->parts as $key => $data)
                {
                    $this->_fetchPartsStructure($mail, $data, $prefix . "." . ($key + 1), $parts);
                }
            }
    
            $part = new stdClass;
            $part->no = $prefix;
            $part->data = $structure;
    
            $parts[] = $part;
        }
    
        private function _fetchParameter($parameters, $key)
        {
            foreach ($parameters as $parameter)
            {
                if (strcmp($key, $parameter->attribute) == 0)
                {
                    return $parameter->value;
                }
            }
            return null;
        }
    
        private function _fetchType($structure)
        {
            $primary_mime_type = array ("TEXT", "MULTIPART", "MESSAGE", "APPLICATION", "AUDIO", "IMAGE", "VIDEO", "OTHER");
            if ((isset($structure->subtype)) && ($structure->subtype) && (isset($structure->type)))
            {
                return $primary_mime_type[(int) $structure->type] . '/' . $structure->subtype;
            }
            return "TEXT/PLAIN";
        }
    
        private function _decode($message, $coding)
        {
            switch ($coding)
            {
                case 2:
                    $message = imap_binary($message);
                    break;
                case 3:
                    $message = imap_base64($message);
                    break;
                case 4:
                    $message = imap_qprint($message);
                    break;
                case 5:
                    break;
                default:
                    break;
            }
            return $message;
        }
    
        private function _callById($method, $data)
        {
            $callback = array ($this, $method);
    
            // data is null
            if (is_null($data))
            {
                $result = array ();
                foreach ($this->list as $mail)
                {
                    $result[] = $this->_callById($method, $mail);
                }
                return $result;
            }
    
            // data is an array
            if (is_array($data))
            {
                $result = array ();
                foreach ($data as $elem)
                {
                    $result[] = $this->_callById($method, $elem);
                }
                return $result;
            }
    
            // data is an object
            if ((is_object($data)) && ($data instanceof stdClass) && (isset($data->id)))
            {
                return call_user_func($callback, $data);
            }
    
            // data is numeric
            if (($this->isConnected()) && (is_array($this->list)) && (is_numeric($data)))
            {
                foreach ($this->list as $mail)
                {
                    if ($mail->id == $data)
                    {
                        return call_user_func($callback, $mail);
                    }
                }
            }
    
            return null;
        }
    
        public function delete($nbr)
        {
            $this->_callById('_delete', $nbr);
            return;
        }
    
        private function _delete($mail)
        {
            if ($mail->deleted == false)
            {
                $test = imap_reopen($this->box, "{$mail->mbox}");
                if ($test)
                {
                    $this->deleted = true;
                    imap_delete($this->box, $mail->id);
                    $mail->deleted = true;
                }
            }
        }
    
        public function searchBy($pattern, $type)
        {
            $result = array ();
            if (is_array($this->list))
            {
                foreach ($this->list as $mail)
                {
                    $match = false;
                    switch ($type)
                    {
                        case self::FROM:
                            $match = $this->_match($mail->from, $pattern);
                            break;
                        case self::TO:
                            $match = $this->_match($mail->to, $pattern);
                            break;
                        case self::REPLY_TO:
                            $match = $this->_match($mail->reply_to, $pattern);
                            break;
                        case self::SUBJECT:
                            $match = $this->_match($mail->subject, $pattern);
                            break;
                        case self::CONTENT:
                            foreach ($mail->content as $content)
                            {
                                $match = $this->_match($content->data, $pattern);
                                if ($match)
                                {
                                    break;
                                }
                            }
                            break;
                        case self::ATTACHMENT:
                            foreach ($mail->attachments as $attachment)
                            {
                                $match = $this->_match($attachment->name, $pattern);
                                if ($match)
                                {
                                    break;
                                }
                            }
                            break;
                    }
                    if ($match)
                    {
                        $result[] = $mail;
                    }
                }
            }
            return $result;
        }
    
        private function _nmatch($string, $pattern, $a, $b)
        {
            if ((!isset($string[$a])) && (!isset($pattern[$b])))
            {
                return 1;
            }
    
            if ((isset($pattern[$b])) && ($pattern[$b] == '*'))
            {
                if (isset($string[$a]))
                {
                    return ($this->_nmatch($string, $pattern, ($a + 1), $b) + $this->_nmatch($string, $pattern, $a, ($b + 1)));
                }
                else
                {
                    return ($this->_nmatch($string, $pattern, $a, ($b + 1)));
                }
            }
    
            if ((isset($string[$a])) && (isset($pattern[$b])) && ($pattern[$b] == '?'))
            {
                return ($this->_nmatch($string, $pattern, ($a + 1), ($b + 1)));
            }
    
            if ((isset($string[$a])) && (isset($pattern[$b])) && ($pattern[$b] == '\\'))
            {
                if ((isset($pattern[($b + 1)])) && ($string[$a] == $pattern[($b + 1)]))
                {
                    return ($this->_nmatch($string, $pattern, ($a + 1), ($b + 2)));
                }
            }
    
            if ((isset($string[$a])) && (isset($pattern[$b])) && ($string[$a] == $pattern[$b]))
            {
                return ($this->_nmatch($string, $pattern, ($a + 1), ($b + 1)));
            }
    
            return 0;
        }
    
        private function _match($string, $pattern)
        {
            return $this->_nmatch($string, $pattern, 0, 0);
        }
    
    }
    

    ImapReader.demo.php Here is the usage sample

    <?php
    
    require_once("ImapReader.class.php");
    
    $box = new ImapReader('example.com', '143', 'somebody@example.com', 'xxxxxxxxxxxx');
    $box
       ->connect()
       ->fetchAllHeaders()
    ;
    
    echo $box->count() . " emails in mailbox\n";
    for ($i = 0; ($i < $box->count()); $i++)
    {
        $msg = $box->get($i);
        echo "Reception date : {$msg->date}\n";
        echo "From : {$msg->from}\n";
        echo "To : {$msg->to}\n";
        echo "Reply to : {$msg->from}\n";
        echo "Subject : {$msg->subject}\n";
        $msg = $box->fetch($msg);
        echo "Number of readable contents : " . count($msg->content) . "\n";
        foreach ($msg->content as $key => $content)
        {
            echo "\tContent  " . ($key + 1) . " :\n";
            echo "\t\tContent type : {$content->mime}\n";
            echo "\t\tContent charset : {$content->charset}\n";
            echo "\t\tContent size : {$content->size}\n";
        }
        echo "Number of attachments : " . count($msg->attachments) . "\n";
        foreach ($msg->attachments as $key => $attachment)
        {
            echo "\tAttachment " . ($key + 1) . " :\n";
            echo "\t\tAttachment type : {$attachment->type}\n";
            echo "\t\tContent type : {$attachment->mime}\n";
            echo "\t\tFile name : {$attachment->name}\n";
            echo "\t\tFile size : {$attachment->size}\n";
        }
        echo "\n";
    }
    
    echo "Searching '*Bob*' ...\n";
    $results = $box->searchBy('*Bob*', ImapReader::FROM);
    foreach ($results as $result)
    {
        echo "\tMatched: {$result->from} - {$result->date} - {$result->subject}\n";
    }
    

    Enjoy

    0 讨论(0)
  • 2020-12-30 02:52

    This happens because the emails are normally Quoted-printable encoded. The = is a soft line break and =20 is a white space. I think, you could use quoted_printable_decode() on the message so it shows correctly. About the blank emails, I don't know, I would need more details.

    Basically:

    //get message body
    $message = quoted_printable_decode(imap_fetchbody($inbox,$email_number,1.1)); 
    
    0 讨论(0)
  • 2020-12-30 02:52
    $data = imap_fetchbody($this->imapStream, $Part->uid, $Part->path, FT_UID | FT_PEEK);
    if ($Part->format === 'quoted-printable' && $data) {
        $data = quoted_printable_decode($data);
    }
    

    This is required for mails with

    Content-Transfer-Encoding: quoted-printable

    But for mails with

    Content-Transfer-Encoding: 8bit

    simply imap_fetchbody is enough.

    Above code was taken from a cake-php component created for fetching mails from mail boxes throgh IMAP.

    0 讨论(0)
  • 2020-12-30 03:00

    I tried all this answers, but neither one worked for me. Then I hit first user contributed note on this PHP page:

    http://php.net/manual/en/function.imap-fetchstructure.php

    and this works for all my cases. Quite old answer btw.

    0 讨论(0)
提交回复
热议问题