rate.email brand book

The measuring instrument for email addresses at signup and checkout.

Version 1.0 · 2026-09-15

Story

rate.email scores an email address before it becomes a customer, and returns one of three verdicts: accept, review or reject. Every verdict carries reason codes, so a merchant can see exactly what the score is made of. The brand behaves like a calibrated instrument: it reports a reading, states its confidence, and leaves the decision to the shop.

What the brand is not: an alarm, a shield, a firewall. No sirens, no padlocks, no threat language. The tone is the tone of a bench instrument manual.

Colour

One accent, a cool graphite neutral ramp, and three verdict hues. The verdict hues are blue shifted on purpose, so red and green confusion does not collapse accept into reject. Colour never carries a verdict alone: an icon and a word always travel with it.

Ultramarine ink, the accent

50100200300400500600700800900

Graphite, the neutral ramp

02550100200300400500600700800900950

Contrast

All pairs below are measured against WCAG 2.1. Every pair passes AA for normal text at 4.5:1. Pairs marked AAA pass 7:1.

RoleForegroundBackgroundRatioLevel
Heading text#10151C#F7F8FA17.24AAA
Body text#38424F#F7F8FA9.59AAA
Muted text#5A6675#F7F8FA5.50AA
Link, accent text#2B3FAE#F7F8FA8.15AAA
Text on accent#F7F8FA#2B3FAE8.15AAA
Accept text#0E7255#E2F4EC5.17AA
Review text#8A5300#FBEEDA5.53AA
Reject text#BC1B45#FCE7EC5.26AA
White on accept fill#FFFFFF#0E72555.90AA
Ink on review fill#10151C#F2B85110.25AAA
White on reject fill#FFFFFF#BC1B456.21AA

Typography

IBM Plex Sans for everything a person reads, IBM Plex Mono for everything a machine produced: scores, reason codes, API payloads, keys, timings. The two faces share skeletons, so a score sitting inside a sentence does not look pasted in. Both are licensed under the SIL Open Font License 1.1.

IBM Plex Sans

Accept, review, reject.

Weights in use: 400 body, 500 labels and buttons, 600 headings. Stack: "IBM Plex Sans", "Segoe UI", "Helvetica Neue", Arial, sans-serif

IBM Plex Mono

score 82 · MX_OK

Weights in use: 400 payloads, 500 numerals in dense UI. Tabular figures on. Stack: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace

Scale

4xl / 2.488rem / 600
Page title
3xl / 2.074rem / 600
Section opener
2xl / 1.728rem / 600
Section heading
xl / 1.44rem / 600
Subheading
lg / 1.2rem / 400
Lede paragraph
md / 1rem / 400
Body copy, the default
sm / 0.917rem / 400
Dense tables and admin grids
xs / 0.833rem / 400
Chips, hints, captions
2xs / 0.694rem / 500
Numeric labels on gauges only

Body line length stays under 68 characters. Line height 1.6 for body, 1.15 for headings. Headings track in at -0.02em. Never set a label in all caps: the product already uses upper case for reason codes, and that distinction has to stay readable.

Verdict badges

Three verdicts, three shapes: a check, a clock, a crossed circle. The shape does the work when colour cannot, which covers colour blindness, grayscale print and the dense Magento grid. The label is always spelled out unless the column is narrower than 90px. The verdict comes from the severities present in the reasons, not from the score, so the badge and the gauge answer two different questions and are never presented as one.

Accept Review Reject
Accept Review Reject

Soft badges are the default. Solid fills are for one place only: the single primary verdict at the top of a detail view. Two solid badges must never appear in the same view.

VerdictRuleIconWhat the merchant does
AcceptNo medium or high reasoncheckLet the order through.
ReviewAny medium reason, no highclockHold and look at the reason codes.
RejectAny high reasoncrossed circleBlock the signup, ask for another address.

Score gauge

The gauge is the one place where the brand raises its voice. It is the logo mark opened out to full size: the same graduations, the scale widened to 240 degrees so five marks fit, and the needle flattened into a cursor that rides the arc, which leaves the centre to the numeral. The cursor moves once, when the reading arrives, and holds. Reduced motion turns the movement off and the cursor simply appears at the reading.

95 / 100
Accept

No medium or high reason. One low reason, NO_DMARC.

65 / 100
Review

Two medium reasons: ROLE_ACCOUNT and CATCH_ALL.

Rules: the numeral is mono and tabular, the track keeps its full 240 degrees at every score, the arc colour follows the verdict and not the number, and the gauge is never used for anything that is not a 0 to 100 score. The score starts at 100 and every reason subtracts from it, so a low score explains a verdict but never sets it.

Reason code chips

Reason codes are printed exactly as the API returns them, in mono upper case. A chip carries a severity dot on the left, matching the four levels the API uses. High and medium decide the verdict. Low trims the score. Info is context and changes nothing. The info dot is hollow rather than a fourth grey, so the four levels stay apart in print and for colour blind readers, and the severity word is always in the tooltip.

DISPOSABLE_DOMAIN NO_MX SPAM_TRAP ROLE_ACCOUNT CATCH_ALL TYPO_SUSPECTED NO_DMARC STALE_RESULT FREE_PROVIDER SUBADDRESS

Never translate a reason code in the UI. Put the plain language sentence next to it, or under it, and keep the code itself searchable. Maximum four chips in a grid cell, then a count: +3

API response

Payload samples are always shown on the code surface, a dark inset block, so a code block reads as machine output rather than page content. The sample follows the response contract in spec/openapi.yaml, field for field, because a brand book that drifts from the API teaches the wrong shape.

{
  "email": "J.Kowalski+shop@Mailinator.com",
  "normalized": "j.kowalski@mailinator.com",
  "local_part": "j.kowalski",
  "domain": "mailinator.com",
  "verdict": "reject",
  "score": 35,
  "reasons": [
    {
      "code": "DISPOSABLE_DOMAIN",
      "severity": "high",
      "source": "allowlist:disposable",
      "message": "mailinator.com is a known disposable email domain."
    },
    {
      "code": "SUBADDRESS",
      "severity": "info",
      "source": "syntax",
      "message": "Plus-addressing detected; normalized form removes the tag."
    }
  ],
  "checks": {
    "syntax": { "valid": true, "rfc5322": true, "suggestion": null },
    "domain": { "resolves": true, "mx": ["mailinator.com"], "spf": true, "dmarc": "none", "age_days": null },
    "provider": { "type": "disposable", "name": "Mailinator" },
    "deliverability": { "status": "skipped", "provider": null, "checked_at": null }
  },
  "cache": { "hit": false, "age_seconds": 0, "ttl_seconds": 21600 },
  "meta": { "request_id": "01J8Z3F1QK9X7N2M5T6R8W0V4B", "latency_ms": 38, "version": "2026-09-15" }
}

Syntax colours: keys ultramarine 300, strings accept 300, numbers review 300, literals reject 300, punctuation muted. Four hues, same family as the rest of the system, no rainbow theme.

Buttons and inputs

Buttons

One primary action per view. Labels name the action, and the result keeps the same word: "Run a check" produces "Check complete". No arrows appended to labels. Corner radius 3px on every control, because the system reads as a panel, not as cards.

Inputs

Checked against MX, disposable lists and typo patterns.
Key rejected. Copy the key again from the dashboard.

Inputs that hold machine values are set in mono. Focus is a 1px accent border plus a 3px accent ring, never a colour change alone.

Iconography

Icons are drawn on a 24 grid with a 2.2px stroke, round caps, round joins and no fill except the needle pivot. Every icon is built from the dial vocabulary: circle, arc, tick, needle. Nothing in the set may be a shield, a padlock, a siren or a warning triangle, and the envelope appears only when the subject really is a message and not an address.

accept
review
reject
score
domain
api key

Icons take the colour of the text they sit with. A verdict icon is never shown without its label or an accessible name.

Voice and tone

Report the reading, name the next step, stop. The product talks about addresses and domains, never about people. Words like fraudster, attacker, threat and protection stay out, because the API does not know intent, it knows signals.

Do

State the measurement. Give the number before the adjective. Use sentence case. Say what the merchant can do next. Name a verdict by its exact word: accept, review, reject.

Do not

No threat language. No exclamation marks. No apologies in errors. No hedging like "may possibly". No marketing adjectives on a score.

Microcopy

  • empty state, dashboardNo checks yet. Send your first address to POST /v1/rate.
  • error, invalid keyAPI key rejected. Copy the key again from the dashboard, then save.
  • error, rate limitRate limit reached at 1000 checks per minute. Retry in 12 seconds.
  • tooltip, review verdictHeld for review. The domain accepts every address, so delivery cannot be confirmed.
  • config help, MagentoPick what happens on each verdict. The score explains the verdict, it does not set it.

For the Magento admin

In a Magento grid the verdict gets one column, often under 110px, next to a UI kit the brand does not control. The rules: keep the icon, keep the score, drop the word when the column is narrower than 90px, and never restyle the surrounding grid. Adminhtml owns the table, rate.email owns one cell.

IDEmailrate.emailReasonsCreated
10241anna.w@gmail.com95 AcceptNO_DMARC FREE_PROVIDER2026-09-15 08:12
10242office@nowa-firma.pl65 ReviewROLE_ACCOUNT CATCH_ALL2026-09-15 08:31
10243j.kowalski@mailinator.com35 RejectDISPOSABLE_DOMAIN +12026-09-15 08:44

Narrow column, 88px

95
65
35

The compact cell keeps an accessible name on the icon, for example aria-label="Reject, score 35", so the column is readable by screen reader and in grayscale export. Column filters use the verdict words, not the colours.