парсинг сырой электронной почты в php

Я ищу хороший / рабочий / простой в использовании php-код для разбора сырой электронной почты на части.

Я написал пару решений для грубой силы, но каждый раз, когда приходит одно небольшое изменение / header / space / что-то, и весь мой синтаксический анализатор терпит неудачу, и проект разваливается.

И прежде чем я укажу на PEAR / PECL, мне нужен реальный код. У моего хоста есть какая-то винтовая конфигурация или что-то в этом роде, я никогда не смогу заставить .so правильно построить. Если я получаю .so, какое-то различие в path / environment / php.ini не всегда делает его доступным (apache против cron против cli).

О, и еще одна вещь, я анализирую необработанный текст электронной почты, НЕ POP3 и НЕ IMAP. Он передаётся в скрипт php через перенаправление электронной почты .qmail.

Я не ожидаю, что SOF напишет это для меня, я ищу некоторые советы / отправные точки для того, чтобы сделать это «правильно». Это одна из тех «колесных» проблем, которые, я знаю, уже решены.

15.08.2008 23:50:17
14 ОТВЕТОВ
РЕШЕНИЕ

Что вы надеетесь закончить в конце? Тело, субъект, отправитель, вложение? Вы должны потратить некоторое время с RFC2822, чтобы понять формат почты, но вот самые простые правила для правильно сформированной электронной почты:

HEADERS\n
\n
BODY

То есть первая пустая строка (двойной перевод строки) - это разделитель между заголовками и телом. Заголовок выглядит так:

HSTRING:HTEXT

HSTRING всегда начинается в начале строки и не содержит пробелов или двоеточий. HTEXT может содержать широкий спектр текста, включая переводы строк, если за символом перевода строки следует пробел.

«ТЕЛО» - это на самом деле любые данные, которые следуют за первым двойным переводом строки. (Существуют разные правила, если вы отправляете почту через SMTP, но обрабатывая ее по каналу, вам не нужно об этом беспокоиться).

Итак, в очень простых терминах RFC822 1982 года электронное письмо выглядит так:

HEADER: HEADER TEXT
HEADER: MORE HEADER TEXT
  INCLUDING A LINE CONTINUATION
HEADER: LAST HEADER

THIS IS ANY
ARBITRARY DATA
(FOR THE MOST PART)

Большинство современных электронных писем более сложны, чем это. Заголовки могут быть закодированы для кодировок или слов MIME RFC2047 , или тонны других вещей, о которых я сейчас не думаю. Тела действительно трудно накатить свой собственный код в эти дни, если вы хотите, чтобы они были значимыми. Почти вся электронная почта, создаваемая MUA, будет закодирована в MIME . Это может быть uuencoded текст, это может быть html, это может быть uuencoded Excel таблица.

Я надеюсь, что это поможет создать основу для понимания некоторых элементарных элементов электронной почты. Если вы предоставите больше информации о том, что вы пытаетесь сделать с данными, я (или кто-то еще) мог бы предоставить лучшее направление.

23
16.08.2008 02:18:11

да, я смог написать базовый парсер, основанный на этом rfc и некоторых других базовых уроках. но это множественные вложенные границы пантомимы, которые продолжают портить меня.

я узнал, что MMS (не SMS) сообщения, отправленные с моего телефона, являются просто стандартными электронными письмами, поэтому у меня есть система, которая читает входящую электронную почту, проверяет от (чтобы разрешить только с моего телефона) и использует часть тела для запуска другого Команды на моем сервере. своего рода пульт дистанционного управления по электронной почте.

Поскольку система предназначена для отправки изображений, она имеет множество различных кодированных частей. часть mms.smil.txt, text / plain (которая бесполезна, просто говорит «это html-сообщение»), часть application / smil (часть, которую телефон будет воспринимать), часть text / html с рекламой для моего оператора, затем с моим сообщением, но все обернуто в HTML, затем, наконец, вложение текстового файла с моим обычным сообщением (это часть, которую я использую) (если я помещаю изображение в качестве вложения в сообщение, оно помещается в вложение 1, закодировано в base64, тогда моя часть текста прикреплена как вложение 2)

у меня он работал с точным почтовым форматом от моего оператора, но когда я пропустил сообщение с чьего-либо телефона через него, он потерпел неудачу целой кучей жалких способов.

У меня есть другие проекты, на которые я хотел бы расширить эту систему команд phone-> mail-> parse->, но мне нужно иметь стабильный / твердый / универсальный синтаксический анализатор, чтобы использовать разные части почты для его использования.

моей конечной целью было бы иметь функцию, в которую я мог бы кормить необработанную почту, и получить большой массив с ассоциативными подмассивами заголовков пар var: val и один для основного текста в виде целой строки

чем больше и больше я ищу в этом, тем больше я нахожу одно и то же: гигантские, слишком развитые пакеты обработки почты, которые делают все под солнцем, что связано с почтой, или бесполезные (для меня в этом проекте) учебники.

я думаю, что мне придется прикусить пулю и просто осторожно написать что-нибудь самому себе.

0
16.08.2008 05:09:11

Вы, вероятно, не будете иметь большого удовольствия от написания собственного парсера MIME. Причина, по которой вы обнаруживаете «чрезмерно развитые пакеты обработки почты», заключается в том, что MIME - это действительно сложный набор правил / форматов / кодировок. Части MIME могут быть рекурсивными, что является частью веселья. Я думаю, что вам лучше всего написать лучший обработчик MIME, который вы можете, проанализировать сообщение, выбросить все, что не является text / plain или text / html, а затем заставить команду во входящей строке иметь префикс COMMAND: или что-то подобное так что вы можете найти его в грязи. Если вы начинаете с таких правил, у вас есть неплохая возможность работать с новыми провайдерами, но вы должны быть готовы настроить, если придет новый провайдер (или, черт возьми, если ваш нынешний провайдер решит изменить их архитектуру обмена сообщениями).

1
16.08.2008 16:06:14

Я не уверен, что это поможет вам - надеюсь, что это так - но это, безусловно, поможет другим, заинтересованным в получении дополнительной информации об электронной почте. Маркус Боинтон сделал одну из лучших презентаций под названием «Mail () и жизнь после Mail ()» на конференции PHP в Лондоне в марте этого года. Слайды и MP3 доступны онлайн. Он говорит с определенным авторитетом, много занимаясь электронной почтой и PHP.

Я считаю, что вы находитесь в мире боли, пытаясь написать действительно общий анализатор.

РЕДАКТИРОВАТЬ - файлы, кажется, были удалены на сайте PHP Лондон; нашел слайды на собственном сайте Маркуса : Часть 1 Часть 2 Хотя я нигде не видел MP3

1
15.08.2011 12:46:08

Есть функции Mailparse, которые вы можете попробовать: http://php.net/manual/en/book.mailparse.php , но не в php conf по умолчанию.

2
5.11.2010 14:36:40

Разбор электронной почты в PHP не является невозможной задачей. Я имею в виду, что вам не нужна команда инженеров, чтобы сделать это; это достижимо как личность. Действительно самая сложная часть, которую я нашел, - это создание FSM для анализа результата IMAP BODYSTRUCTURE. Нигде в Интернете я не видел этого, поэтому я написал свой собственный. Моя процедура в основном создает массив вложенных массивов из выходных данных команды, а глубина, в которой находится массив, приблизительно соответствует номеру (-ам) детали, необходимым для выполнения поиска. Таким образом, он обрабатывает вложенные структуры MIME довольно изящно.

Проблема в том, что стандартные функции PHP imap_ * по умолчанию не обеспечивают особой детализации ... поэтому мне пришлось открыть сокет для порта IMAP и написать функции для отправки и получения необходимой информации (IMAP FETCH 1 BODY.PEEK [1.2] например), и это включает в себя просмотр документации RFC.

Вам предоставляется кодировка данных (цитируемая для печати, base64, 7bit, 8bit и т. Д.), Длина сообщения, тип содержимого и т. Д .; для вложений, текста, HTML и т. д. Возможно, вам придется выяснить нюансы вашего почтового сервера, так как не все поля всегда заполнены на 100%.

Драгоценный камень - это FSM ... если у вас есть опыт работы с Comp Sci, это может быть действительно забавно (так как они заключаются в том, что скобки не являются обычной грамматикой;)); в противном случае это будет борьба и / или результат в некрасивом коде с использованием традиционных методов. Также вам нужно время!

Надеюсь это поможет!

1
20.11.2010 20:49:47

Я соединил это вместе, некоторый код не мой, но я не знаю, откуда он взялся ... Позже я принял более надежный «MimeMailParser», но это работает хорошо, я передаю свою электронную почту по умолчанию на него с помощью cPanel, и это работает большой.

#!/usr/bin/php -q
<?php
// Config
$dbuser = 'emlusr';
$dbpass = 'pass';
$dbname = 'email';
$dbhost = 'localhost';
$notify= 'services@.com'; // an email address required in case of errors
function mailRead($iKlimit = "") 
    { 
        // Purpose: 
        //   Reads piped mail from STDIN 
        // 
        // Arguements: 
        //   $iKlimit (integer, optional): specifies after how many kilobytes reading of mail should stop 
        //   Defaults to 1024k if no value is specified 
        //     A value of -1 will cause reading to continue until the entire message has been read 
        // 
        // Return value: 
        //   A string containing the entire email, headers, body and all. 

        // Variable perparation         
            // Set default limit of 1024k if no limit has been specified 
            if ($iKlimit == "") { 
                $iKlimit = 1024; 
            } 

            // Error strings 
            $sErrorSTDINFail = "Error - failed to read mail from STDIN!"; 

        // Attempt to connect to STDIN 
        $fp = fopen("php://stdin", "r"); 

        // Failed to connect to STDIN? (shouldn't really happen) 
        if (!$fp) { 
            echo $sErrorSTDINFail; 
            exit(); 
        } 

        // Create empty string for storing message 
        $sEmail = ""; 

        // Read message up until limit (if any) 
        if ($iKlimit == -1) { 
            while (!feof($fp)) { 
                $sEmail .= fread($fp, 1024); 
            }                     
        } else { 
            while (!feof($fp) && $i_limit < $iKlimit) { 
                $sEmail .= fread($fp, 1024); 
                $i_limit++; 
            }         
        } 

        // Close connection to STDIN 
        fclose($fp); 

        // Return message 
        return $sEmail; 
    }  
$email = mailRead();

// handle email
$lines = explode("\n", $email);

// empty vars
$from = "";
$subject = "";
$headers = "";
$message = "";
$splittingheaders = true;
for ($i=0; $i < count($lines); $i++) {
    if ($splittingheaders) {
        // this is a header
        $headers .= $lines[$i]."\n";

        // look out for special headers
        if (preg_match("/^Subject: (.*)/", $lines[$i], $matches)) {
            $subject = $matches[1];
        }
        if (preg_match("/^From: (.*)/", $lines[$i], $matches)) {
            $from = $matches[1];
        }
        if (preg_match("/^To: (.*)/", $lines[$i], $matches)) {
            $to = $matches[1];
        }
    } else {
        // not a header, but message
        $message .= $lines[$i]."\n";
    }

    if (trim($lines[$i])=="") {
        // empty line, header section has ended
        $splittingheaders = false;
    }
}

if ($conn = @mysql_connect($dbhost,$dbuser,$dbpass)) {
  if(!@mysql_select_db($dbname,$conn))
    mail($email,'Email Logger Error',"There was an error selecting the email logger database.\n\n".mysql_error());
  $from    = mysql_real_escape_string($from);
  $to    = mysql_real_escape_string($to);
  $subject = mysql_real_escape_string($subject);
  $headers = mysql_real_escape_string($headers);
  $message = mysql_real_escape_string($message);
  $email   = mysql_real_escape_string($email);
  $result = @mysql_query("INSERT INTO email_log (`to`,`from`,`subject`,`headers`,`message`,`source`) VALUES('$to','$from','$subject','$headers','$message','$email')");
  if (mysql_affected_rows() == 0)
    mail($notify,'Email Logger Error',"There was an error inserting into the email logger database.\n\n".mysql_error());
} else {
  mail($notify,'Email Logger Error',"There was an error connecting the email logger database.\n\n".mysql_error());
}
?>
5
7.06.2013 14:50:48
Мне нравится этот подход, и он работает довольно хорошо по большей части. Однако при устранении неполадок я заметил, что он не будет обрабатывать перенос заголовков, например, если адреса to: используют более одной строки.
Jason Silver 27.03.2017 16:05:33

Попробуйте анализатор электронной почты PHP Plancake: https://github.com/plancake/official-library-php-email-parser

Я использовал его для своих проектов. Он отлично работает, это всего лишь один класс и с открытым исходным кодом.

19
15.05.2011 21:56:52
отличная библиотека дан! как избавиться от символов типа = 23 и = 40?
cwd 4.04.2013 01:35:14
@cwd это кодировка текста в кавычках, я думаю.
Jeyanth Kumar 18.06.2013 10:05:56
чтобы избавиться от = 23 и т. д., вам нужно использовать quoted_printable_decodeфункцию.
Alex W 18.08.2015 18:57:12
Могу подтвердить, что Plancake является мусором. Судя по всему, плохо обрабатывает электронные письма, отправленные из Outlook. Не обновлялся пять лет.
rgbflawed 18.04.2017 18:37:44

Почтовый код Pear lib lib_mimeDecode написан на простом PHP, который вы можете увидеть здесь: Источник Mail_mimeDecode

2
31.01.2017 17:36:30
chiliNUT 23.12.2015 22:58:44

Эта библиотека работает очень хорошо:

http://www.phpclasses.org/package/3169-PHP-Decode-MIME-e-mail-messages.html

0
8.11.2011 21:27:33
-1 Вам нужно зарегистрироваться на этом сайте, чтобы получить его, тогда документация непонятна. Можете ли вы привести пример, как его использовать хотя бы? Ответ планета выглядит лучше, чем этот.
cwd 4.04.2013 01:23:47

Существует библиотека для разбора необработанных сообщений электронной почты в массив php - http://flourishlib.com/api/fMailbox#parseMessage .

Статический метод parseMessage () можно использовать для анализа полного сообщения электронной почты MIME в том же формате, который возвращает fetchMessage (), за вычетом ключа uid.

$ parsed_message = fMailbox :: parseMessage (file_get_contents ('/ path / to / email'));

Вот пример разобранного сообщения:

array(
    'received' => '28 Apr 2010 22:00:38 -0400',
    'headers'  => array(
        'received' => array(
            0 => '(qmail 25838 invoked from network); 28 Apr 2010 22:00:38 -0400',
            1 => 'from example.com (HELO ?192.168.10.2?) (example) by example.com with (DHE-RSA-AES256-SHA encrypted) SMTP; 28 Apr 2010 22:00:38 -0400'
        ),
        'message-id' => '<4BD8E815.1050209@flourishlib.com>',
        'date' => 'Wed, 28 Apr 2010 21:59:49 -0400',
        'from' => array(
            'personal' => 'Will Bond',
            'mailbox'  => 'tests',
            'host'     => 'flourishlib.com'
        ),
        'user-agent'   => 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.9) Gecko/20100317 Thunderbird/3.0.4',
        'mime-version' => '1.0',
        'to' => array(
            0 => array(
                'mailbox' => 'tests',
                'host'    => 'flourishlib.com'
            )
        ),
        'subject' => 'This message is encrypted'
    ),
    'text'      => 'This message is encrypted',
    'decrypted' => TRUE,
    'uid'       => 15
);
2
2.07.2015 13:51:57

Я столкнулся с той же проблемой, поэтому я написал следующий класс: Email_Parser. Он принимает необработанное письмо и превращает его в приятный объект.

Требуется PEAR Mail_mimeDecode, но его легко установить через WHM или прямо из командной строки.

Получите это здесь: https://github.com/optimumweb/php-email-reader-parser

0
23.10.2015 21:47:40

Этот https://github.com/zbateson/MailMimeParser работает для меня и не нуждается в расширении mailparse.

<?php
echo $message->getHeaderValue('from');          // user@example.com
echo $message
    ->getHeader('from')
    ->getPersonName();                          // Person Name
echo $message->getHeaderValue('subject');       // The email's subject

echo $message->getTextContent();                // or getHtmlContent
2
23.11.2016 12:34:43

Простой PhpMimeParser https://github.com/breakermind/PhpMimeParser Yuo может вырезать сообщения MIME из файлов, строк. Получить файлы, HTML и встроенные изображения.

$str = file_get_contents('mime-mixed-related-alternative.eml');

// MimeParser
$m = new PhpMimeParser($str);

// Emails
print_r($m->mTo);
print_r($m->mFrom);

// Message
echo $m->mSubject;
echo $m->mHtml;
echo $m->mText;

// Attachments and inline images
print_r($m->mFiles);
print_r($m->mInlineList);
0
4.11.2017 12:48:57
При использовании вашего класса я получаю ошибку: Warning: Invalid argument supplied for foreach()в строке синтаксического анализатора 315 переменная $ AllPartsUnique пуста. Возможно, ваш код разбит на определенные файлы eml.
Agnius Vasiliauskas 16.09.2018 11:27:24