From 7ed347c86e5fd565d9982d045cc1621a81672224 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Fri, 24 Oct 2025 10:22:16 +0700 Subject: [PATCH] Improve test display in some circonstancies --- pkg/analyzer/content.go | 22 ++----- .../lib/components/AuthenticationCard.svelte | 36 ++++++----- .../lib/components/ContentAnalysisCard.svelte | 6 +- .../lib/components/DkimRecordsDisplay.svelte | 64 +++++++++++-------- web/src/lib/components/DnsRecordsCard.svelte | 8 +-- web/src/lib/components/EmailPathCard.svelte | 2 +- web/src/lib/components/ScoreCard.svelte | 12 ++-- web/src/lib/components/SummaryCard.svelte | 43 ++++++++++++- web/src/routes/test/[test]/+page.svelte | 2 +- 9 files changed, 118 insertions(+), 77 deletions(-) diff --git a/pkg/analyzer/content.go b/pkg/analyzer/content.go index 27eea4b..613e5d5 100644 --- a/pkg/analyzer/content.go +++ b/pkg/analyzer/content.go @@ -751,9 +751,7 @@ func (c *ContentAnalyzer) CalculateContentScore(results *ContentResults) (int, s brokenLinks++ } } - if brokenLinks == 0 { - score += 20 - } + score += 20 * brokenLinks / len(results.Links) // Too much links, 10 points penalty if len(results.Links) > 30 { score -= 10 @@ -771,11 +769,7 @@ func (c *ContentAnalyzer) CalculateContentScore(results *ContentResults) (int, s noAltCount++ } } - if noAltCount == 0 { - score += 15 - } else if noAltCount < len(results.Images) { - score += 7 - } + score += 15 * noAltCount / len(results.Images) } else { // No images is Ok score += 15 @@ -795,20 +789,12 @@ func (c *ContentAnalyzer) CalculateContentScore(results *ContentResults) (int, s // Penalize suspicious URLs (deduct up to 5 points) if len(results.SuspiciousURLs) > 0 { - penalty := len(results.SuspiciousURLs) - if penalty > 5.0 { - penalty = 5 - } - score -= penalty + score -= min(len(results.SuspiciousURLs), 5) } // Penalize harmful HTML tags (deduct 20 points per harmful tag, max 40 points) if len(results.HarmfullIssues) > 0 { - penalty := len(results.HarmfullIssues) * 20 - if penalty > 40 { - penalty = 40 - } - score -= penalty + score -= min(len(results.HarmfullIssues)*20, 40) } // Ensure score is between 0 and 100 diff --git a/web/src/lib/components/AuthenticationCard.svelte b/web/src/lib/components/AuthenticationCard.svelte index c43be7d..c14d4ec 100644 --- a/web/src/lib/components/AuthenticationCard.svelte +++ b/web/src/lib/components/AuthenticationCard.svelte @@ -12,7 +12,7 @@ let { authentication, authenticationGrade, authenticationScore, dnsResults }: Props = $props(); - function getAuthResultClass(result: string): string { + function getAuthResultClass(result: string, noneIsFail: boolean): string { switch (result) { case "pass": return "text-success"; @@ -22,12 +22,14 @@ case "softfail": case "neutral": return "text-warning"; + case "none": + return noneIsFail ? "text-danger" : "text-muted"; default: return "text-muted"; } } - function getAuthResultIcon(result: string): string { + function getAuthResultIcon(result: string, noneIsFail: boolean): string { switch (result) { case "pass": return "bi-check-circle-fill"; @@ -38,6 +40,8 @@ return "bi-exclamation-circle-fill"; case "missing": return "bi-dash-circle-fill"; + case "none": + return noneIsFail ? "bi-x-circle-fill" : "bi-question-circle"; default: return "bi-question-circle"; } @@ -77,10 +81,10 @@ {#if authentication.iprev}
- +
IP Reverse DNS - + {authentication.iprev.result} {#if authentication.iprev.ip} @@ -107,10 +111,10 @@
{#if authentication.spf} - +
SPF - + {authentication.spf.result} {#if authentication.spf.domain} @@ -140,10 +144,10 @@
{#if authentication.dkim && authentication.dkim.length > 0} - +
DKIM - + {authentication.dkim[0].result} {#if authentication.dkim[0].domain} @@ -179,10 +183,10 @@
{#if authentication.dmarc} - +
DMARC - + {authentication.dmarc.result} {#if authentication.dmarc.domain} @@ -205,11 +209,13 @@
{/snippet} - {#if authentication.dmarc.details.indexOf("policy.published-domain-policy=") > 0} - {@const policy = authentication.dmarc.details.replace(/^.*policy.published-domain-policy=([^\s]+).*$/, "$1")} - {@render DMARCPolicy(policy)} - {:else if authentication.dmarc.domain} - {@render DMARCPolicy(dnsResults.dmarc_record.policy)} + {#if authentication.dmarc.result != "none"} + {#if authentication.dmarc.details.indexOf("policy.published-domain-policy=") > 0} + {@const policy = authentication.dmarc.details.replace(/^.*policy.published-domain-policy=([^\s]+).*$/, "$1")} + {@render DMARCPolicy(policy)} + {:else if authentication.dmarc.domain} + {@render DMARCPolicy(dnsResults.dmarc_record.policy)} + {/if} {/if} {#if authentication.dmarc.details}
{authentication.dmarc.details}
diff --git a/web/src/lib/components/ContentAnalysisCard.svelte b/web/src/lib/components/ContentAnalysisCard.svelte index bc65de0..b5fc380 100644 --- a/web/src/lib/components/ContentAnalysisCard.svelte +++ b/web/src/lib/components/ContentAnalysisCard.svelte @@ -71,7 +71,7 @@ {#if contentAnalysis.html_issues && contentAnalysis.html_issues.length > 0}
-
Content Issues
+
Content Issues
{#each contentAnalysis.html_issues as issue}
@@ -97,7 +97,7 @@ {#if contentAnalysis.links && contentAnalysis.links.length > 0}
-
Links ({contentAnalysis.links.length})
+
Links ({contentAnalysis.links.length})
@@ -132,7 +132,7 @@ {#if contentAnalysis.images && contentAnalysis.images.length > 0}
-
Images ({contentAnalysis.images.length})
+
Images ({contentAnalysis.images.length})
diff --git a/web/src/lib/components/DkimRecordsDisplay.svelte b/web/src/lib/components/DkimRecordsDisplay.svelte index 45c67b3..fad7205 100644 --- a/web/src/lib/components/DkimRecordsDisplay.svelte +++ b/web/src/lib/components/DkimRecordsDisplay.svelte @@ -8,30 +8,31 @@ let { dkimRecords }: Props = $props(); // Compute overall validity - const dkimIsValid = $derived( - dkimRecords?.reduce((acc, r) => acc && r.valid, true) ?? false - ); + const dkimIsValid = $derived(dkimRecords?.reduce((acc, r) => acc && r.valid, true) ?? false); -{#if dkimRecords && dkimRecords.length > 0} -
-
-
- - DomainKeys Identified Mail -
- DKIM -
-
-

DKIM cryptographically signs your emails, proving they haven't been tampered with in transit. Receiving servers verify this signature against your DNS records.

-
-
+
+
+
+ + DomainKeys Identified Mail +
+ DKIM +
+
+

+ DKIM cryptographically signs your emails, proving they haven't been tampered with in + transit. Receiving servers verify this signature against your DNS records. +

+
+
+ {#if dkimRecords && dkimRecords.length > 0} {#each dkimRecords as dkim}
@@ -48,17 +49,26 @@
{#if dkim.record}
- Record:
- {dkim.record} + Record:
+ {dkim.record}
{/if} {#if dkim.error}
- Error: {dkim.error} + Error: + {dkim.error}
{/if}
{/each} -
+ {:else} +
+ + No DKIM signatures found in this email. DKIM provides cryptographic authentication and + helps avoid spoofing, thus improving deliverability. +
+ {/if}
-{/if} +
diff --git a/web/src/lib/components/DnsRecordsCard.svelte b/web/src/lib/components/DnsRecordsCard.svelte index e49ce97..3a73432 100644 --- a/web/src/lib/components/DnsRecordsCard.svelte +++ b/web/src/lib/components/DnsRecordsCard.svelte @@ -63,8 +63,8 @@ {#if receivedChain && receivedChain.length > 0}
-

- Received by: {receivedChain[0].from} ({receivedChain[0].reverse || "Unknown"} [{receivedChain[0].ip}]) +

+ Received from: {receivedChain[0].from} ({receivedChain[0].reverse || "Unknown"} [{receivedChain[0].ip}])

{/if} @@ -84,7 +84,7 @@
-

+

Return-Path Domain: {dnsResults.rp_domain || dnsResults.from_domain}

{#if (domainAlignment && !domainAlignment.aligned && !domainAlignment.relaxed_aligned) || (domainAlignment && !domainAlignment.aligned && domainAlignment.relaxed_aligned && dnsResults.dmarc_record && dnsResults.dmarc_record.spf_alignment === "strict") || (!domainAlignment && dnsResults.rp_domain && dnsResults.rp_domain !== dnsResults.from_domain)} @@ -116,7 +116,7 @@
-

+

From Domain: {dnsResults.from_domain}

{#if dnsResults.rp_domain && dnsResults.rp_domain !== dnsResults.from_domain} diff --git a/web/src/lib/components/EmailPathCard.svelte b/web/src/lib/components/EmailPathCard.svelte index c8b9a67..422ba0a 100644 --- a/web/src/lib/components/EmailPathCard.svelte +++ b/web/src/lib/components/EmailPathCard.svelte @@ -17,7 +17,7 @@
{receivedChain.length - i} - {hop.reverse || '-'}{#if hop.ip} ({hop.ip}){/if} → {hop.by || 'Unknown'} + {hop.reverse || '-'} {#if hop.ip}({hop.ip}){/if} → {hop.by || 'Unknown'}
{hop.timestamp ? new Intl.DateTimeFormat('default', { dateStyle: 'long', 'timeStyle': 'short' }).format(new Date(hop.timestamp)) : '-'}
diff --git a/web/src/lib/components/ScoreCard.svelte b/web/src/lib/components/ScoreCard.svelte index d1e6b5d..11e5396 100644 --- a/web/src/lib/components/ScoreCard.svelte +++ b/web/src/lib/components/ScoreCard.svelte @@ -42,7 +42,7 @@ {#if summary}
-
+ -
+ -
+ -
+ -
+ -
+
diff --git a/web/src/lib/components/SummaryCard.svelte b/web/src/lib/components/SummaryCard.svelte index 393a847..43ea811 100644 --- a/web/src/lib/components/SummaryCard.svelte +++ b/web/src/lib/components/SummaryCard.svelte @@ -85,6 +85,41 @@ segments.push({ text: " (lacks proper authentication)" }); } + // SPF specific issues + if (spfResult && spfResult !== "pass") { + segments.push({ text: ". SPF check " }); + if (spfResult === "fail") { + segments.push({ + text: "failed", + highlight: { color: "danger", bold: true }, + link: "#authentication-spf" + }); + segments.push({ text: ", the sending server is not authorized to send mail for this domain" }); + } else if (spfResult === "softfail") { + segments.push({ + text: "soft-failed", + highlight: { color: "warning", bold: true }, + link: "#authentication-spf" + }); + segments.push({ text: ", the sending server may not be authorized" }); + } else if (spfResult === "temperror" || spfResult === "permerror") { + segments.push({ + text: "encountered an error", + highlight: { color: "warning", bold: true }, + link: "#authentication-spf" + }); + segments.push({ text: ", check your SPF record configuration" }); + } else if (spfResult === "none") { + segments.push({ text: "Your domain has " }); + segments.push({ + text: "no SPF record", + highlight: { color: "danger", bold: true }, + link: "#dns-spf" + }); + segments.push({ text: ", you should add one to specify which servers can send email on your behalf" }); + } + } + // IP Reverse DNS (iprev) check const iprevResult = report.authentication?.iprev; if (iprevResult) { @@ -207,7 +242,9 @@ if (dmarcRecord.policy === "reject") { segments.push({ text: ", which is great" }); } else { - segments.push({ text: ", consider switching to reject" }); + segments.push({ text: ", consider switching to '" }); + segments.push({ text: "reject", highlight: { monospace: true, bold: true } }); + segments.push({ text: "'" }); } } } else if (dmarcResult && dmarcResult.result === "fail") { @@ -238,6 +275,8 @@ highlight: { color: "warning", bold: true }, link: "#dns-bimi" }); + segments.push({ text: ", you could " }); + segments.push({ text: "add a record to decline participation", highlight: { bold: true } }); } else if (bimiResult || bimiRecord) { segments.push({ text: ". Your domain has " }); segments.push({ @@ -395,7 +434,7 @@ {segment.text} {/if} {/each} - Overall, your email received a grade {#if report.grade == "A" || report.grade == "A+"}, well done 🎉{/if}! Check the details below 🔽 + Overall, your email received a grade {#if report.grade == "A" || report.grade == "A+"}, well done 🎉{:else if report.grade == "C" || report.grade == "D"}: you should try to increase your score to ensure inbox delivery.{:else if report.grade == "E"}: you could have delivery issues with common providers.{:else if report.grade == "F"}: it will most likely be rejected by most providers.{:else}!{/if} Check the details below 🔽

diff --git a/web/src/routes/test/[test]/+page.svelte b/web/src/routes/test/[test]/+page.svelte index c79b9f4..59697e2 100644 --- a/web/src/routes/test/[test]/+page.svelte +++ b/web/src/routes/test/[test]/+page.svelte @@ -102,7 +102,7 @@ - {test ? `Test ${test.id.slice(0, 7)} - happyDeliver` : "Loading..."} + {report ? `Test of ${report.dns_results.from_domain} ${report.test_id.slice(0, 7)}` : (test ? `Test ${test.id.slice(0, 7)}` : "Loading...")} - happyDeliver