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>
|
<h2 class="tool-title">DSGVO-Export Hilfe</h2>
|
||||||
<p class="tool-description">Informationen zum Beantragen von DSGVO-Exporten bei verschiedenen Diensten.</p>
|
<p class="tool-description">Informationen zum Beantragen von DSGVO-Exporten bei verschiedenen Diensten.</p>
|
||||||
</a>
|
</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">
|
<a href="https://tools.ponywave.de/text_cleaner" class="tool-bubble">
|
||||||
<h2 class="tool-title">Text Cleaner</h2>
|
<h2 class="tool-title">Text Cleaner</h2>
|
||||||
<p class="tool-description">Entferne doppelte Zeilen aus einem Text</p>
|
<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/depp_gpt
|
||||||
https://tools.ponywave.de/dogify
|
https://tools.ponywave.de/dogify
|
||||||
https://tools.ponywave.de/dsgvo_helper
|
https://tools.ponywave.de/dsgvo_helper
|
||||||
|
https://tools.ponywave.de/eml_viewer
|
||||||
https://tools.ponywave.de/emoji
|
https://tools.ponywave.de/emoji
|
||||||
https://tools.ponywave.de/emoji_jump
|
https://tools.ponywave.de/emoji_jump
|
||||||
https://tools.ponywave.de/favorites_viewer
|
https://tools.ponywave.de/favorites_viewer
|
||||||
|
|||||||
Reference in New Issue
Block a user