MailDingo

Methodology, sources and tests

What the analyser does with the text you paste, what it deliberately can't do, the open data behind it, and the test results from this build.

206/206parser tests passed
10,396public-suffix rules (2026-10-31)
1,787look-alike characters (Unicode 18.0.0)
44 msslowest hostile-input test

How an analysis works

  1. Find the header block. The paste is split at blank lines and the block with the most recognisable header fields is used, so a whole message source, a Gmail "Show original" page copied with its summary table, or an mbox file all work. Input is capped at 1,000,000 characters and 3,000 fields.
  2. Unfold folded lines (a line break followed by a space or tab is removed, RFC 5322 §2.2.3) and decode encoded-words in names and subjects (RFC 2047: B and Q encodings, any charset the browser knows).
  3. Parse each field with small hand-written scanners that understand quoted strings and nested comments (RFC 5322 §3.2.2): addresses, dates (including the obsolete forms of §4.3: two-digit years, named zones like EST and PDT), Received clauses (from, by, with, id, for and the date after the last semicolon, RFC 5321 §4.4), Authentication-Results (RFC 8601), ARC (RFC 8617), Received-SPF (RFC 7208 §9.1) and DKIM-Signature tags (RFC 6376 §3.5). Every scanner is linear: no regular expression can backtrack over a long field.
  4. Route. Received fields are read bottom-up, every timestamp is converted to UTC, and the gap between consecutive hops is computed. Gaps of 5 minutes or more are highlighted, an hour or more in red; a hop that seems to go back in time by more than 2 minutes is labelled clock skew. The last hop where the sending and receiving hosts belong to different organisations is marked as where your provider took the message in: its IP address was observed by the receiving server, unlike anything below it.
  5. Authentication. Only the topmost Authentication-Results field's server (the authserv-id) is treated as your provider; fields from other servers lower down are listed separately, because a sender can write anything there (RFC 8601 §5). Microsoft 365 writes its field without a server name; when such a field is on top it is used too.
  6. Alignment. The From domain is compared with the domain SPF checked (smtp.mailfrom, else Received-SPF's envelope-from, else Return-Path) and each DKIM signing domain (header.d). Relaxed alignment means the same organisational domain, strict means identical (RFC 9989 §3.2.10).
  7. Red flags and verdict from the rules below.

What it can't do

Red-flag rules

FlagSeverityRaised when
DMARC failedhighYour provider recorded dmarc=fail and no arc=pass.
DMARC failed, forwarder vouchesmediumdmarc=fail together with arc=pass.
SPF fail/softfail and no valid DKIMhigh (fail) / medium (softfail)No DKIM pass to compensate, and no DMARC result already covering it.
Display name contains a different addresshighThe name part of From contains an email address other than the real one (medium-low if it's the same organisation).
Display name names another domain / mixes alphabetsmediumA domain-like word in the name that isn't the From organisation; Latin mixed with Cyrillic, Greek or other scripts.
From domain mixes alphabetshighAny label of the From domain (after punycode decoding, RFC 3492) contains letters from more than one script.
From domain imitates anotherhighThe From domain's skeleton (below) equals that of another domain in the message (Reply-To, Return-Path, Sender, DKIM, Received, To, the display name) belonging to a different organisation.
International (punycode) From domainmediumContains xn-- labels or raw Unicode, without mixed scripts.
Replies go to a different domainmedium (low on mailing lists)Reply-To's organisation differs from From's.
Return-Path doesn't match Frommedium / noteDifferent organisations and no aligned DKIM pass; only a note when DKIM aligns or a list/forwarder is involved.
No authentication resultsmediumNo Authentication-Results and no Received-SPF field at all.
Date later than delivery / long before itlowDate header more than 15 minutes after the first Received time, or more than 2 days before it.
Encoded name for no reasonlowThe From name is MIME-encoded but decodes to plain ASCII.
Partial DKIM body (l=)lowA DKIM-Signature carries l= (RFC 6376 §8.2).
Slow hop / clock skewlow / noteA hop gap of an hour or more (5 minutes or more is a note) / a negative gap over 2 minutes.

Verdict: any high flag gives Suspicious. Otherwise a DMARC pass (or, with no DMARC result, an aligned SPF or DKIM pass) and no medium flags gives Looks genuine; with medium flags, Check carefully. No authentication data at all gives Can't tell.

Look-alike detection

Domains are decoded from punycode, then each character is mapped through the Unicode confusables data (Unicode Technical Standard #39, version 18.0.0), keeping the 1,787 mappings whose target is one to three ASCII letters or digits, plus Unicode compatibility decomposition (so fullwidth e becomes e). This is a simplified skeleton: real UTS #39 also maps multi-character sequences and non-Latin targets. On top of that, the common ASCII swaps rn→m, vv→w, cl→d, 0→o, 1→l and 5→s are folded. Mixed-script detection checks Latin, Cyrillic, Greek, Armenian, Cherokee, Han, Arabic and Hebrew per label (UTS #39 §5.1, simplified).

Sending-service rules

A host, DKIM signing domain, Return-Path or Message-ID domain that equals or ends in one of these domains names the service. It's a static, documented table, not a guess: a name not on it is simply not identified.

ServiceKindMatched domains
Google (Gmail / Google Workspace)mailboxgoogle.com, googlemail.com, gmail.com
Microsoft (Outlook.com / Exchange Online)mailboxoutlook.com, protection.outlook.com, hotmail.com, office365.com, onmicrosoft.com, outlook.office365.com
Yahoo / AOL Mailmailboxyahoo.com, yahoodns.net, aol.com
Apple iCloud Mailmailboxicloud.com, me.com, mac.com
Proton Mailmailboxprotonmail.ch, proton.me, protonmail.com
Fastmailmailboxmessagingengine.com, fastmail.com
Zoho Mailmailboxzoho.com, zohomail.com, zoho.eu
Amazon SESsending serviceamazonses.com
SendGrid (Twilio)sending servicesendgrid.net
Mailchimp / Mandrillsending servicemcsv.net, mcdlv.net, rsgsv.net, mandrillapp.com
Mailgunsending servicemailgun.org, mailgun.net
Postmarksending servicemtasv.net, postmarkapp.com
SparkPostsending servicesparkpostmail.com
Brevo (Sendinblue)sending servicesendinblue.com, brevo.com
HubSpotsending servicehubspotemail.net
Salesforce Marketing Cloudsending serviceexacttarget.com
Mimecastsecurity gatewaymimecast.com
Proofpointsecurity gatewaypphosted.com
Barracudasecurity gatewaybarracudanetworks.com
Cisco Secure Emailsecurity gatewayiphmx.com

Test results for this build

Every weekly build runs the test suite under Node.js v20.19.2 against the exact mailcheck.js file your browser downloads. If any test fails, the build stops and the previous version of the site stays online. Run on 2026-11-01.

GroupWhat it coversPassed
unfoldUnfolding folded header lines (RFC 5322 §2.2.3), line endings, header-block detection12/12
encodedEncoded-words (RFC 2047): B and Q encodings, charsets, adjacent words, malformed input12/12
datesDate parsing (RFC 5322 §3.3) including obsolete forms (§4.3), named zones and odd formats21/21
receivedReceived field parsing: Postfix, Exim, Gmail, Exchange Online, SendGrid, IPv6, TLS, missing parts16/16
authresAuthentication-Results (RFC 8601), ARC-Authentication-Results (RFC 8617) and vendor variants10/10
addressAddress parsing: display names, quoting, encoded names, groups, comments10/10
domainsOrganisational domains via the Public Suffix List, punycode (RFC 3492)11/11
lookalikeLook-alike domains: mixed scripts, Unicode confusables skeleton (UTS #39), ASCII swaps10/10
providersSending-service identification from the documented hostname table7/7
hostileHostile and malformed input: huge pastes, pathological nesting; every case must finish quickly and render escaped HTML15/15
registryEvery active IANA result code for spf, dkim, dmarc, arc, iprev and auth has a plain-English explanation32/32
examplesSynthetic example messages: expected verdicts, flags, delays and alignment50/50

Hostile input

Each case must be parsed and rendered in under 3 seconds without throwing, and the output must contain no unescaped markup. Times from this build:

InputSizeTime
1 MB single line, no newline1,000,010 chars44 ms
2 MB paste is truncated to 1 MB2,054,011 chars21 ms
100,000 nested parentheses100,054 chars2 ms
100,000 unbalanced quotes100,021 chars7 ms
50,000 encoded-word fragments500,009 chars5 ms
20,000 valid encoded-words280,009 chars38 ms
10,000 Received fields1,170,000 chars15 ms
100,000 continuation lines300,017 chars39 ms
random binary bytes300,000 chars0 ms
10,000 semicolons in Authentication-Results100,038 chars3 ms
long IPv6-ish token100,056 chars1 ms
many '@' in From200,006 chars2 ms
PSL walk on 10,000-label domain20,011 chars6 ms

Plain-English explanations, checked against the RFCs

Each one-line explanation the analyser shows was written from, and checked by hand against, the section that defines the result. The list of result codes is read from IANA's registry every week; the build fails if a registered code for these methods has no explanation.

ResultDefined inWhat MailDingo says
arc=failRFC 8617 §4.4, §5.2 (via RFC 8617 §2.2)The ARC chain is broken: a seal did not verify, so earlier servers' results can't be relied on.
arc=noneRFC 8617 §4.4, §5.2 (via RFC 8617 §2.2)No ARC chain: the message was not sealed by any intermediary.
arc=passRFC 8617 §4.4, §5.2 (via RFC 8617 §2.2)The ARC chain is intact: every forwarding server's seal verified.
auth=failRFC 8601 §2.7.4The sender tried to log in and failed.
auth=noneRFC 8601 §2.7.4No login was used.
auth=passRFC 8601 §2.7.4The sender logged in to submit this message.
auth=permerrorRFC 8601 §2.7.4A permanent error during login checking.
auth=temperrorRFC 8601 §2.7.4A temporary error during login checking.
dkim=failRFC 8601 §2.7.1A signature was present but did not verify: the message was changed after signing, or the signature is forged.
dkim=neutralRFC 8601 §2.7.1A signature was present but had syntax errors or couldn't be processed, so the message is treated as unsigned.
dkim=noneRFC 8601 §2.7.1The message was not DKIM-signed.
dkim=passRFC 8601 §2.7.1The signature verified: the signing domain really handled this message and the signed content is unchanged.
dkim=permerrorRFC 8601 §2.7.1The signature can't ever be verified because of a permanent problem, such as a missing key or a required header field that isn't there.
dkim=policyRFC 8601 §2.7.1The message was signed, but something about the signature wasn't acceptable to the receiver (for example a weak key, an outdated algorithm or a body-length limit).
dkim=temperrorRFC 8601 §2.7.1The signing key couldn't be fetched because of a temporary DNS problem.
dmarc=failRFC 9989 §9.2Neither SPF nor DKIM passed for a domain aligned with the From domain, and that domain publishes DMARC: the From address is not authenticated.
dmarc=noneRFC 9989 §9.2The From domain publishes no DMARC record, so the receiver had no way to judge the From address.
dmarc=passRFC 9989 §9.2SPF or DKIM passed for a domain that aligns with the visible From domain: the From address is authentic.
dmarc=permerrorRFC 9989 §9.2The From domain's DMARC record is broken and can't be used.
dmarc=temperrorRFC 9989 §9.2A temporary DNS problem stopped the DMARC check.
iprev=failRFC 8601 §2.7.3The sending IP's reverse DNS name doesn't point back to it (or doesn't exist when looked up forward); common on badly run servers and spam sources.
iprev=passRFC 8601 §2.7.3The sending IP's reverse DNS name points back to it.
iprev=permerrorRFC 8601 §2.7.3The sending IP has no reverse DNS name at all.
iprev=temperrorRFC 8601 §2.7.3A temporary DNS problem stopped the reverse DNS check.
spf=failRFC 7208 §2.6 (via RFC 8601 §2.7.2)The envelope domain says this server is NOT allowed to send its mail (a hard "-all" fail).
spf=neutralRFC 7208 §2.6 (via RFC 8601 §2.7.2)The envelope domain's SPF record makes no statement about this server ("?all").
spf=noneRFC 7208 §2.6 (via RFC 8601 §2.7.2)The envelope domain publishes no SPF record (or no domain could be checked), so nothing was verified.
spf=passRFC 7208 §2.6 (via RFC 8601 §2.7.2)The sending server is on the envelope domain's list of permitted senders.
spf=permerrorRFC 7208 §2.6 (via RFC 8601 §2.7.2)The domain's SPF record is broken (syntax error or too many DNS lookups), so it can't be evaluated.
spf=policyRFC 8601 §2.7.2The server was authorised by SPF, but the receiver's own policy found the result unacceptable (for example, the domain is on its block list). Rarely used.
spf=softfailRFC 7208 §2.6 (via RFC 8601 §2.7.2)The envelope domain says this server probably shouldn't send its mail ("~all"), but asks receivers not to reject outright.
spf=temperrorRFC 7208 §2.6 (via RFC 8601 §2.7.2)A temporary DNS problem stopped the check; a retry might give a real answer.

Sources and licences