Вы сказали:
Есть тело письма *.eml находится в архиве
Разархивировать архив имя файла не известно но с расширением .eml Прочитать файл и полностью структуру письма Учитывая кодировку разную на все случаи жизни и файлы вложения
Для выполнения этой задачи — разархивировать архив с неизвестным именем .eml-файла, прочитать его структуру (включая вложения и корректную обработку кодировок) — можно воспользоваться Python-скриптом. Вот подробный пошаговый план и соответствующий код:
Разархивировать архив (формат .zip, .rar, .7z и т.п.).
Найти файл с расширением .eml.
Прочитать .eml-файл с учетом кодировок.
Извлечь структуру письма:
Заголовки
Тело (plain / html)
Вложения (с именами, типами, размером)
bashpip install extract-msg chardet py7zr rarfile
Для
.rarпотребуетсяunrarустановленный в системе. Для.7z—7z.
pythonimport os
import zipfile
import rarfile
import py7zr
import chardet
import email
from email import policy
from email.parser import BytesParser
def extract_archive(archive_path, extract_to='extracted'):
os.makedirs(extract_to, exist_ok=True)
if zipfile.is_zipfile(archive_path):
with zipfile.ZipFile(archive_path, 'r') as z:
z.extractall(extract_to)
elif rarfile.is_rarfile(archive_path):
with rarfile.RarFile(archive_path) as r:
r.extractall(extract_to)
elif archive_path.endswith('.7z'):
with py7zr.SevenZipFile(archive_path, mode='r') as z:
z.extractall(path=extract_to)
else:
raise ValueError("Неподдерживаемый формат архива")
return extract_to
def find_eml_file(directory):
for root, dirs, files in os.walk(directory):
for file in files:
if file.lower().endswith('.eml'):
return os.path.join(root, file)
return None
def detect_encoding(data):
result = chardet.detect(data)
return result['encoding']
def parse_eml(eml_path):
with open(eml_path, 'rb') as f:
msg = BytesParser(policy=policy.default).parse(f)
print("== Заголовки ==")
for key, value in msg.items():
print(f"{key}: {value}")
print("\n== Содержимое ==")
if msg.is_multipart():
for part in msg.walk():
content_type = part.get_content_type()
content_disp = part.get('Content-Disposition', '')
if 'attachment' in content_disp:
filename = part.get_filename()
print(f"\n[Вложение] {filename} ({content_type}) — {len(part.get_payload(decode=True))} байт")
elif content_type == 'text/plain':
print("\n[Текст Plain]:")
print(part.get_content())
elif content_type == 'text/html':
print("\n[HTML]:")
print(part.get_content())
else:
print(msg.get_content())
# ===== Запуск =====
archive_file = 'archive_input_file.zip' # Заменить на свой путь
extracted_path = extract_archive(archive_file)
eml_file = find_eml_file(extracted_path)
if eml_file:
print(f"Найден файл: {eml_file}")
parse_eml(eml_file)
else:
print("Файл .eml не найден в архиве.")
Если в архиве несколько .eml-файлов, можно вернуть список и обрабатывать их по очереди.
Для обработки редких кодировок chardet помогает, но email.policy.default уже сам по себе хорошо справляется.
Вложения можно сохранять, если нужно — просто допиши with open(...).
Если хочешь, я могу адаптировать скрипт под конкретный архив, если ты его загрузишь.
Поддержка форматов: .zip, .rar, .7z реализована. Могу добавить другие по запросу.
Готов сгенерировать версию с GUI, логами или экспортом в JSON — просто скажи.
Хорошо! Вот полный пример на PHP с использованием процедурного подхода, который:
Разархивирует архив (.zip, т.к. PHP встроенно поддерживает его).
Находит файл с расширением .eml.
Читает структуру письма:
Заголовки
Текстовое тело (plain и/или html)
Вложения (с именами и размерами)
Учитывает разные кодировки.
PHP 7.0+
php-mbstring (для работы с кодировками)
ZipArchive включён (обычно включён по умолчанию)
Для чтения .eml — базовая обработка MIME вручную
pythonproject/
├── archive.zip
└── parser.php
parser.php – полный код:php<?php
/**
* Распаковка архива, поиск .eml, парсинг структуры письма
* Процедурный стиль, комментарии включены
*/
// === 1. Настройки ===
$archivePath = "archive.zip"; // Путь к архиву
$extractTo = "extracted"; // Куда распаковать
// === 2. Распаковать архив ZIP ===
function extract_zip($zipFile, $outputDir) {
if (!file_exists($zipFile)) {
die("Файл архива не найден.\n");
}
$zip = new ZipArchive;
if ($zip->open($zipFile) === TRUE) {
$zip->extractTo($outputDir);
$zip->close();
echo "Архив успешно распакован в '$outputDir'\n";
} else {
die("Ошибка при открытии архива.\n");
}
}
// === 3. Найти .eml файл в распакованной папке ===
function find_eml_file($directory) {
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory));
foreach ($iterator as $file) {
if (strtolower(pathinfo($file, PATHINFO_EXTENSION)) === 'eml') {
return $file->getPathname();
}
}
return false;
}
// === 4. Декодировать заголовок (если есть =?UTF-8?Q?...?=) ===
function decode_mime_header($text) {
return mb_decode_mimeheader($text);
}
// === 5. Разобрать EML ===
function parse_eml($emlPath) {
$raw = file_get_contents($emlPath);
if (!$raw) {
die("Не удалось прочитать EML файл.\n");
}
echo "\n--- Разбор письма ---\n";
// Разделить заголовки и тело
list($rawHeaders, $rawBody) = explode("\r\n\r\n", $raw, 2);
$headers = [];
foreach (explode("\r\n", $rawHeaders) as $line) {
if (preg_match('/^([\w\-]+):\s*(.*)/', $line, $matches)) {
$headers[$matches[1]] = decode_mime_header($matches[2]);
}
}
// === Заголовки ===
echo "\nЗаголовки:\n";
foreach ($headers as $key => $value) {
echo "$key: $value\n";
}
// === Многокомпонентность ===
$boundary = '';
foreach ($headers as $key => $value) {
if (stripos($key, 'Content-Type') !== false && preg_match('/boundary="([^"]+)"/', $value, $matches)) {
$boundary = $matches[1];
break;
}
}
if ($boundary) {
echo "\nОбнаружен multipart boundary: $boundary\n";
$parts = explode('--' . $boundary, $rawBody);
foreach ($parts as $part) {
if (trim($part) == '' || $part == "--") continue;
// Заголовки части
list($partHeadersRaw, $partBody) = explode("\r\n\r\n", $part, 2) + ["", ""];
$partHeaders = [];
foreach (explode("\r\n", $partHeadersRaw) as $line) {
if (preg_match('/^([\w\-]+):\s*(.*)/', $line, $matches)) {
$partHeaders[$matches[1]] = decode_mime_header($matches[2]);
}
}
// Тип содержимого
$contentType = $partHeaders['Content-Type'] ?? 'text/plain';
$disposition = $partHeaders['Content-Disposition'] ?? '';
// Вложения
if (stripos($disposition, 'attachment') !== false && preg_match('/filename="?(.*?)"?$/', $disposition, $fn)) {
$filename = $fn[1];
$data = base64_decode(trim($partBody));
$size = strlen($data);
echo "\n[Вложение] $filename ($contentType) — $size байт\n";
// file_put_contents("output/" . $filename, $data); // Можно сохранить
} else {
if (stripos($contentType, 'text/plain') !== false) {
echo "\n[Текстовая часть]\n" . trim($partBody) . "\n";
} elseif (stripos($contentType, 'text/html') !== false) {
echo "\n[HTML часть]\n" . trim($partBody) . "\n";
}
}
}
} else {
echo "\n[Простое письмо]\n";
echo $rawBody;
}
}
// === ВЫПОЛНЕНИЕ ===
extract_zip($archivePath, $extractTo);
$emlFile = find_eml_file($extractTo);
if ($emlFile) {
echo "Найден EML файл: $emlFile\n";
parse_eml($emlFile);
} else {
echo "Файл .eml не найден.\n";
}
| Этап | Описание |
|---|---|
| Распаковка архива | Использует ZipArchive |
Поиск .eml | Рекурсивный по директориям |
Парсинг .eml | Разделяет заголовки и тело |
| Поддержка multipart письма | Обработка частей, границ и вложений |
| Работа с кодировками | Использует mb_decode_mimeheader |
Поддержка .rar, .7z: потребует внешние утилиты (через shell_exec()).
Сохранение вложений в папку output/.
Экспорт результатов в JSON или HTML.
Если хочешь, я могу:
Добавить сохранение вложений.
Сделать HTML-интерфейс.
Расширить поддержку других форматов архивов.
Скажи, если нужно.
Отличная задача — ты хочешь создать веб-интерфейс на PHP, который работает как файловый менеджер, и при открытии .eml-файла отображает его как почтовый клиент: заголовки, тело, вложения, дату, отправителя, и т.д., с учетом кодировки. Также должна быть возможность загрузки архива или .eml.
Рекурсивный просмотр файлов и папок (Проводник)
Отображение содержимого выбранной папки
Открытие файлов, просмотр .eml как письма
Загрузка .zip или .eml файлов
Автоматическая распаковка архива и парсинг .eml, если в архиве
Поддержка разных кодировок
pgsqlproject/
├── index.php ← HTML-интерфейс + логика
├── parser.php ← Функции для разбора .eml
├── uploads/ ← Загрузка файлов (архивы или .eml)
├── explorer/ ← Начальная директория просмотра
├── extracted/ ← Распакованные архивы
├── assets/ ← CSS/иконки (опционально)
index.php — интерфейс проводника + логикаphp<?php
// Конфигурация
$baseDir = realpath('explorer'); // Начальная директория
$uploadDir = 'uploads/';
$extractDir = 'extracted/';
$currentPath = isset($_GET['path']) ? realpath($_GET['path']) : $baseDir;
// Защита от выхода за пределы
if (strpos($currentPath, $baseDir) !== 0) {
$currentPath = $baseDir;
}
// === Загрузка файла ===
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['file'])) {
$name = basename($_FILES['file']['name']);
$dest = $uploadDir . $name;
move_uploaded_file($_FILES['file']['tmp_name'], $dest);
// Если zip — распаковываем
if (strtolower(pathinfo($dest, PATHINFO_EXTENSION)) === 'zip') {
$zip = new ZipArchive();
if ($zip->open($dest) === TRUE) {
$folderName = uniqid('zip_');
$zip->extractTo($extractDir . $folderName);
$zip->close();
echo "<p>Архив распакован: $folderName</p>";
}
}
// Перенаправление
header("Location: " . $_SERVER['PHP_SELF']);
exit;
}
// === Показ проводника ===
function list_directory($path) {
$items = scandir($path);
echo "<ul>";
foreach ($items as $item) {
if ($item === '.' || $item === '..') continue;
$fullPath = realpath("$path/$item");
$isDir = is_dir($fullPath);
$url = "?path=" . urlencode($fullPath);
echo "<li>";
echo $isDir ? "📁" : "📄";
echo " <a href='$url'>" . htmlspecialchars($item) . "</a>";
echo "</li>";
}
echo "</ul>";
}
?>
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Файловый Проводник + EML Парсер</title>
<style>
body { font-family: sans-serif; margin: 20px; }
h1 { font-size: 20px; }
ul { list-style-type: none; padding-left: 1em; }
</style>
</head>
<body>
<h1>Файловый Проводник</h1>
<p>Текущий путь: <strong><?= htmlspecialchars($currentPath) ?></strong></p>
<?php list_directory($currentPath); ?>
<h2>Загрузка файла (архив .zip или .eml)</h2>
<form method="POST" enctype="multipart/form-data">
<input type="file" name="file" required>
<button type="submit">Загрузить</button>
</form>
<?php
// === Если выбран EML-файл — парсить ===
if (is_file($currentPath) && strtolower(pathinfo($currentPath, PATHINFO_EXTENSION)) === 'eml') {
echo "<hr><h2>Просмотр EML-файла</h2>";
require_once 'parser.php';
parse_eml_html($currentPath);
}
?>
</body>
</html>
parser.php — разбор EML с выводом как письмоphp<?php
function decode_header_line($text) {
return mb_decode_mimeheader($text);
}
function parse_eml_html($emlPath) {
$raw = file_get_contents($emlPath);
if (!$raw) {
echo "<p>Ошибка чтения файла</p>";
return;
}
list($rawHeaders, $rawBody) = explode("\r\n\r\n", $raw, 2) + ["", ""];
// Заголовки
$headers = [];
foreach (explode("\r\n", $rawHeaders) as $line) {
if (preg_match('/^([\w\-]+):\s*(.*)/', $line, $matches)) {
$headers[$matches[1]] = decode_header_line($matches[2]);
}
}
// Заголовки (с описанием)
echo "<h3>Заголовки письма</h3><table border='1' cellpadding='5'>";
foreach ($headers as $key => $val) {
echo "<tr><td><strong>$key</strong></td><td>$val</td></tr>";
}
echo "</table>";
// Поиск boundary
$boundary = '';
if (isset($headers['Content-Type']) && preg_match('/boundary="?(.*?)"?$/', $headers['Content-Type'], $b)) {
$boundary = $b[1];
}
echo "<h3>Содержимое письма</h3>";
if ($boundary) {
$parts = explode('--' . $boundary, $rawBody);
foreach ($parts as $part) {
if (trim($part) == '' || $part == "--") continue;
list($partHeadersRaw, $partBody) = explode("\r\n\r\n", $part, 2) + ["", ""];
$contentType = 'text/plain';
$disposition = '';
foreach (explode("\r\n", $partHeadersRaw) as $line) {
if (stripos($line, 'Content-Type:') === 0)
$contentType = trim(substr($line, 13));
if (stripos($line, 'Content-Disposition:') === 0)
$disposition = trim(substr($line, 21));
}
if (stripos($disposition, 'attachment') !== false) {
if (preg_match('/filename="?(.*?)"?$/', $disposition, $f)) {
$filename = $f[1];
$data = base64_decode(trim($partBody));
$size = strlen($data);
echo "<p><strong>Вложение:</strong> $filename ($size байт)</p>";
// file_put_contents("attachments/$filename", $data);
}
} else {
echo "<h4>Часть ($contentType)</h4>";
echo "<pre>" . htmlspecialchars(trim($partBody)) . "</pre>";
}
}
} else {
echo "<pre>" . htmlspecialchars($rawBody) . "</pre>";
}
}
Создай структуру, как указано выше.
Перейди на http://localhost/project/index.php.
Загрузи .eml или .zip с .eml — он отобразится.
Навигируй по структуре explorer/.
Сохранение вложений в attachments/
Просмотр HTML-версии письма в <iframe>
Поиск писем по заголовкам/отправителю
Расширение поддержки .rar, .7z с shell_exec()
Хочешь — соберу архив проекта с примерами писем, чтобы ты мог скачать и сразу использовать. Готов?