Перейти к содержимому
Вы сказали:
На windows mailparse php как пользоваться есть файлы *.eml Создай скрипт который будет обрабатывать любое почтовое сообщение подробно распиши Код писать процедурно очень подробно Максимально функционально полностью обработать письмо Указываю путь в input внутри сервера /attach...../файл.eml
ChatGPT сказал:

Понял, нужно на Windows с PHP и расширением mailparse сделать максимально подробный процедурный скрипт, который получает путь к .eml файлу (например, /attach/файл.eml), и полностью разбирает письмо, включая заголовки, тело, вложения, кодировки — максимально функционально.


Введение

Расширение mailparse для PHP позволяет парсить MIME-сообщения, в том числе .eml файлы. С его помощью можно получить структуру письма, заголовки, содержимое, извлечь вложения и декодировать их.


Что нужно:

  • PHP с установленным и включённым расширением mailparse (проверь командой php -m | grep mailparse).

  • Файл письма (.eml), путь к которому указываем.

  • Процедурный стиль кода.

  • Вывести всё максимально подробно.


Скрипт: полный разбор письма

php
<?php // Путь к файлу .eml (указать корректный, например '/attach/письмо.eml') $eml_file = __DIR__ . '/attach/письмо.eml'; if (!file_exists($eml_file)) { die("Файл $eml_file не найден\n"); } // Читаем содержимое письма $email_content = file_get_contents($eml_file); if ($email_content === false) { die("Не удалось прочитать файл $eml_file\n"); } // Создаем ресурс mailparse для письма $mime = mailparse_msg_create(); if (!mailparse_msg_parse($mime, $email_content)) { die("Не удалось распарсить письмо\n"); } // Получаем структуру частей письма (вложений и тела) $structure = mailparse_msg_get_structure($mime); // Функция для декодирования содержимого из разных кодировок function decode_part_data($part, $email_content) { $data = mailparse_msg_extract_part($part, $email_content); $info = mailparse_msg_get_part_data($part); // Кодировка содержимого $encoding = strtolower($info['transfer-encoding'] ?? ''); // Декодируем base64, quoted-printable и т.п. switch ($encoding) { case 'base64': $data = base64_decode($data); break; case 'quoted-printable': $data = quoted_printable_decode($data); break; // Можно добавить другие, если надо default: // Оставим как есть break; } return $data; } // Функция для вывода заголовков письма function print_headers($headers) { echo "=== Заголовки письма ===\n"; foreach ($headers as $key => $value) { // Иногда заголовок - массив (например, Received) if (is_array($value)) { foreach ($value as $v) { echo "$key: $v\n"; } } else { echo "$key: $value\n"; } } echo "=======================\n\n"; } // Функция для вывода информации о части письма function print_part_info($part, $email_content) { $info = mailparse_msg_get_part_data($part); echo "----- Часть письма -----\n"; // Content-Type echo "Content-Type: " . ($info['content-type'] ?? 'unknown') . "\n"; // Content-Disposition echo "Content-Disposition: " . ($info['disposition-filename'] ?? ($info['content-disposition'] ?? 'none')) . "\n"; // Filename вложения if (!empty($info['disposition-filename'])) { echo "Имя вложения: " . $info['disposition-filename'] . "\n"; } elseif (!empty($info['content-name'])) { echo "Имя вложения (content-name): " . $info['content-name'] . "\n"; } // Content-Transfer-Encoding echo "Content-Transfer-Encoding: " . ($info['transfer-encoding'] ?? 'none') . "\n"; // Получаем тело этой части и декодируем $decoded_data = decode_part_data($part, $email_content); // Если это текстовая часть — выведем первые 500 символов if (strpos($info['content-type'], 'text/') === 0) { // Определим кодировку $charset = 'UTF-8'; // по умолчанию if (isset($info['content-type-parameters']['charset'])) { $charset = $info['content-type-parameters']['charset']; } // Преобразуем в UTF-8, если надо $text = $decoded_data; if (strtoupper($charset) !== 'UTF-8') { $text = mb_convert_encoding($decoded_data, 'UTF-8', $charset); } echo "Текст (первые 500 символов):\n"; echo mb_substr($text, 0, 500) . "\n"; } else { // Для вложений покажем размер и первые байты в hex echo "Данные (размер в байтах): " . strlen($decoded_data) . "\n"; echo "Первые 50 байт в HEX: " . strtoupper(bin2hex(substr($decoded_data, 0, 50))) . "\n"; } echo "-----------------------\n\n"; } // Получаем заголовки письма $headers = mailparse_msg_get_part_data($mime)['headers'] ?? []; print_headers($headers); // Перебираем все части письма foreach ($structure as $part_id) { $part = mailparse_msg_get_part($mime, $part_id); print_part_info($part, $email_content); } // Освобождаем ресурс mailparse_msg_free($mime); echo "Разбор письма завершён\n"; ?>

Как пользоваться:

  1. Сохраните скрипт, например, в parse_eml.php.

  2. Положите файл письма письмо.eml в папку /attach/ рядом с этим скриптом.

  3. Запустите из командной строки:

    nginx
    php parse_eml.php
  4. В консоли вы увидите подробный разбор заголовков, а затем по частям — текстовые части с декодированным текстом и вложения (с краткой информацией).


Что делает скрипт:

  • Читает содержимое .eml файла.

  • Создаёт ресурс mailparse и парсит MIME структуру.

  • Выводит заголовки.

  • Перебирает все части письма (текстовые и вложения).

  • Декодирует содержимое частей по их Content-Transfer-Encoding.

  • Для текстовых частей пытается конвертировать в UTF-8 по charset.

  • Для вложений показывает размер и первые байты в HEX.

  • Показывает имя вложения (если есть).

  • Всё строго процедурно, подробно и полно.


Возможное расширение:

  • Сохранять вложения на диск.

  • Поддержка inline-картинок.

  • Обработка более сложных вложений и разных кодировок.

  • Обработка multipart/alternative (обычно HTML + Plain text).

  • Вывод в удобном формате (HTML, JSON).


Если нужно — могу помочь расширить или сделать в ООП стиле.


Если хочешь — могу объяснить детали любого этапа — скажи!

Вы сказали:
Включить все возможные расширения Сохранять вложения на диск Поддержка inline-картинок Обработка более сложных вложений и разных кодировок Обработка multipart/alternative (обычно HTML + Plain text). Вывод в удобном формате (HTML, JSON) в отдельный файл
ChatGPT сказал:

Отлично! Сделаем максимально продвинутый процедурный PHP-скрипт, который:

  • Включит расширения (mailparse и mbstring),

  • Разберёт .eml с поддержкой всех вложений, inline-картинок,

  • Обработает multipart/alternative (plain + html),

  • Сохранит вложения и картинки на диск,

  • Корректно распознает и конвертирует кодировки,

  • Выведет итог в удобном JSON-файле с подробной структурой письма.


Полный продвинутый пример

php
<?php // Убедимся, что mailparse и mbstring подключены if (!extension_loaded('mailparse')) { die("Требуется расширение mailparse\n"); } if (!extension_loaded('mbstring')) { die("Требуется расширение mbstring\n"); } // Путь к EML-файлу (укажите свой) $eml_file = __DIR__ . '/attach/письмо.eml'; // Папка для сохранения вложений $attachments_dir = __DIR__ . '/attach/saved_attachments'; // Создаем папку для вложений, если нет if (!is_dir($attachments_dir)) { mkdir($attachments_dir, 0777, true); } // Проверка файла if (!file_exists($eml_file)) { die("Файл $eml_file не найден\n"); } // Читаем файл $email_content = file_get_contents($eml_file); if ($email_content === false) { die("Не удалось прочитать файл $eml_file\n"); } // Создаем ресурс mailparse $mime = mailparse_msg_create(); if (!mailparse_msg_parse($mime, $email_content)) { die("Не удалось распарсить письмо\n"); } $structure = mailparse_msg_get_structure($mime); // Функция для декодирования части письма с учётом кодировки transfer-encoding function decode_part_data($part, $email_content) { $data = mailparse_msg_extract_part($part, $email_content); $info = mailparse_msg_get_part_data($part); $encoding = strtolower($info['transfer-encoding'] ?? ''); switch ($encoding) { case 'base64': $data = base64_decode($data); break; case 'quoted-printable': $data = quoted_printable_decode($data); break; // можно добавить '7bit', '8bit', 'binary' — там обычно нет декодирования default: break; } return $data; } // Функция для безопасного имени файла function safe_filename($filename) { // Удалим опасные символы $filename = preg_replace('/[^a-zA-Z0-9_\.\-]/u', '_', $filename); return $filename; } // Функция для обработки одной части function process_part($part, $email_content, $attachments_dir) { $info = mailparse_msg_get_part_data($part); $part_result = []; // Контент-тип $ctype = $info['content-type'] ?? 'unknown'; $part_result['content_type'] = $ctype; // Заголовки $part_result['headers'] = $info['headers'] ?? []; // Файл вложения, если есть $filename = $info['disposition-filename'] ?? ($info['content-name'] ?? null); if ($filename) { $filename = safe_filename($filename); } // Получаем тело и декодируем $data = decode_part_data($part, $email_content); // Обрабатываем текстовые части if (strpos($ctype, 'text/') === 0) { // Кодировка charset $charset = 'UTF-8'; if (isset($info['content-type-parameters']['charset'])) { $charset = $info['content-type-parameters']['charset']; } $text = $data; if (strtoupper($charset) !== 'UTF-8') { $text = @mb_convert_encoding($data, 'UTF-8', $charset); if ($text === false) $text = $data; } $part_result['content'] = $text; $part_result['charset'] = $charset; } else { // Это вложение или бинарные данные — сохраняем если есть имя файла if ($filename) { $save_path = $attachments_dir . '/' . $filename; // Уникальность имени файла $save_path = unique_filename($save_path); file_put_contents($save_path, $data); $part_result['attachment_saved'] = $save_path; $part_result['attachment_size'] = strlen($data); $part_result['filename'] = $filename; } else { // Если нет имени файла, просто укажем размер данных $part_result['content_length'] = strlen($data); } } // Если Content-Disposition inline и есть cid (inline-картинки) if (($info['content-disposition'] ?? '') === 'inline' && !empty($info['headers']['content-id'])) { $cid = trim($info['headers']['content-id'], "<>"); $part_result['content_id'] = $cid; } return $part_result; } // Функция генерации уникального имени файла (если файл с таким именем уже есть) function unique_filename($filepath) { $dir = dirname($filepath); $name = pathinfo($filepath, PATHINFO_FILENAME); $ext = pathinfo($filepath, PATHINFO_EXTENSION); $counter = 1; $newpath = $filepath; while (file_exists($newpath)) { $newpath = $dir . '/' . $name . '_' . $counter; if ($ext) $newpath .= '.' . $ext; $counter++; } return $newpath; } // Функция для вывода заголовков письма в массив function get_headers($mime) { $hdrs = mailparse_msg_get_part_data($mime)['headers'] ?? []; return $hdrs; } // Теперь строим итоговую структуру письма с рекурсией по частям function process_structure($mime, $email_content, $attachments_dir, $structure) { $result = []; foreach ($structure as $part_id) { $part = mailparse_msg_get_part($mime, $part_id); $info = mailparse_msg_get_part_data($part); // Если multipart — парсим рекурсивно (у mailparse вложенности нет, но можем просто идти по частям) if (isset($info['content-type']) && strpos($info['content-type'], 'multipart/') === 0) { // Для multipart часто важен multipart/alternative (html + text) — сохранем этот факт $result[$part_id] = [ 'content_type' => $info['content-type'], 'parts' => [] // mailparse не предоставляет вложенность явно, так что мы просто соберем все части и можно сгруппировать по Content-Type, если надо ]; // Можно сгруппировать части по порядку ниже, но в этой процедуре просто укажем пустой массив, // тк mailparse выводит все части "плоско" } else { $result[$part_id] = process_part($part, $email_content, $attachments_dir); } } return $result; } // Собираем данные $headers = get_headers($mime); $parts_data = process_structure($mime, $email_content, $attachments_dir, $structure); // Итоговая структура $output = [ 'headers' => $headers, 'parts' => $parts_data ]; // Сохраняем результат в JSON файл $json_file = __DIR__ . '/attach/parsed_email.json'; file_put_contents($json_file, json_encode($output, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); mailparse_msg_free($mime); echo "Письмо распарсено и сохранено в $json_file\n"; echo "Вложения сохранены в $attachments_dir\n"; ?>

Объяснение:

  • Проверяем, что mailparse и mbstring загружены (нужно для кодировок).

  • Читаем .eml файл и парсим.

  • Рекурсивно (по структуре mailparse) обрабатываем все части.

  • Для текстовых частей корректно декодируем charset и transfer-encoding.

  • Вложения (с именами) сохраняем в указанную папку, проверяя на уникальность имён.

  • Inline картинки определяются по Content-Disposition: inline и Content-ID.

  • Итог собирается в массив с заголовками и частями.

  • Выводим в красивый JSON с UTF-8.

  • Вложения сохраняются в папку.


К чему готовиться

  • mailparse не предоставляет вложенную структуру MIME, все части идут плоско, поэтому можно дополнительно группировать multipart/alternative самостоятельно, если нужно.

  • Для поддержки inline-картинок и их связей с HTML нужно дополнительно парсить HTML и искать cid:... — можно расширить скрипт для этого.

  • Кодировка преобразуется в UTF-8 для текстовых частей.


Если хочешь — могу помочь сделать:

  • Автоматическое связывание inline-картинок с HTML (замена cid на локальные файлы),

  • Группировку multipart/alternative (html + plain),

  • Или более наглядный вывод (HTML-отчёт).


Напиши, если надо сделать что-то из этого!

Вы сказали:
Группировку multipart/alternative (html + plain) Добавить выводить все возможные служебные заголовки какие только существуют
ChatGPT сказал:

Понял, добавим:

  • Группировку multipart/alternative — определим части plain/text и text/html, свяжем их в структуре, чтобы в JSON четко было видно, что они связаны (обычно html + plain версия одного блока письма);

  • Вывод всех служебных заголовков, которые может найти mailparse (они лежат в headers у письма и частей) — просто выведем их все (mailparse получает все заголовки, никаких ограничений нет);

  • При этом расширим структуру JSON, чтобы было понятнее.


Обновлённый полный процедурный скрипт с группировкой multipart/alternative и подробными заголовками

php
<?php if (!extension_loaded('mailparse')) { die("Требуется расширение mailparse\n"); } if (!extension_loaded('mbstring')) { die("Требуется расширение mbstring\n"); } $eml_file = __DIR__ . '/attach/письмо.eml'; $attachments_dir = __DIR__ . '/attach/saved_attachments'; if (!is_dir($attachments_dir)) { mkdir($attachments_dir, 0777, true); } if (!file_exists($eml_file)) { die("Файл $eml_file не найден\n"); } $email_content = file_get_contents($eml_file); if ($email_content === false) { die("Не удалось прочитать файл $eml_file\n"); } $mime = mailparse_msg_create(); if (!mailparse_msg_parse($mime, $email_content)) { die("Не удалось распарсить письмо\n"); } $structure = mailparse_msg_get_structure($mime); function decode_part_data($part, $email_content) { $data = mailparse_msg_extract_part($part, $email_content); $info = mailparse_msg_get_part_data($part); $encoding = strtolower($info['transfer-encoding'] ?? ''); switch ($encoding) { case 'base64': $data = base64_decode($data); break; case 'quoted-printable': $data = quoted_printable_decode($data); break; default: break; } return $data; } function safe_filename($filename) { return preg_replace('/[^a-zA-Z0-9_\.\-]/u', '_', $filename); } function unique_filename($filepath) { $dir = dirname($filepath); $name = pathinfo($filepath, PATHINFO_FILENAME); $ext = pathinfo($filepath, PATHINFO_EXTENSION); $counter = 1; $newpath = $filepath; while (file_exists($newpath)) { $newpath = $dir . '/' . $name . '_' . $counter; if ($ext) $newpath .= '.' . $ext; $counter++; } return $newpath; } function process_part($part, $email_content, $attachments_dir) { $info = mailparse_msg_get_part_data($part); $part_result = []; $ctype = $info['content-type'] ?? 'unknown'; $part_result['content_type'] = $ctype; $part_result['headers'] = $info['headers'] ?? []; $filename = $info['disposition-filename'] ?? ($info['content-name'] ?? null); if ($filename) { $filename = safe_filename($filename); } $data = decode_part_data($part, $email_content); if (strpos($ctype, 'text/') === 0) { $charset = 'UTF-8'; if (isset($info['content-type-parameters']['charset'])) { $charset = $info['content-type-parameters']['charset']; } $text = $data; if (strtoupper($charset) !== 'UTF-8') { $text = @mb_convert_encoding($data, 'UTF-8', $charset); if ($text === false) $text = $data; } $part_result['content'] = $text; $part_result['charset'] = $charset; } else { if ($filename) { $save_path = $attachments_dir . '/' . $filename; $save_path = unique_filename($save_path); file_put_contents($save_path, $data); $part_result['attachment_saved'] = $save_path; $part_result['attachment_size'] = strlen($data); $part_result['filename'] = $filename; } else { $part_result['content_length'] = strlen($data); } } if (($info['content-disposition'] ?? '') === 'inline' && !empty($info['headers']['content-id'])) { $cid = trim($info['headers']['content-id'], "<>"); $part_result['content_id'] = $cid; } return $part_result; } // Доп функция группировки multipart/alternative function group_multipart_alternative($parts_data, $mime, $email_content, $attachments_dir) { // Попытаемся собрать части с одинаковым parent multipart/alternative // mailparse не возвращает вложенную структуру явно, // но можно найти части с одинаковым parent и content-type multipart/alternative // Найдем части с multipart/alternative, и "соберём" их дочерние части // Собираем список частей с info (content-type и parent) $parts_info = []; foreach ($parts_data as $part_id => $data) { $info = mailparse_msg_get_part_data(mailparse_msg_get_part($mime, $part_id)); $parts_info[$part_id] = $info; } // Сгруппируем по parent $parents_map = []; foreach ($parts_info as $part_id => $info) { $parent = $info['parent'] ?? null; if ($parent) { $parents_map[$parent][] = $part_id; } } $result = []; foreach ($parts_data as $part_id => $part_data) { $info = $parts_info[$part_id] ?? []; $ctype = $info['content-type'] ?? ''; if (strpos($ctype, 'multipart/alternative') === 0) { // multipart/alternative — берем дочерние части и группируем $children = $parents_map[$part_id] ?? []; $alt_parts = []; foreach ($children as $child_id) { $child_data = $parts_data[$child_id] ?? null; if ($child_data) { $alt_parts[$child_id] = $child_data; } } $result[$part_id] = [ 'content_type' => $ctype, 'parts' => $alt_parts, 'headers' => $info['headers'] ?? [] ]; } elseif (!isset($parents_map[$part_id])) { // Часть без дочерних (т.е. "обычные" части) // Если не является дочерним multipart/alternative, просто выводим $result[$part_id] = $part_data; } // дочерние части multipart/alternative будут в составе parent части, не выводим отдельно } return $result; } function get_all_headers($mime) { // mailparse возвращает заголовки для всего письма и для частей // Здесь получим заголовки корня (самого письма) $hdrs = mailparse_msg_get_part_data($mime)['headers'] ?? []; return $hdrs; } // Сначала обработаем все части без группировки $parts_data = []; foreach ($structure as $part_id) { $part = mailparse_msg_get_part($mime, $part_id); $parts_data[$part_id] = process_part($part, $email_content, $attachments_dir); } // Выполним группировку multipart/alternative $grouped_parts = group_multipart_alternative($parts_data, $mime, $email_content, $attachments_dir); // Получим заголовки корня письма (все возможные) $headers = get_all_headers($mime); $output = [ 'headers' => $headers, 'parts' => $grouped_parts ]; $json_file = __DIR__ . '/attach/parsed_email.json'; file_put_contents($json_file, json_encode($output, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); mailparse_msg_free($mime); echo "Письмо распарсено и сохранено в $json_file\n"; echo "Вложения сохранены в $attachments_dir\n"; ?>

Ключевые моменты:

  • Функция group_multipart_alternative — собирает части с общим родителем multipart/alternative и помещает их в один блок JSON, где plain и html части лежат рядом, что удобно.

  • Выводим все заголовки, которые mailparse парсит — включая служебные (в JSON будут все ключи и значения заголовков письма).

  • Вложения и inline-картинки сохраняются и сопровождаются информацией о сохранении.

  • Текстовые части преобразуются в UTF-8 по charset.

  • В JSON четко видна структура: заголовки, части, вложения, grouped multipart/alternative.


Если надо:

  • Можем добавить вывод HTML-отчёта,

  • Или заменить в html содержимом cid: ссылки на локальные файлы из сохранённых inline-картинок,

  • Или улучшить распознавание вложений и inline-картинок.


Напиши, если хочешь эти улучшения или если нужна помощь с интеграцией!

Получайте более умные ответы, загружайте файлы и изображения и многое другое.


ChatGPT может допускать ошибки. Рекомендуем проверять важную информацию.