Подтвердить что ты не робот

Разбор сырой электронной почты в php

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

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

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

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

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

4b9b3361

Ответ 1

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

HEADERS\n
\n
BODY

Таким образом, первая пустая строка (двойная новая строка) является разделителем между HEADERS и BODY. ГОЛОВА выглядит так:

HSTRING:HTEXT

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

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

Итак, в действительно простых, около 1982 года RFC822 условиях, электронное письмо выглядит следующим образом:

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

THIS IS ANY
ARBITRARY DATA
(FOR THE MOST PART)

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

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

Ответ 2

Попробуйте парсер PHP Plancake PHP: https://github.com/plancake/official-library-php-email-parser

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

Ответ 3

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

#!/usr/bin/php -q
<?php
// Config
$dbuser = 'emlusr';
$dbpass = 'pass';
$dbname = 'email';
$dbhost = 'localhost';
$notify= '[email protected]'; // 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([email protected]_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());
}
?>

Ответ 4

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

Ответ 5

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

Ответ 6

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

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

$parsed_message = fMailbox:: parseMessage (file_get_contents ( '/путь/к/электронная почта'));

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

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' => '<[email protected]>',
        '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
);

Ответ 7

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

<?php
echo $message->getHeaderValue('from');          // [email protected]
echo $message
    ->getHeader('from')
    ->getPersonName();                          // Person Name
echo $message->getHeaderValue('subject');       // The email subject

echo $message->getTextContent();                // or getHtmlContent

Ответ 8

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

Ответ 9

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

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

EDIT - файлы, кажется, были удалены на сайте PHP London; нашел слайды на Часть 1 Часть 2 Не удалось увидеть MP3 в любом месте, хотя

Ответ 10

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

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

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

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

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

Ответ 11

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

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

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

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

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

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

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

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

Ответ 13

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

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

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

Ответ 14

Простой 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);