1
0

Neu: EML-Viewer

This commit is contained in:
Akamaru
2025-10-18 19:18:28 +02:00
parent d20d0f1ea0
commit f3419892bc
4 changed files with 540 additions and 0 deletions

BIN
eml_viewer/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

535
eml_viewer/index.html Normal file
View File

@@ -0,0 +1,535 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>EML Viewer - PonyWave Tools</title>
<meta property="og:title" content="EML Viewer | PonyWave Tools">
<meta property="og:description" content="E-Mail-Dateien (.eml) sicher und lokal im Browser betrachten">
<meta property="og:type" content="website">
<meta property="og:url" content="https://tools.ponywave.de/eml_viewer">
<meta property="og:image" content="https://tools.ponywave.de/eml_viewer/icon.png">
<link rel="icon" href="icon.png">
<!-- Umami Tracking -->
<script defer src="https://stats.ponywave.de/script" data-website-id="9ef713d2-adb9-4906-9df5-708d8a8b9131" data-tag="eml_viewer"></script>
<style>
:root {
--primary-color: #7F006E;
--secondary-color: #FF7FED;
--bg-gradient: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
--text-color: #e0e0e0;
--tool-bg: #2a2a2a;
--shadow-color: rgba(0, 0, 0, 0.5);
--footer-color: rgba(0, 0, 0, 0.8);
--border-color: #444;
--email-bg: #1e1e1e;
--email-header-bg: #252525;
--email-field-label: #888;
--button-hover: #CC65B5;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-image: var(--bg-gradient);
background-attachment: fixed;
color: var(--text-color);
min-height: 100vh;
display: flex;
flex-direction: column;
line-height: 1.6;
margin: 0;
padding: 20px 20px 70px 20px;
}
.container {
flex: 1;
max-width: 1400px;
margin: 0 auto;
padding: 20px;
width: 100%;
}
.title {
text-align: center;
color: var(--secondary-color);
margin-bottom: 30px;
font-size: 2.5em;
text-shadow: 2px 2px 6px rgba(255, 127, 237, 0.66);
}
.upload-section {
background: var(--tool-bg);
border-radius: 15px;
padding: 30px;
margin-bottom: 30px;
box-shadow: 0 4px 6px var(--shadow-color);
text-align: center;
}
.file-input-wrapper {
position: relative;
display: inline-block;
margin: 20px 0;
}
.file-input-label {
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
color: white;
padding: 15px 30px;
border-radius: 8px;
cursor: pointer;
font-size: 1.1em;
font-weight: 600;
transition: all 0.3s ease;
display: inline-block;
box-shadow: 0 2px 4px var(--shadow-color);
}
.file-input-label:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px var(--shadow-color);
}
#fileInput {
display: none;
}
.file-name {
margin-top: 15px;
color: var(--secondary-color);
font-size: 1em;
font-weight: 500;
}
.email-viewer {
background: var(--email-bg);
border-radius: 15px;
box-shadow: 0 4px 6px var(--shadow-color);
overflow: hidden;
display: none;
}
.email-header {
background: var(--email-header-bg);
padding: 25px 30px;
border-bottom: 2px solid var(--border-color);
}
.email-field {
margin-bottom: 15px;
display: flex;
align-items: flex-start;
}
.email-field-label {
color: var(--email-field-label);
font-weight: 600;
min-width: 100px;
margin-right: 15px;
}
.email-field-value {
color: var(--text-color);
flex: 1;
word-break: break-word;
}
.email-subject {
font-size: 1.5em;
font-weight: 700;
color: var(--secondary-color);
margin-bottom: 20px;
word-break: break-word;
}
.email-body {
padding: 30px;
background: white;
color: #333;
min-height: 200px;
}
.email-body iframe {
width: 100%;
border: none;
min-height: 400px;
}
.raw-headers {
background: #1a1a1a;
padding: 20px;
margin-top: 20px;
border-radius: 8px;
border: 1px solid var(--border-color);
display: none;
}
.raw-headers pre {
margin: 0;
font-family: 'Courier New', monospace;
font-size: 0.85em;
color: #888;
white-space: pre-wrap;
word-wrap: break-word;
}
.toggle-headers-btn {
background: var(--tool-bg);
border: 1px solid var(--border-color);
color: var(--text-color);
padding: 10px 20px;
border-radius: 6px;
cursor: pointer;
font-size: 0.9em;
margin-top: 15px;
transition: all 0.3s ease;
}
.toggle-headers-btn:hover {
background: var(--border-color);
}
.error-message {
background: #3d1e1e;
border: 1px solid #8b0000;
border-radius: 8px;
padding: 20px;
margin: 20px 0;
color: #ff6b6b;
display: none;
}
.info-message {
background: rgba(127, 0, 110, 0.2);
border: 1px solid var(--primary-color);
border-radius: 8px;
padding: 15px;
margin: 15px 0;
color: var(--text-color);
}
footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 15px 0;
background-color: var(--footer-color);
border-top: 1px solid var(--border-color);
text-align: center;
font-size: 14px;
color: var(--text-color);
z-index: 100;
}
footer a {
color: var(--secondary-color);
text-decoration: none;
font-weight: bold;
}
footer a:hover {
text-decoration: underline;
}
.heart {
color: #ff0000;
animation: heartbeat 1.5s infinite;
}
@keyframes heartbeat {
0% { transform: scale(1); }
50% { transform: scale(1.2); }
100% { transform: scale(1); }
}
@media (max-width: 768px) {
.title {
font-size: 2em;
}
.email-field {
flex-direction: column;
}
.email-field-label {
margin-bottom: 5px;
}
.upload-section {
padding: 20px;
}
}
</style>
</head>
<body>
<div class="container">
<h1 class="title">📧 EML Viewer</h1>
<div class="upload-section">
<h2 style="margin-bottom: 15px;">E-Mail-Datei auswählen</h2>
<p style="color: var(--email-field-label); margin-bottom: 10px;">
Wähle eine .eml-Datei von deinem Computer aus, um sie hier anzuzeigen.
</p>
<div class="info-message">
Alle Daten werden nur lokal in deinem Browser verarbeitet. Es werden keine Daten hochgeladen.
</div>
<div class="file-input-wrapper">
<label for="fileInput" class="file-input-label">
EML-Datei auswählen
</label>
<input type="file" id="fileInput" accept=".eml" />
</div>
<div class="file-name" id="fileName"></div>
</div>
<div class="error-message" id="errorMessage"></div>
<div class="email-viewer" id="emailViewer">
<div class="email-header">
<div class="email-subject" id="subject"></div>
<div class="email-field">
<div class="email-field-label">Von:</div>
<div class="email-field-value" id="from"></div>
</div>
<div class="email-field">
<div class="email-field-label">An:</div>
<div class="email-field-value" id="to"></div>
</div>
<div class="email-field">
<div class="email-field-label">Datum:</div>
<div class="email-field-value" id="date"></div>
</div>
<div class="email-field" id="ccField" style="display: none;">
<div class="email-field-label">CC:</div>
<div class="email-field-value" id="cc"></div>
</div>
<button class="toggle-headers-btn" onclick="toggleHeaders()">
Rohe Header anzeigen
</button>
<div class="raw-headers" id="rawHeaders">
<pre id="rawHeadersContent"></pre>
</div>
</div>
<div class="email-body" id="emailBody"></div>
</div>
</div>
<footer>
<p>
<a href="https://tools.ponywave.de/">Zurück zur Startseite</a> |
&copy; <span id="currentYear"></span> Akamaru | Made with <span class="heart">❤️</span> by Claude
</p>
</footer>
<script>
// Jahr aktualisieren
document.getElementById('currentYear').textContent = new Date().getFullYear();
// File Input Handler
document.getElementById('fileInput').addEventListener('change', function(e) {
const file = e.target.files[0];
if (file) {
if (!file.name.toLowerCase().endsWith('.eml')) {
showError('Bitte wähle eine .eml-Datei aus.');
return;
}
document.getElementById('fileName').textContent = `Ausgewählt: ${file.name}`;
readEMLFile(file);
}
});
function showError(message) {
const errorDiv = document.getElementById('errorMessage');
errorDiv.textContent = message;
errorDiv.style.display = 'block';
document.getElementById('emailViewer').style.display = 'none';
}
function hideError() {
document.getElementById('errorMessage').style.display = 'none';
}
function readEMLFile(file) {
const reader = new FileReader();
reader.onload = function(e) {
try {
parseEML(e.target.result);
hideError();
} catch (error) {
showError('Fehler beim Lesen der EML-Datei: ' + error.message);
}
};
reader.onerror = function() {
showError('Fehler beim Lesen der Datei.');
};
reader.readAsText(file);
}
function parseEML(emlContent) {
const lines = emlContent.split('\n');
const headers = {};
let headerEnd = 0;
let currentHeader = '';
let rawHeaders = '';
// Parse headers
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
// End of headers (empty line)
if (line.trim() === '') {
headerEnd = i + 1;
break;
}
rawHeaders += line + '\n';
// Continuation of previous header (starts with whitespace)
if (line.match(/^\s/) && currentHeader) {
headers[currentHeader] += ' ' + line.trim();
} else {
// New header
const match = line.match(/^([^:]+):\s*(.*)$/);
if (match) {
currentHeader = match[1].toLowerCase();
headers[currentHeader] = match[2].trim();
}
}
}
// Get body
const body = lines.slice(headerEnd).join('\n');
// Display email
displayEmail(headers, body, rawHeaders);
}
function displayEmail(headers, body, rawHeaders) {
// Subject
document.getElementById('subject').textContent =
decodeHeader(headers['subject']) || '(Kein Betreff)';
// From
document.getElementById('from').textContent =
decodeHeader(headers['from']) || '(Unbekannt)';
// To
document.getElementById('to').textContent =
decodeHeader(headers['to']) || '(Unbekannt)';
// Date
document.getElementById('date').textContent =
headers['date'] || '(Unbekannt)';
// CC (optional)
if (headers['cc']) {
document.getElementById('ccField').style.display = 'flex';
document.getElementById('cc').textContent = decodeHeader(headers['cc']);
} else {
document.getElementById('ccField').style.display = 'none';
}
// Raw headers
document.getElementById('rawHeadersContent').textContent = rawHeaders;
// Body
displayBody(body, headers);
// Show viewer
document.getElementById('emailViewer').style.display = 'block';
}
function displayBody(body, headers) {
const contentType = headers['content-type'] || '';
const bodyDiv = document.getElementById('emailBody');
// Decode quoted-printable if needed
if (headers['content-transfer-encoding'] === 'quoted-printable') {
body = decodeQuotedPrintable(body);
}
// Check if HTML content
if (contentType.includes('text/html')) {
// Create iframe for safe HTML display
const iframe = document.createElement('iframe');
iframe.style.width = '100%';
iframe.style.border = 'none';
iframe.style.minHeight = '400px';
bodyDiv.innerHTML = '';
bodyDiv.appendChild(iframe);
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
iframeDoc.open();
iframeDoc.write(body);
iframeDoc.close();
// Adjust iframe height to content
iframe.onload = function() {
iframe.style.height = (iframe.contentWindow.document.body.scrollHeight + 20) + 'px';
};
} else {
// Plain text - convert to HTML with line breaks
bodyDiv.innerHTML = '<pre style="white-space: pre-wrap; word-wrap: break-word; font-family: inherit;">' +
escapeHtml(body) + '</pre>';
}
}
function decodeQuotedPrintable(str) {
// Basic quoted-printable decoder
return str
.replace(/=\r?\n/g, '') // Remove soft line breaks
.replace(/=([0-9A-F]{2})/gi, (match, hex) => {
return String.fromCharCode(parseInt(hex, 16));
});
}
function decodeHeader(header) {
if (!header) return '';
// Decode RFC 2047 encoded words (=?charset?encoding?text?=)
return header.replace(/=\?([^?]+)\?([BQ])\?([^?]+)\?=/gi, (match, charset, encoding, text) => {
if (encoding.toUpperCase() === 'B') {
// Base64
try {
return atob(text);
} catch (e) {
return text;
}
} else if (encoding.toUpperCase() === 'Q') {
// Quoted-printable
return decodeQuotedPrintable(text.replace(/_/g, ' '));
}
return text;
});
}
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
function toggleHeaders() {
const headersDiv = document.getElementById('rawHeaders');
const btn = event.target;
if (headersDiv.style.display === 'none' || headersDiv.style.display === '') {
headersDiv.style.display = 'block';
btn.textContent = 'Rohe Header ausblenden';
} else {
headersDiv.style.display = 'none';
btn.textContent = 'Rohe Header anzeigen';
}
}
</script>
</body>
</html>

View File

@@ -205,6 +205,10 @@
<h2 class="tool-title">DSGVO-Export Hilfe</h2>
<p class="tool-description">Informationen zum Beantragen von DSGVO-Exporten bei verschiedenen Diensten.</p>
</a>
<a href="https://tools.ponywave.de/eml_viewer" class="tool-bubble">
<h2 class="tool-title">EML Viewer</h2>
<p class="tool-description">E-Mail-Dateien (.eml) sicher und lokal im Browser betrachten</p>
</a>
<a href="https://tools.ponywave.de/text_cleaner" class="tool-bubble">
<h2 class="tool-title">Text Cleaner</h2>
<p class="tool-description">Entferne doppelte Zeilen aus einem Text</p>

View File

@@ -11,6 +11,7 @@ https://tools.ponywave.de/chrome_extensions_checker
https://tools.ponywave.de/depp_gpt
https://tools.ponywave.de/dogify
https://tools.ponywave.de/dsgvo_helper
https://tools.ponywave.de/eml_viewer
https://tools.ponywave.de/emoji
https://tools.ponywave.de/emoji_jump
https://tools.ponywave.de/favorites_viewer