php imap - 获取正文并制作纯文本

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19092161/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 18:49:44  来源:igfitidea点击:

php imap - get body and make plain text

phpmysqlemail

提问by user2710234

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

我正在使用 PHP imap 函数从 POP3 邮箱获取电子邮件并将数据插入到 MySQL 数据库中。

Here is the PHP code:

这是PHP代码:

$inbox = imap_open($hostname,$username,$password) or die('Cannot connect: ' . imap_last_error());

$emails = imap_search($inbox,'ALL');


if($emails)
{
    $output = '';

    rsort($emails);

    foreach($emails as $email_number) 
    {
        $header=imap_headerinfo($inbox,$email_number);

        $from = $header->from[0]->mailbox . "@" . $header->from[0]->host;
        $toaddress=$header->toaddress;
        $replyto=$header->reply_to[0]->mailbox."@".$header->reply_to[0]->host;
        $datetime=date("Y-m-d H:i:s",$header->udate);
        $subject=$header->subject;

        //remove the " from the $toaddress
        $toaddress = str_replace('"','',$toaddress);

        echo '<strong>To:</strong> '.$toaddress.'<br>';
        echo '<strong>From:</strong> '.$from.'<br>';
        echo '<strong>Subject:</strong> '.$subject.'<br>';

        //get message body
        $message = (imap_fetchbody($inbox,$email_number,1.1)); 
        if($message == '')
        {
            $message = (imap_fetchbody($inbox,$email_number,1));
        }
}

It works fine, however on some emails in the body I get =in between words, or =20in between words. And other times the emails will just be blank even though they are not blank when sent.

它工作正常,但是在正文中的某些电子邮件中,我=在单词=20之间或单词之间收到。有时,即使发送时电子邮件并非空白,电子邮件也将是空白的。

This only happens when coming from certain emails.

这仅在来自某些电子邮件时发生。

How can I get round this and just make the email completely plain text?

我怎样才能解决这个问题,让电子邮件完全是纯文本的?

回答by aleation

This happens because the emails are normally Quoted-printableencoded. The =is a soft line break and =20is 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.

发生这种情况是因为电子邮件通常是Quoted-printable编码的。这=是一个软换行符,=20是一个空白。我认为,您可以在消息上使用Quoted_printable_decode()以使其正确显示。关于空白电子邮件,我不知道,我需要更多详细信息。

Basically:

基本上

//get message body
$message = quoted_printable_decode(imap_fetchbody($inbox,$email_number,1.1)); 

回答by sumit

$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

内容传输编码:8bit

simply imap_fetchbody is enough.

简单的 imap_fetchbody 就足够了。

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

上面的代码取自为通过 IMAP 从邮箱获取邮件而创建的 cake-php 组件。

回答by Alain Tiemblo

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.

几年前我做了一整节课,当我需要从电子邮件中获取内容时,我仍在使用它。它将帮助您以可读格式获取所有电子邮件正文(有时您有 html 和纯文本),并获取所有附加文件,准备好保存在某处或发送给网站用户。

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.phpHere is the source code.

ImapReader.class.php这是源代码。

<?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.phpHere is the usage sample

ImapReader.demo.php这是使用示例

<?php

require_once("ImapReader.class.php");

$box = new ImapReader('example.com', '143', '[email protected]', '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

享受

回答by amphetkid

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.

如果它是二进制编码的邮件,那么当您尝试将它们插入 mysql 文本字段时,您将收到空白邮件。

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

尝试将每封邮件转换为 UTF-8,然后插入

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

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

回答by Pavel Niedoba

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

我尝试了所有这些答案,但没有一个对我有用。然后我在这个 PHP 页面上点击了第一个用户贡献的注释:

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

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

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

这适用于我的所有情况。顺便说一句,很老的答案。