Method
The same measurement, six months later
A finding that cannot be redone is an opinion. Here is how ours is redone, identically, with the same evidence — and how each score is reconstructed from what is published here.
- Analyzers in production
- 26 analyzers
- Weighting version
- weighting v13
- Scoring version
- scoring v1
- Archive
- archive written once
01
The observation point
We do not measure what a sending platform claims to send. We receive emails, like a subscriber, on addresses we control, and we read what actually arrived. Everything else on this page follows from that choice.
- Collection
- We sign ourselves up to brands' communications, from ordinary addresses. What arrives forms the public corpus, the one behind brand reports and comparisons.
- The upload
- A customer sends us one of their emails, as a file or by forwarding. The same analyzers read it; it is attached to their account and is never included in any public aggregate.
- Claiming
- A brand adds our contact card to its sending platform. It is the only route that gives us its transactional emails, and it asks for no access to its systems.
No integration, no API, no credentials. And if a finding seems wrong to you, you can check it yourself: receive the same message, open its source, look for the cited excerpt.
02
The archive
Written once
The raw message, as the receiving server received it, is written once and addressed by its content's fingerprint. It is never modified, never deleted, and two receptions of the same bytes make only one piece of evidence. Every measurement relies on this evidence and on nothing else: a message reconstructed after the fact would prove nothing.
Read, never rewritten
The application reads the archive; it does not write to it. The client that accesses it refuses any write under the corpus prefix; only uploads and imports are written, under their own prefix, and they are deleted along with the account that created them. No public page reads the archive: previews are produced at ingestion and served from the database, so that viewing a report never decides what gets read from storage.
What comes out of it, and what does not
Measurements, evidence excerpts, and thumbnails. Never a whole message. Never the addresses we receive it on: making them visible would allow filtering on them, and so escaping any measurement. The archive is hosted in the European Union.
03
The analyzers
A pure function
An analyzer is a function: the raw message and a context go in, findings come out. It has no state, makes no calls, and two runs on the same message give the same result, down to the character.
(raw message, context) → findings
What it knows of the world, and nothing else
Everything an analyzer needs is passed to it as a parameter, frozen for the duration of the run:
- the moment of the analysis — injected, never read from the clock;
- the domains of the attributed brand, empty if the message is quarantined;
- the known sending-infrastructure domains, which distinguish a measurement domain from a brand domain;
- the authentication authorities recognized for the mailbox that received the message;
- the sending-platform signatures, copied in rather than read from the database;
- a flag: is this message an artifact of our own sign-up;
- the tracking-pixel rule, published below with its dates.
No database, no network, no randomness. It is this context that makes the replay reproducible: on two machines, on two dates, the same archive and the same context give the same findings.
What a finding carries
- A key
pixel.detected,auth.dmarc— never a sentence. The label is resolved at display time, by language.- A signal
- What triggered the detection, not just the fact that it occurred. A tracker spotted by its host domain is not defended the same way as one spotted by its dimensions.
- Evidence
- The excerpt from the source, verbatim, truncated to 400 characters and flagged as such. It is the evidence.
- A location
- A named header, or a position in the HTML — enough to find the excerpt within the evidence.
- A signature
- The analyzer, its version, the date of the run.
The tracking-pixel rule
An image is a tracking pixel if one of these three signals holds; the finding says which. A pixel is recognised by its size, by the form of its address or by the host that serves it — never by being hidden alone.
-
Its size. A declared dimension —
widthorheightattribute, or inline style — of at most 2 px. Since Oct. 4, 2026.Hidden by its inline style (
display:none, visibility:hidden, width:0, height:0), an image is a pixel only if its address carries a recipient identifier. Hidden by a class or an@mediarule — the mobile and desktop switch of a content image —, it is not one, whatever its size. Since Oct. 4, 2026.A recipient identifier is, in a path segment, a token: at least 20 characters among letters, digits,
_and-, mixing upper case, lower case and digits. In a query value, a token, an email address in clear or encoded, or a hexadecimal hash of at least 32 characters.utm_…parameters never carry one: they are campaign labels. A short or purely numeric value identifies no one. Since Oct. 4, 2026. -
The form of its address. The image address contains one of these patterns, regardless of case:
Pattern Measurement point Since /open— Aug. 2, 2026 open?— Aug. 2, 2026 /o.gif— Aug. 2, 2026 /t.gif— Aug. 2, 2026 /oo.gif— Aug. 2, 2026 wf/open— Aug. 2, 2026 beacon— Aug. 2, 2026 /pixel— Aug. 2, 2026 pixel.— Aug. 2, 2026 /track— Aug. 2, 2026 track?— Aug. 2, 2026 /imp— Aug. 2, 2026 impression— Aug. 2, 2026 /spacer— Aug. 2, 2026 /blank.gif— Aug. 2, 2026 /t/o?Connectif Sept. 12, 2026 ?esid=Salesforce Sept. 12, 2026 &esid=Salesforce Sept. 12, 2026 /p.png?Boursobank Sept. 12, 2026 /tr/op/Brevo Oct. 4, 2026 /mk/op/Brevo Oct. 4, 2026 email-openVeepee Oct. 4, 2026 /probe.Zalando Oct. 4, 2026 - The host that serves it. A known measurement domain — that of an email platform, or of an engine that composes the image on open —, distinct from the brand's domains.
A pattern is added by one line of the rule and one entry in the methods log; the archive is then re-read with the new rule.
Not knowing is a state
A sending platform missing from the signatures table is not matched to the closest one: it is “unidentified”, qualified by hand, and the table grows without a redeploy. An email whose nature is not established is neither a campaign nor a transactional: it gets the common grid, and nothing else. Authentication is never recalculated: the verdict is the one the receiving server issued on arrival, dated by construction, read at the highest point of the chain on a recognized authority.
What's running, right now
26 analyzers, each with its current version. An older finding keeps its own — that's what makes it possible to retrace a past decision.
Analyzers in production
-
Attachments
attachments v1 -
Authentication
auth v2 -
Authoring tool
composer v1 -
Bulk-sending headers
bulk v1 -
Click tracking
links v11 -
Content fingerprint
shape v1 -
DKIM signature quality
dkim v1 -
Declared authentication
declared v2 -
Declared rendering
rendering v3 -
HTML validity
markup v1 -
Identity displayed
claims v1 -
Message format
rfc5322 v1 -
Open trackers
pixel v4 -
Privacy Policy
policy v2 -
Readability without images
image_free v2 -
Recipient identifier
recipient v1 -
Remote resources
resources v1 -
Reply address
reply_path v1 -
Sender identity
sender v2 -
Sender match
identity v5 -
Sending platform
esp v8 -
Subscription confirmation request
confirmation v3 -
Thread
thread v1 -
Type of email
kind v5 -
Unsubscribe
unsubscribe v6 -
Weight and structure
structure v3
04
The replay
Each finding carries its version
Changing an analyzer bumps its version. The findings produced by the old one stay; the new ones are written alongside. Nothing is overwritten: a report read yesterday reads identically tomorrow, and the gap between two versions is read, not guessed.
A criterion added travels back in time
A new analyzer is replayed over the entire archive. A criterion's history starts at the first piece of evidence archived, not on the day the idea came about. That's what makes it possible to say what a brand was doing in March on a criterion written in September.
Idempotent, resumable
The analyzer, version, message triplet is unique. Replaying the same batch twice gives the same database, and the test harness checks this on every change. Each analyzer has its golden files: any variation in output shows up as an explicit diff, reviewed before it is accepted.
To dispute is to replay
A disputed figure is redone: same evidence, same version, same context. We republish the calculation and the excerpt that establishes it, and we correct it if the error is on our side.
05
What we never do
Each of these actions would distort the data being measured, or the statistics of the brand being observed. None has an exception inside an analyzer.
- Load an image
- A single request to a brand's measurement domain registers an open. A message preview blocks every remote resource and shows the host it would have called in its place.
- Follow a link
- A tracked link registers a click and marks a contact as engaged. Links are counted, classified, read — never visited, not even to check they respond. A wrapped redirect is read from the URL itself.
- Open an attachment
- What a file is is read from its header bytes and its name, never by opening it.
- Recalculate authentication
- A redone check would query today's DNS. The verdict is the one the receiving server gave, on the date of receipt.
- Query the network from an analyzer
- The only request the product sends outward is the suspicious-email check, to domain-name registries — never to the sender's site. It lives outside the analyzers, and it is dated.
- Bypass a test set for a visitor
- A sign-up happens the way a subscriber would do it. A form behind a captcha stays out of reach, and that is a recorded result, not a problem to solve.
06
No language model in a measurement
No published measurement comes from a language model. A model does not give the same answer twice; a measurement that depended on one could not be replayed, and so could not be defended the day someone disputes it.
A model is used to read text, in a separate layer: the nature of an email when the headers aren't enough, a promotional mechanic, the wording of a consent. These readings are stored as interpretations, flagged as such in the report and in the data. They are never part of any score, any ranking, any alert.
And never on every message: the template fingerprint first, the model only on a template never seen before, under a daily cap that stops and says so.
07
How to read a report
The four states of a criterion
A state describes what was observed, never the severity of what is observed. Two criteria that are equally not met carry the same state, serious or not — severity is read in the weight.
- Met
- Checked on every email where the criterion applied.
- Partly met
- Checked on some of them. The detail says which.
- Not met
- Checked on none.
- Not observable
- The criterion did not apply to any email received. It drops out of the denominator and is never counted as a failure.
Two regimes, one single method
The analyzers produce the same findings on every message. What changes with the type of email is the scoring reference: the criteria selected and their weight. A pixel does not carry the same weight in a promotion as in an order confirmation.
- Campaigns
- The full grid, unsubscribe included.
- Transactional
- The same grid without prospecting — unsubscribe is not applicable there — and heavier weights on tracking.
- Type not established
- The common grid only. We do not invent an obligation for an email whose nature is unknown.
How a family is calculated
Each criterion carries a weight, and earns that weight in proportion to the emails where it is met: a 25-point criterion met on four emails out of five earns 20 points. A family's score is the sum of its points over the sum of the weights of its applicable criteria. A criterion that cannot be observed counts in neither the numerator nor the denominator; nor does one outside its scope — it is shown as “not applicable”.
Some criteria are indicators: they answer a question — can the recipient still understand? can they act? — through several observations that count equally. Ranking them would require numbers no source backs up.
The grid, family by family
The weights below are read from the scoring code, at the moment you read this page. A “not applicable” row drops out of the denominator; a row marked bonus never enters it.
| Compliance | Campaigns | Transactional |
|---|---|---|
| No open-tracking pixel | 30 | 35 |
| Unsubscribing is possible and announced · 2 observations | 15 | not applicable |
| The recipient keeps control over tracking · 2 observations · conditional | 20 | 20 |
| The message says who is writing and under which rules · 3 observations | 15 | 20 |
| An untracked path leads to the site | 10 | 15 |
| No recipient identifier in the message | 10 | 10 |
| Deliverability | Campaigns | Transactional |
|---|---|---|
| DKIM signature validated | 20 | 20 |
| DMARC alignment validated | 20 | 20 |
| DMARC policy that helps keep out some impersonation | 15 | 15 |
| No SPF failure | 10 | 10 |
| One-click unsubscribe, as defined by RFC 8058 · 2 observations | 15 | not applicable |
| A DKIM signature that covers what matters · 4 observations | 5 | 5 |
| Technical | Campaigns | Transactional |
|---|---|---|
| HTML under Gmail's clipping threshold | 25 | 25 |
| A shallow template · 1 observations | 20 | 20 |
| Well-formed HTML · 4 observations | 15 | 15 |
| Every link leads somewhere | 10 | 10 |
| No remote stylesheet | 10 | 10 |
| The message follows the shape of an email · 5 observations | 5 | 5 |
| Experience | Campaigns | Transactional |
|---|---|---|
| The message makes sense without its images, from the inbox on · 2 observations | 25 | 25 |
| The message can be rendered outside HTML · 3 observations | 15 | 15 |
| All links stay visible with images blocked | 15 | 15 |
| Tap targets large enough | 10 | 10 |
| The message stays readable with assistive technology · 4 observations | 20 | 20 |
| The message declares its adaptation to screens · 2 observations | 15 | 15 |
| Dark mode declared · bonus | +5 | +5 |
“Conditional”: one of the indicator's observations is measured only in the presence of another — a message that tracks no one is not faulted for missing a tracking setting.
The bonuses
A bonus is a weight that enters the numerator when it is earned, never the denominator: not having it costs nothing, having it pays off. The rule that decides: is not meeting a measure a shortfall? If yes, it's a criterion. If not, but meeting it takes observable work, it's a bonus.
They exist only in Technical et Experience — never in compliance, the family reserved for “here is what could be held against you”, nor in deliverability, whose criteria are verdicts borrowed from the receiving server. The score stays capped at 100.
A brand's overall score
The overall score is the average of the families, weighted by their weight. What the brand risks being held to account for weighs the most; nobody has ever been sent a formal notice over a deep DOM.
- Compliance
- 35
- Deliverability
- 30
- Technical
- 15
- Experience
- 20
It reads in three tiers — high from 80, medium from 55 — with no adjective: “good” or “weak” would add nothing to the figure and would bring it closer to a judgment. A disqualifying finding stays displayed whatever the score: the score never absorbs the alert.
An email's letter grade
The report for an uploaded email carries a letter grade. It does not average: it weighs each family's gap to 100, raised to the power of 1.5, then converts back to a score. A collapsed family costs more than two lukewarm ones, and any repair raises the letter grade — the average used to dilute a collapse, and the worst family used to stay put when the rest was fixed.
note = 100 − ( Σ poids × (100 − famille)^1.5 / Σ poids )^(1/1.5)
- A
- from 90
- B
- from 80
- C
- from 70
- D
- from 60
- E
- from 50
- F
- below
A risk level comes with the letter grade. It is decided first by the heaviest of the missed criteria — 25 points or more makes it critical, 15 or higher — then by the overall score, which can only make it worse. No tier carries a reassuring adjective, and none says “healthy”.
The thresholds, and where they come from
Most criteria rest on a public document — an RFC, a W3C or WHATWG specification, a compatibility table. Each report page cites these sources under the relevant criterion, and we recheck them: a source that no longer responds disappears from the page rather than staying there dead.
A few thresholds have no first-hand source. We own them as choices rather than inventing one for them, and they are read here from the code that applies them:
- Gmail's truncation at 102 KB. An observed behavior that Google documents nowhere and that no compatibility table covers.
- Layout tables, at most 6 nested. No specification sets the limit; email rendering references recommend four to six, and we keep the upper bound. Document depth is no longer scored: it is read in the report, without a threshold.
- At least 200 readable characters without the images. This threshold flags an email that is almost entirely images; it is not the boundary of comprehensibility.
- The existence of an untracked path to the site. No standard requires it. A message where every link passes through a tracker leaves no way to visit the brand without being measured.
- The untracked unsubscribe link. Same reason, on the link that matters most: exercising your objection without being measured one last time.
These thresholds are debatable, and that is why they are named here rather than folded into the others.
08
Versions
Every number on this page has a version, and every archived result carries its own. A score produced under an earlier version is never rewritten: it is recalculated under the new one, alongside, and the gap is there to read.
| Family weighting | v13 | Bumps on any change to a weight, a threshold, or a criterion added or removed. Written on every score. |
|---|---|---|
| Letter-grade calibration | v1 | The exponent and the family weights combined. Distinct from the weighting: bumping it does not force a replay when no family score moves. |
| Analyzers | one per analyzer | See the list in production, section 03. Each finding carries the one that produced it. |
| Check index | v1 | The findings' weights and the tier thresholds for the “Check a suspicious email” tool. |
| Diagnostic scoring scale | pixel-cnil-2026-09 | Stored on every run of the tracking-pixel diagnostic. Retroactive recalculation is forbidden. |
Methods log
Every change of method that moves published findings, dated by the replay that applies it to the archive. An entry is never rewritten: a correction is a new entry.
-
Sign-up confirmation is read on our own sign-ups
An analyser now reads, in the mail that follows each of our sign-ups, whether the brand asks to confirm the subscription: a confirmation link, a button that asks for it, or a subject line the body of the message backs up. It reads twenty-three languages. An account activation is not a request.
A brand counts once. It asks for confirmation if one of its sign-ups received a request; it does not if a campaign arrived with no request before it. A sign-up that got no reply, or only service messages, settles nothing and leaves the base.
No French rule requires this confirmation: the measure describes a practice. Replayed on 17 October 2026 across the whole archive, it gives 46 brands out of 241 on the French market, which the observatory publishes with their base.
-
The tracking pixel is read on the last three campaigns
The “No open-tracking pixel” criterion is now read on a brand's last three campaigns received, no longer on all of them. A brand that removes its pixel sees it in its score within its next three emails; so does a brand that adds one.
The other criteria are still read on all emails received. The page names the window, “on the last 3 campaigns”, as soon as it leaves out an older email, and its header says when our address entered the brand's database.
No weight changes. Scores computed with weighting 12 stay in the database, next to those of weighting 13.
-
The tracking-pixel rule: size, not hiding
A tracking pixel is now recognised by its size, not by its hiding. An image is a pixel if one of three signals holds: a declared dimension of 2 px at most, one of the published open patterns, or a known measurement host, distinct from the brand's own.
An image hidden by its inline style is a pixel only if its address carries a recipient identifier. Hidden by a class or an @media rule, like content images that switch between mobile and desktop, it is not one, whatever its size.
Four open patterns are added: /tr/op/ and /mk/op/ (Brevo), email-open (Veepee), /probe. (Zalando).
Seven sends no longer count a pixel: five Amazon campaigns, from 30 July to 5 September 2026, and two Shopify sends, of 6 June and 6 July 2026. The only signal that flagged them was a hidden content image.
Thirty sends now count one, missed until now because of its 2 px size: Niche Beauty (nineteen), Miliboo (six), Loberon (two), Tennis-Point, Höffner and Sconto (one each).
Brand pages and their sends follow the measurement since the replay. An audit report already delivered on a submitted email keeps the findings and the score of its run.
09
Other tools, same standard
The suspicious-email check
It measures what a message says about itself, never what it is. Each finding carries a weight; their sum is an index, read in three tiers, and the floor grants no clean bill:
- faisceau
- from 35
- isole
- from 1
- aucun
- at 0
The high threshold sits below the weight of the heaviest finding: a single gap can be enough. The only outbound request goes to domain-name registries, never to the sender's site, and no response is a named state, not a blank field.
The tracking-pixel diagnostic
A scoring scale, computed server-side — with no database, no clock, no network — and versioned. It qualifies before it scores: a determining condition is carried by a finding, visible whatever the score. Non-applicable axes drop out of the denominator, and the score is a measure of maturity, never a qualification.
10
Dispute a finding
Every published finding can be replayed identically, with its evidence. If a figure seems wrong to you, tell us the brand and the finding: we republish the calculation and the excerpt that establishes it, and correct it if the error is on our side. An accurate report is not withdrawn at a brand's request.
Check it on one of your emails
The report is given in full, without an account and without leaving an address.