Neu: EML-Viewer
This commit is contained in:
BIN
eml_viewer/icon.png
Normal file
BIN
eml_viewer/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
535
eml_viewer/index.html
Normal file
535
eml_viewer/index.html
Normal 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> |
|
||||
© <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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user