375 lines
15 KiB
HTML
375 lines
15 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>Email Header Analyzer</title>
|
|
<link rel="stylesheet" href="/static/style.css">
|
|
<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
</head>
|
|
<body>
|
|
<nav>
|
|
<a href="/">Analyze New Header</a>
|
|
<a href="/dns">DNS Tools</a>
|
|
<a href="/password">Password Generator</a>
|
|
</nav>
|
|
<div class="container">
|
|
<h1>Email Header Analyzer</h1>
|
|
{{if not .From}}
|
|
<form method="POST">
|
|
<textarea name="headers" placeholder="Paste email headers here..."></textarea>
|
|
<br>
|
|
<button type="submit">Analyze Headers</button>
|
|
</form>
|
|
{{end}}
|
|
|
|
{{if .From}}
|
|
<div id="report" class="container">
|
|
<div class="section" style="display: flex; align-items: flex-start; justify-content: space-between; gap: 30px;">
|
|
<div style="flex: 1 1 0; min-width: 0;">
|
|
<h2>Sender Identification</h2>
|
|
<div class="grid">
|
|
<div>
|
|
<p><b>Envelope Sender (Return-Path):</b> {{.EnvelopeSender}}</p>
|
|
<p><b>From Domain:</b> {{.FromDomain}}</p>
|
|
<p><b>Sending Server:</b> {{.SendingServer}}</p>
|
|
</div>
|
|
<div class="score-indicators">
|
|
<span class="status {{if .SPFPass}}good{{else}}error{{end}}" title="SPF">SPF {{if .SPFPass}}✓{{else}}✗{{end}}</span>
|
|
<span class="status {{if .DMARCPass}}good{{else}}error{{end}}" title="DMARC">DMARC {{if .DMARCPass}}✓{{else}}✗{{end}}</span>
|
|
<span class="status {{if .DKIMPass}}good{{else}}error{{end}}" title="DKIM">DKIM {{if .DKIMPass}}✓{{else}}✗{{end}}</span>
|
|
<span class="status {{if .Encrypted}}good{{else}}error{{end}}" title="Encrypted">Encrypted {{if .Encrypted}}✓{{else}}✗{{end}}</span>
|
|
{{if .Blacklists}}
|
|
<span class="status error" title="{{range .Blacklists}}{{.}}, {{end}}">Blacklisted {{len .Blacklists}} times</span>
|
|
{{else}}
|
|
<span class="status good">Not listed on major blacklists</span>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
{{if .SenderRep}}
|
|
<div>
|
|
<b><span>Sender Reputation: </span></b><div class="status {{if contains .SenderRep "EXCELLENT"}}good{{else if contains .SenderRep "GOOD"}}good{{else if contains .SenderRep "FAIR"}}warning{{else}}error{{end}}">
|
|
{{.SenderRep}}
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
<div class="explanation">
|
|
<small>
|
|
<b>Envelope Sender</b> is the real sender used for delivery (can differ from From).<br>
|
|
<b>From Domain</b> is the domain shown to the recipient.<br>
|
|
<b>Sending Server</b> is the host or IP that actually sent the message (from first Received header).<br>
|
|
If these differ, the message may be sent on behalf of another user or via a third-party service.
|
|
</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<details id="all-headers" class="section" style="margin-top:10px;">
|
|
<summary><b style="font-size: 1.5em;">All Email Headers Table</b></summary>
|
|
<div style="margin-bottom:10px;">
|
|
<input type="text" id="headerSearch" placeholder="Search headers..." style="width: 100%; max-width: 350px; padding: 5px; border-radius: 4px; border: 1px solid #444; background: #232323; color: #e0e0e0;">
|
|
</div>
|
|
<div style="overflow-x:auto;">
|
|
<table id="headersTable" style="width:100%; border-collapse:collapse; border:1px solid #444;">
|
|
<thead>
|
|
<tr>
|
|
<th style="text-align:left; padding:4px 8px; border:1px solid #444; width: 180px; background:#232323;">Header Name</th>
|
|
<th style="text-align:left; padding:4px 8px; border:1px solid #444; background:#232323;">Value</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{range $k, $v := .AllHeaders}}
|
|
<tr>
|
|
<td style="vertical-align:top; padding:4px 8px; border:1px solid #444; word-break:break-word;">{{$k}}</td>
|
|
<td style="vertical-align:top; padding:4px 8px; border:1px solid #444; white-space:pre-wrap; word-break:break-word;">{{$v}}</td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</details>
|
|
|
|
<div class="section">
|
|
<h2>Basic Information</h2>
|
|
<div class="grid">
|
|
<div>
|
|
<p><b>From:</b> {{.From}}</p>
|
|
<p><b>To:</b> {{.To}}</p>
|
|
<p><b>Subject:</b> {{.Subject}}</p>
|
|
<p><b>Date:</b> {{.Date}}</p>
|
|
{{if .ReplyTo}}<p><b>Reply-To:</b> {{.ReplyTo}}</p>{{end}}
|
|
</div>
|
|
<div>
|
|
<p><b>Message-ID:</b> {{.MessageID}}</p>
|
|
<p><b>Priority:</b> {{.Priority}}</p>
|
|
<p><b>Content Type:</b> {{.ContentType}}</p>
|
|
<p><b>Encoding:</b> {{.Encoding}}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h2>Mail Flow</h2>
|
|
<ul class="mail-flow">
|
|
{{range .Received}}<li>{{.}}</li>{{end}}
|
|
</ul>
|
|
</div>
|
|
|
|
{{if ne .DeliveryDelay "Insufficient data for delay analysis"}}
|
|
<div class="section">
|
|
<h2>Delivery Analysis</h2>
|
|
<p><b>Delivery Timing:</b> {{.DeliveryDelay}}</p>
|
|
{{if .GeoLocation}}<p><b>Geographic Info:</b> {{.GeoLocation}}</p>{{end}}
|
|
</div>
|
|
{{end}}
|
|
|
|
<div class="section">
|
|
<h2>Security Analysis</h2>
|
|
<div class="security-analysis-vertical">
|
|
<div class="section">
|
|
<h3>SPF Authentication</h3>
|
|
<div class="status {{if .SPFPass}}good{{else}}error{{end}}">
|
|
{{if .SPFPass}}✓ Passed{{else}}✗ Failed{{end}}
|
|
</div>
|
|
<p>{{.SPFDetails}}</p>
|
|
{{if .SPFRecord}}<pre>{{.SPFRecord}}</pre>{{end}}
|
|
{{if .SPFHeader}}
|
|
<details class="details"><summary>Show SPF Header</summary><pre>{{.SPFHeader}}</pre></details>
|
|
{{end}}
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h3>DMARC Policy</h3>
|
|
<div class="status {{if .DMARCPass}}good{{else}}error{{end}}">
|
|
{{if .DMARCPass}}✓ Passed{{else}}✗ Failed{{end}}
|
|
</div>
|
|
<p>{{.DMARCDetails}}</p>
|
|
{{if .DMARCRecord}}<pre>{{.DMARCRecord}}</pre>{{end}}
|
|
{{if .DMARCHeader}}
|
|
<details class="details"><summary>Show DMARC Header</summary><pre>{{.DMARCHeader}}</pre></details>
|
|
{{end}}
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h3>DKIM Signature</h3>
|
|
<div class="status {{if .DKIMPass}}good{{else}}error{{end}}">
|
|
{{if .DKIMPass}}✓ Present{{else}}✗ Missing{{end}}
|
|
</div>
|
|
<p>{{.DKIMDetails}}</p>
|
|
{{if .DKIM}}
|
|
<details class="details"><summary>Show DKIM Header</summary><pre>{{.DKIM}}</pre></details>
|
|
{{else if .DKIMHeader}}
|
|
<details class="details"><summary>Show DKIM Header</summary><pre>{{.DKIMHeader}}</pre></details>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h2>Encryption</h2>
|
|
<div class="status {{if .Encrypted}}good{{else}}error{{end}}">
|
|
{{if .Encrypted}}Encrypted (TLS){{else}}Not Encrypted{{end}}
|
|
</div>
|
|
<details><summary>Show Encryption Details</summary><pre>{{.EncryptionDetail}}</pre></details>
|
|
</div>
|
|
|
|
{{if .Warnings}}
|
|
<div class="section">
|
|
<h2>Warnings</h2>
|
|
<ul>
|
|
{{range .Warnings}}<li class="status warning">⚠️ {{.}}</li>{{end}}
|
|
</ul>
|
|
</div>
|
|
{{end}}
|
|
|
|
{{if .SecurityFlags}}
|
|
<div class="section">
|
|
<h2>Security Flags</h2>
|
|
<ul>
|
|
{{range .SecurityFlags}}<li class="status">🔒 {{.}}</li>{{end}}
|
|
</ul>
|
|
</div>
|
|
{{end}}
|
|
|
|
{{if .Blacklists}}
|
|
<div class="section">
|
|
<h2>Blacklist Status</h2>
|
|
<div style="margin-bottom: 6px;">
|
|
<b>Checked:</b>
|
|
{{if .SendingServer}}IP {{.SendingServer}}{{else if .FromDomain}}Domain {{.FromDomain}}{{end}}
|
|
</div>
|
|
<div class="status error">⚠️ Listed on the following blacklists:</div>
|
|
<ul>
|
|
{{range .Blacklists}}<li>{{.}}</li>{{end}}
|
|
</ul>
|
|
</div>
|
|
{{end}}
|
|
|
|
|
|
{{if .SpamFlags}}
|
|
<div class="section">
|
|
<h2>Spam Analysis</h2>
|
|
<div class="status {{if gt (len .SpamFlags) 0}}warning{{else}}good{{end}}">
|
|
{{if gt (len .SpamFlags) 0}}⚠️ Spam Indicators Found{{else}}✓ No Spam Indicators{{end}}
|
|
</div>
|
|
{{if .SpamScore}}<p><b>Spam Score:</b> {{.SpamScore}}</p>{{end}}
|
|
{{if .SpamFlags}}
|
|
<ul>
|
|
{{range .SpamFlags}}<li>{{.}}</li>{{end}}
|
|
</ul>
|
|
{{end}}
|
|
</div>
|
|
{{end}}
|
|
|
|
{{if ne .VirusInfo "No virus scanning information found"}}
|
|
<div class="section">
|
|
<h2>Virus Scanning</h2>
|
|
<div class="status good">🛡️ Virus Scanning Information</div>
|
|
<p>{{.VirusInfo}}</p>
|
|
</div>
|
|
{{end}}
|
|
|
|
{{if .PhishingRisk}}
|
|
<div class="section">
|
|
<h2>Security Risk Assessment</h2>
|
|
<div class="security-analysis-vertical">
|
|
<div class="section">
|
|
<h3>Phishing Risk</h3>
|
|
<div class="status {{if eq (index (splitString .PhishingRisk " ") 0) "HIGH"}}error{{else if eq (index (splitString .PhishingRisk " ") 0) "MEDIUM"}}warning{{else}}good{{end}}">
|
|
{{.PhishingRisk}}
|
|
</div>
|
|
</div>
|
|
<div class="section">
|
|
<h3>Spoofing Risk</h3>
|
|
<div class="status {{if contains .SpoofingRisk "POTENTIAL"}}warning{{else}}good{{end}}">
|
|
{{.SpoofingRisk}}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
|
|
{{if .ListInfo}}
|
|
<div class="section">
|
|
<h2>Mailing List Information</h2>
|
|
<ul>
|
|
{{range .ListInfo}}<li>{{.}}</li>{{end}}
|
|
</ul>
|
|
{{if .AutoReply}}<p class="status">📧 Auto-reply message detected</p>{{end}}
|
|
{{if .BulkEmail}}<p class="status">📬 Bulk/marketing email detected</p>{{end}}
|
|
</div>
|
|
{{end}}
|
|
|
|
{{if .Compliance}}
|
|
<div class="section">
|
|
<h2>Compliance Information</h2>
|
|
<ul>
|
|
{{range .Compliance}}<li class="status good">✓ {{.}}</li>{{end}}
|
|
</ul>
|
|
</div>
|
|
{{end}}
|
|
|
|
{{if .ARC}}
|
|
<div class="section">
|
|
<h2>ARC (Authenticated Received Chain)</h2>
|
|
<details><summary>Show ARC Headers</summary>
|
|
<ul>
|
|
{{range .ARC}}<li><pre>{{.}}</pre></li>{{end}}
|
|
</ul>
|
|
</details>
|
|
</div>
|
|
{{end}}
|
|
|
|
{{if ne .BIMI "No BIMI record found"}}
|
|
<div class="section">
|
|
<h2>Brand Indicators (BIMI)</h2>
|
|
<p>{{.BIMI}}</p>
|
|
</div>
|
|
{{end}}
|
|
|
|
{{if .Attachments}}
|
|
<div class="section">
|
|
<h2>Attachment Information</h2>
|
|
<ul>
|
|
{{range .Attachments}}<li>{{.}}</li>{{end}}
|
|
</ul>
|
|
</div>
|
|
{{end}}
|
|
|
|
{{if .URLs}}
|
|
<div class="section">
|
|
<h2>URL Information</h2>
|
|
<ul>
|
|
{{range .URLs}}<li>{{.}}</li>{{end}}
|
|
</ul>
|
|
</div>
|
|
{{end}}
|
|
|
|
{{if ne .ThreadInfo "No threading information available"}}
|
|
<div class="section">
|
|
<h2>Message Threading</h2>
|
|
<details><summary>Show Threading Information</summary>
|
|
<pre>{{.ThreadInfo}}</pre>
|
|
</details>
|
|
</div>
|
|
{{end}}
|
|
|
|
|
|
<div class="section">
|
|
<button onclick="exportPDF()" type="button">Export as PDF</button>
|
|
<button onclick="exportImage()" type="button">Save as Image</button>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
|
|
<script>
|
|
// Template helper functions for the enhanced features
|
|
function splitString(str, delimiter) {
|
|
return str.split(delimiter);
|
|
}
|
|
|
|
function contains(str, substr) {
|
|
return str.includes(substr);
|
|
}
|
|
|
|
function exportImage() {
|
|
html2canvas(document.querySelector("#report")).then(canvas => {
|
|
let link = document.createElement("a");
|
|
link.download = "email-analysis.png";
|
|
link.href = canvas.toDataURL();
|
|
link.click();
|
|
});
|
|
}
|
|
|
|
function exportPDF() {
|
|
// Expand all details before export
|
|
document.querySelectorAll('#report details').forEach(d => d.open = true);
|
|
document.getElementById('all-headers').open = true;
|
|
const element = document.getElementById('report');
|
|
const opt = {
|
|
margin: 0.1,
|
|
filename: 'email-analysis.pdf',
|
|
image: { type: 'jpeg', quality: 0.98 },
|
|
html2canvas: { scale: 2, useCORS: true },
|
|
jsPDF: { unit: 'in', format: 'a4', orientation: 'portrait', putOnlyUsedFonts:true }
|
|
};
|
|
html2pdf().set(opt).from(element).save();
|
|
}
|
|
|
|
// Header table search
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
var search = document.getElementById('headerSearch');
|
|
if (search) {
|
|
search.addEventListener('input', function() {
|
|
var filter = search.value.toLowerCase();
|
|
var rows = document.querySelectorAll('#headersTable tbody tr');
|
|
rows.forEach(function(row) {
|
|
var text = row.textContent.toLowerCase();
|
|
row.style.display = text.indexOf(filter) > -1 ? '' : 'none';
|
|
});
|
|
});
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|