Send one message to a disposable address and 42 checks run against it. This page is all of them: what each one looks at, what it costs your score when it fails, and the section of the standard it comes from.
Nothing here is our opinion dressed as a rule. Where a check enforces something a standard says, the sentence from that standard is quoted underneath it. Where it enforces something Google or Yahoo requires instead, their page is linked. Where it is our own judgement, it says so.
Authentication
Whether the receiving server can prove the message came from where it says. This is the half of deliverability that is pure DNS, and the half Gmail and Yahoo made mandatory for bulk senders in 2024.
ARC chain auth.arc
ARC preserves the authentication result across a forwarder. Without it, a mailing list that appends a footer breaks your DKIM signature and the forwarded copy fails DMARC at the far end.
If it fails: Nothing to do as a sender. This matters if you run a list or a forwarder, and it explains why some of your mail fails DMARC after somebody forwards it.
Costs up to 2 points of 100 on our score.
RFC 7960 §1 — Introduction
DMARC with restrictive policies causes problems for many Mailing Lists.
RFC 8617 §2.1 — Evidence
In ARC's situation, the "evidence" is a message's authentication assessment at any point along the delivery path between origination and final delivery.
Google — Sender guidelines FAQ: rules for 5,000+ messages a day
DKIM signature auth.dkim
DKIM signs parts of the message with a private key and publishes the public key in DNS. We verify every signature the message carries and report the signing domain, the selector and the key length.
If it fails: Turn on DKIM at your sending platform and publish the key it gives you. Use 2048 bits: 1024 still verifies, but a key that short can be cracked and is no longer safe.
Costs up to 18 points of 100 on our score and up to 1 of 10 on the classic score.
RFC 6376 §3.5 — The DKIM-Signature Header Field
The signature of the email is stored in the DKIM-Signature header field.
RFC 6376 §6.1 — Extract Signatures from the Message
Verifiers MUST NOT attribute ultimate meaning to the order of multiple DKIM-Signature header fields.
RFC 8301 §3.1 — Signing and Verification Algorithms
rsa-sha1 MUST NOT be used for signing or verifying.
RFC 8463 §6 — Transition Considerations
For backward compatibility, signers can add multiple signatures that use old and new signing algorithms.
Google — Set up DKIM
Google — Sender guidelines FAQ: rules for 5,000+ messages a day
DKIM alignment auth.dkim_alignment
A valid signature is not enough for DMARC. The signing domain has to match the domain in the From header, exactly or by organisational domain depending on the policy you published.
If it fails: Sign with your own domain rather than your platform's. Most platforms support this and call it a custom or authenticated sending domain.
Costs up to 10 points of 100 on our score and up to 1 of 10 on the classic score.
RFC 9989 §4.4.1 — DKIM-Authenticated Identifiers
A single email can contain multiple DKIM signatures, and it is considered to produce a DMARC "pass" result if any DKIM-Authenticated Identifier aligns with the Author Domain.
Google — Set up DMARC
Google — Sender guidelines FAQ: rules for 5,000+ messages a day
DMARC result auth.dmarc
DMARC ties SPF and DKIM to the domain your reader sees and tells receivers what to do when neither aligns. We report the published policy and whether this message satisfied it.
If it fails: Publish a DMARC record. Start at p=none, read the reports for a few weeks, then move to quarantine once you know what else sends as you.
Costs up to 14 points of 100 on our score.
RFC 9989 §5.3.5 — Determine DMARC "Pass" or "Fail"
If no Authenticated Identifiers exist for the domain, or none of the Authenticated Identifiers align with the Author Domain, the message is considered to fail the DMARC mechanism check.
RFC 9989 §4.7 — DMARC Policy Record Format
DMARC Policy Records follow the extensible "tag-value" syntax for DNS-based key records defined in DKIM [RFC6376].
Google — Sender guidelines FAQ: rules for 5,000+ messages a day
Yahoo — Sender requirements and recommendations
Sender ID auth.sender_id
The same check as SPF, run against the domain in the From header rather than the envelope. It answers a different question: whether the domain your reader sees authorises the server that sent the message. A message can pass SPF on its envelope while the visible domain vouches for nobody.
If it fails: Publish SPF for the domain in your From header, not only for the bounce domain your platform gave you.
Costs up to 5 points of 100 on our score and up to 0.5 of 10 on the classic score.
RFC 4406 §4 — Record Selection
After the above steps, there should be one record remaining and evaluation can proceed.
SPF auth.spf
SPF is a DNS record listing which servers may send for your domain. The receiving server takes the address in the envelope, looks up that domain's record and checks whether the connecting IP is in it. We report the result and the number of DNS lookups the record needed, because evaluation stops at ten and anything past that is a permanent error rather than a pass.
If it fails: Publish a record that names your sending platform and nothing else. If yours is close to the ten-lookup limit, flatten the includes you do not use (a record that passes today starts failing the day a provider adds an include of its own).
Costs up to 18 points of 100 on our score and up to 1 of 10 on the classic score.
RFC 7208 §4.6.4 — DNS Lookup Limits
SPF implementations MUST limit the total number of those terms to 10 during SPF evaluation, to avoid unreasonable load on the DNS. If this limit is exceeded, the implementation MUST return "permerror".
RFC 7208 §2.6 — Results of Evaluation
Section 4 defines check_host(), a model function definition that uses the inputs defined above and the sender's policy published in the DNS to reach a conclusion about client authorization.
Google — Set up SPF
Google — Sender guidelines FAQ: rules for 5,000+ messages a day
SPF alignment auth.spf_alignment
Whether the bounce address matches the From address a reader sees. SPF authorises the envelope, and DMARC only counts that authorisation when the two align.
If it fails: Ask your sending platform for a bounce subdomain of your own domain. If your DKIM is already aligned this is not urgent, but it leaves you without a fallback when DKIM breaks in transit.
Costs up to 5 points of 100 on our score and up to 0.5 of 10 on the classic score.
RFC 9989 §4.4.2 — SPF-Authenticated Identifiers
Only an SPF-Authenticated Identifier that has Identifier Alignment with the Author Domain is enough to validate the authorized use of the Author Domain.
RFC 9989 §5.3.5 — Determine DMARC "Pass" or "Fail"
If one or more of the Authenticated Identifiers align with the Author Domain, the message is considered to pass the DMARC mechanism check.
Google — Set up DMARC
Google — Sender guidelines FAQ: rules for 5,000+ messages a day
Infrastructure and reputation
The machine and the address the message was sent from, and what the rest of the internet already thinks of them.
Sending hostname resolves infra.a_record
Whether the hostname announced at HELO has an address record at all.
If it fails: Publish an A record for the name your server announces.
Costs up to 5 points of 100 on our score and up to 3 of 10 on the classic score.
RFC 5321 §5.1 — Locating the Target Host
If an empty list of MXs is returned, the address is treated as if it was associated with an implicit MX RR, with a preference of 0, pointing to that host.
Google — Set up MX records
Blocklists infra.dnsbl
Whether the sending IP is listed by any of the blocklists receivers actually consult. Our roster is checked against each zone's own documented test point rather than assembled from a web search, because a dead zone answers NXDOMAIN and that reads as "clean".
If it fails: Follow the delisting process on the listing operator's site. A listing on a major zone stops mail outright, so treat it before anything else on the page.
Costs up to 25 points of 100 on our score and up to 3 of 10 on the classic score.
RFC 5782 §2.1 — IP Address DNSxL
Each IPv4 address listed in the DNSxL has a corresponding DNS entry.
RFC 5782 §5 — Test and Contact Addresses
IPv4-based DNSxLs MUST contain an entry for 127.0.0.2 for testing purposes.
Google — Postmaster Tools: reputation and delivery errors
Google — Email sender guidelines
HELO name infra.helo
The name the sending server announces itself as at the start of the SMTP conversation. It has to be a fully qualified domain that resolves.
If it fails: Set your mail server's hostname to a real name in your domain, not to a container id or an internal name.
Costs up to 5 points of 100 on our score.
RFC 5321 §4.1.1.1 — Extended HELLO (EHLO) or HELLO (HELO)
The argument clause contains the fully-qualified domain name of the SMTP client, if one is available.
Google — Email sender guidelines
Google — Sender guidelines FAQ: rules for 5,000+ messages a day
MX record infra.mx
Whether the domain in your From header can receive mail. Replies and bounces have nowhere to go without it, and filters treat a sending domain that cannot receive as a bad sign.
If it fails: Publish an MX record for the domain you send from, even if it only routes to a mailbox you read once a month.
Costs up to 5 points of 100 on our score and up to 3 of 10 on the classic score.
RFC 5321 §5.1 — Locating the Target Host
The lookup first attempts to locate an MX record associated with the name.
Google — Set up MX records
Reverse DNS infra.rdns
Whether the sending IP resolves back to a hostname, and whether that hostname resolves forward to the same IP. The round trip is the point: a PTR pointing anywhere is easy, a matching pair is evidence the address is yours.
If it fails: Ask whoever owns the IP to set the PTR to a name you control, and make sure that name has an A record pointing back.
Costs up to 12 points of 100 on our score and up to 1.5 of 10 on the classic score.
RFC 1912 §2.1 — Inconsistent, Missing, or Bad Data
Make sure your PTR and A records match. For every IP address, there should be a matching PTR record in the in-addr.arpa domain.
Google — Email sender guidelines
Google — Sender guidelines FAQ: rules for 5,000+ messages a day
Transport encryption infra.tls
Whether the message arrived over TLS, and with which cipher. Everything modern negotiates it; a message arriving in the clear says something about the sending setup.
If it fails: Enable STARTTLS on the sending server. Every mainstream platform does this already, so a failure here usually means a self-hosted relay in the path.
Costs up to 5 points of 100 on our score.
RFC 3207 §2 — STARTTLS Extension
The STARTTLS extension to SMTP is laid out as follows:
Google — Send email over a secure TLS connection
Google — Sender guidelines FAQ: rules for 5,000+ messages a day
Spam engines
What independent content filters make of the message. Two engines rather than one, because a single engine's score is that engine's opinion.
AI judge spam.ai_judge
A model estimates how a modern machine-learning filter would treat the message, from the technical findings and the content measurements. It sees the facts, not the body text.
If it fails: Detail only on its own. Its estimate feeds the combined verdict below.
Shown for detail. Never scored.
Combined verdict spam.panel
One number from the engines that answered, weighted so the loudest is not simply averaged away. SpamAssassin and Postmark count as a single vote because they share a rule base.
If it fails: Work through the individual findings. This row moves when they do.
Costs up to 25 points of 100 on our score.
Google — Why Gmail marks messages as spam
How this score is calculated
Postmark SpamCheck spam.postmark
A third opinion, off by default. Its endpoint takes the whole message and we cannot redact any of it without destroying what is being measured, so switching it on means accepting that every tested message is copied to a third party.
If it fails: Nothing to do. When it is off the check reports that it is off, which is not the same as a pass.
Shown for detail. Never scored.
Rspamd spam.rspamd
A second, independently developed filter. It disagrees with SpamAssassin often enough to be worth asking, which is the reason it is here.
If it fails: Detail only. This engine's opinion is folded into the combined verdict rather than scored on its own.
Shown for detail. Never scored.
SpamAssassin spam.spamassassin
The classic rule-based filter, still the engine behind most email testing tools. Every rule that fired is listed with its weight.
If it fails: Read the rules that fired rather than the total. Most are cheap to clear once you can see which ones they are.
Costs up to 3 of 10 on the classic score.
Google — Why Gmail marks messages as spam
Apache SpamAssassin — rule documentation
Content
The message itself: its structure, its links, its images, the things a filter reads before it decides.
Image alt text content.alt_attributes
Whether images carry alt attributes. Mail clients block remote images by default, so for the first few seconds the alt text is your message.
If it fails: Write alt text that carries the meaning, and never leave the main visual without one.
Costs up to 4 points of 100 on our score and up to 0.5 of 10 on the classic score.
Google — Email sender guidelines
Link availability content.broken_links
Whether the links in the message resolve. A dead link in a newsletter costs trust immediately, and filters notice too.
If it fails: Fix or remove them. Check the tracking domain as well: an expired one breaks every link at once.
Costs up to 5 points of 100 on our score and up to 1 of 10 on the classic score.
Google — Why Gmail marks messages as spam
Script and iframe content.forbidden_tags
Whether the HTML contains tags no mail client will run. They are stripped at best and treated as an evasion signal at worst.
If it fails: Remove script, iframe, object and embed. Anything interactive belongs behind a link.
Costs up to 10 points of 100 on our score and up to 1 of 10 on the classic score.
Google — Email sender guidelines
Text to HTML balance content.html_text_ratio
How much of the message is markup against how much is readable text. A page of markup wrapped around one sentence is a shape filters recognise.
If it fails: Write a text part that says what the HTML says, rather than a placeholder.
Costs up to 3 points of 100 on our score and up to 0.3 of 10 on the classic score.
RFC 2046 §5.1.4 — Alternative Subtype
Systems should recognize that the content of the various parts are interchangeable.
Google — Why Gmail marks messages as spam
Text and HTML parts content.html_version
Whether the message carries a plain text alternative alongside the HTML. Some filters weigh its absence, and every screen reader wants one.
If it fails: Send multipart/alternative with a real text version, not an empty part or a line saying to view it in a browser.
Costs up to 5 points of 100 on our score.
RFC 2046 §5.1.4 — Alternative Subtype
The "multipart/alternative" type is syntactically identical to "multipart/mixed", but the semantics are different. In particular, each of the body parts is an "alternative" version of the same information.
Google — Email sender guidelines
HTML size content.html_weight
How large the HTML part is. Gmail clips a message past roughly 102 KB and hides the rest behind a link, which takes your unsubscribe footer with it.
If it fails: Trim inline CSS and repeated style blocks (most templates fit in a third of the limit once the unused rules are gone).
Costs up to 3 points of 100 on our score and up to 0.3 of 10 on the classic score.
Google — Email sender guidelines
Image weight content.images_weight
The total size of the images the message pulls in. Heavy images make a message slow on a phone, and image-only mail is a shape filters treat with suspicion.
If it fails: Compress them and make sure the message still reads with images off.
Costs up to 3 points of 100 on our score and up to 0.3 of 10 on the classic score.
Google — Email sender guidelines
Visible link destinations content.link_mismatch
Compares explicit domains in link text with the destination reached after HTTP redirects. Normal tracking redirects that reach the displayed site are accepted. A mismatch is a readability and trust warning, not proof of phishing.
If it fails: Use the actual destination domain as the label or use descriptive text. If the destination could not be reached, retry after fixing the link.
Costs up to 3 points of 100 on our score.
Google — Email sender guidelines
Link reputation content.malicious_links
Checks URLs against threat lists. A listing does not prove that every recipient will block the message.
If it fails: Inspect the flagged destinations and replace or remove unsafe links before sending. A historical record alone does not establish a current infection.
Costs up to 40 points of 100 on our score.
Google — Why Gmail marks messages as spam
Attachment scanning content.malware
Whether attachments carry known malware. On deployments where the scanner is switched off, this reports that it did not run rather than reporting clean.
If it fails: If this fires, stop sending and find out what is on the machine that built the message.
Costs up to 60 points of 100 on our score.
Google — Why Gmail marks messages as spam
ClamAV — how detection works
Subject line content.subject
Length, capitalisation and the patterns filters score. We measure the decoded subject, so a Cyrillic or CJK line is judged as text rather than as its encoding.
If it fails: Keep it under about 60 characters, drop the shouting and the exclamation marks.
Costs up to 3 points of 100 on our score.
RFC 5322 §2.2 — Header Fields
Header fields are lines beginning with a field name, followed by a colon (":"), followed by a field body, and terminated by CRLF.
RFC 2047 §2 — Syntax of encoded-words
An 'encoded-word' is defined by the following ABNF grammar.
Google — Why Gmail marks messages as spam
Shortened links content.url_shortener
Whether links go through a public shortener. Shorteners hide the destination, which is exactly what filters are trained to distrust.
If it fails: Link your own domain, or use your platform's tracking domain on a subdomain of yours.
Costs up to 5 points of 100 on our score and up to 0.5 of 10 on the classic score.
Google — Why Gmail marks messages as spam
Bulk sender rules
The requirements Gmail and Yahoo publish for anyone sending in volume. These apply to mailings and are skipped for messages that do not look like one.
DMARC policy published compliance.dmarc_present
Whether the From domain publishes a DMARC record at all, separately from whether this message passed it. Gmail and Yahoo require one from bulk senders.
If it fails: Publish a record. p=none is enough to satisfy the requirement and gives you reports to work from.
Costs up to 6 points of 100 on our score.
RFC 9989 §4.7 — DMARC Policy Record Format
If this tag is not present in an otherwise syntactically valid DMARC Policy Record, then the record is treated as if it included "p=none".
Google — Sender guidelines FAQ: rules for 5,000+ messages a day
Yahoo — Sender requirements and recommendations
List-Unsubscribe compliance.list_unsubscribe
Whether the message carries an unsubscribe header a mail client can act on. Gmail and Yahoo require it from bulk senders, and its absence is filtered on regardless of everything else. The rule is for mailings. A letter that asks the recipient to confirm a subscription, or tells them it went through, is sent to one person about something they just did; CAN-SPAM calls that a transactional or relationship message, and neither Gmail nor Yahoo asks for an unsubscribe header on it. So this check reads the letter first. A subscription confirmation, a welcome letter, a transactional letter or a notification without list headers is not charged, and the report says what the letter was taken for. A welcome letter padded with offers is in effect the first issue of the mailing; without list headers the check cannot tell the two apart, and it does not charge on a guess. If the letter carries List-Unsubscribe or List-Id, you declared it list mail yourself, and the check runs as it always did.
If it fails: Add a List-Unsubscribe header with an HTTPS URI. Every sending platform can do this.
Costs up to 10 points of 100 on our score and up to 1 of 10 on the classic score.
RFC 2369 §3.2 — List-Unsubscribe
The List-Unsubscribe field describes the command (preferably using mail) to directly unsubscribe the user (removing them from the list).
Google — Sender guidelines FAQ: rules for 5,000+ messages a day
Yahoo — Sender requirements and recommendations
One-click unsubscribe compliance.one_click_unsubscribe
The stricter form: an HTTPS URI, a "List-Unsubscribe-Post" header, and a single valid DKIM signature covering both headers. All three, or the receiver does not show the button. Like the List-Unsubscribe check, it applies to mailings, not to a confirmation or a welcome letter.
If it fails: The usual miss is the signature: platforms sign "List-Unsubscribe" and forget "List-Unsubscribe-Post". Both header names have to appear in the h= tag of the same signature.
Costs up to 8 points of 100 on our score.
RFC 8058 §4 — Additional Requirements
The List-Unsubscribe and List-Unsubscribe-Post headers MUST be covered by the signature and included in the "h=" tag of a valid DKIM-Signature header field.
RFC 8058 §3.1 — Mail Senders
The List-Unsubscribe header field MUST contain one HTTPS URI.
Google — Sender guidelines FAQ: rules for 5,000+ messages a day
Yahoo — Sender requirements and recommendations
TLS for bulk mail compliance.tls_required
Whether the message arrived encrypted. Covered by the infrastructure check when that one has already run.
If it fails: See the transport encryption check above.
Costs up to 5 points of 100 on our score.
Google — Send email over a secure TLS connection
Google — Sender guidelines FAQ: rules for 5,000+ messages a day
Recommendations
Worth doing and never scored. Nothing in this section can cost points, which is a product decision the tests enforce.
BIMI advisory.bimi
Whether the domain publishes a BIMI record, which puts a logo next to your messages in some clients. It needs an enforcing DMARC policy first, and a verified mark certificate that costs money.
If it fails: Worth doing once DMARC is at quarantine or reject and the volume justifies the certificate.
Advisory. Costs nothing.
BIMI — draft specification, not yet an RFC
DKIM key age and length advisory.dkim_key_rotation
The length of the signing key and how long it has been in use. Short keys are cheaper to attack offline every year that passes.
If it fails: Move to 2048 bits and rotate on a schedule. Publish the new selector, switch signing to it, then retire the old one.
Advisory. Costs nothing.
RFC 8301 §3.2 — Key Sizes
Since short RSA keys more easily succumb to off-line attacks, Signers MUST use RSA keys of at least 1024 bits for all keys. Signers SHOULD use RSA keys of at least 2048 bits.
Google — Set up DKIM
DMARC report delivery advisory.dmarc_reporting
Whether the addresses in your DMARC record will actually receive anything. If a report address is outside your own domain, RFC 9990 makes that domain publish its own permission first, as a TXT record at your-domain._report._dmarc.their-domain. Without it a receiver drops the address: no bounce, no error, no report. This is the ordinary setup rather than an unusual one, because the address is normally at a monitoring vendor, or at your main domain while the policy sits on a sending subdomain. The same rule covers failure reports, with RFC 9991 pointing at the same procedure for the ruf tag. We look up the same records a receiver would and show you the names we asked for.
If it fails: Ask whoever runs the destination domain to publish a TXT record containing v=DMARC1 at the name shown in the finding. Monitoring vendors usually do this for you once you add the domain to their account, so if the record is missing the domain was probably never added on their side. If the reports go to your own domain instead, nothing is needed.
Advisory. Costs nothing.
RFC 9990 §4 — Verifying External Destinations
When a Mail Receiver discovers a DMARC Policy Record in the DNS, and the Organizational Domain at which that record was discovered is not identical to the Organizational Domain of the host part of the authority component of a [RFC3986] specified in the "rua" tag, the following verification steps MUST be taken:
RFC 9990 §4 — Verifying External Destinations
Where the above algorithm fails to confirm that the external reporting was authorized by the Report Consumer, the URI MUST be ignored by the Mail Receiver generating the report.
RFC 9991 §5 — Verifying External Destinations
In case of external destinations, a Mail Receiver who generates failure reports MUST use the Verifying External Destinations procedure described in Section 4 of [RFC9990], substituting the "ruf" tag where the "rua" tag appears in that procedure.
Google — Set up DMARC
DNSSEC advisory.dnssec
Whether the domain is signed. SPF, DKIM and DMARC all live in DNS, so an attacker who can forge DNS answers can forge all three.
If it fails: Enable it at your registrar. It is usually one switch, and the registrar handles the rest.
Advisory. Costs nothing.
RFC 4033 §2 — Definitions of Important DNSSEC Terms
Authentication Chain: An alternating sequence of DNS public key (DNSKEY) RRsets and Delegation Signer (DS) RRsets
MTA-STS advisory.mta_sts
Whether the domain publishes a policy telling other servers to refuse unencrypted delivery to you. It protects mail sent to you rather than mail you send.
If it fails: Publish the TXT record and the policy file over HTTPS (an afternoon of work, and it closes a downgrade attack).
Advisory. Costs nothing.
RFC 8461 §3 — Policy Discovery
To discover if a recipient domain implements MTA-STS, a sender need only resolve a single TXT record.
Return path length advisory.return_path_length
How long the bounce address is. RFC 5321 obliges a receiving server to accept 64 octets before the @, and says in the same section that no implementation should impose a limit it can avoid. Plenty impose one anyway, and a message over the line is refused at MAIL FROM, before the body is even sent. Sending platforms run into this by encoding the recipient into the return path so bounces can be matched back, which makes the length depend on who you are writing to rather than on you.
If it fails: Shorten the fixed part your platform prepends, or switch the bounce domain to a shorter one. If you cannot change either, the addresses at risk are your longest subscribers, so it is worth measuring the worst one on your list rather than an average.
Advisory. Costs nothing.
RFC 5321 §4.5.3.1.1 — Local-part
The maximum total length of a user name or other local-part is 64 octets.
RFC 5321 §4.5.3.1 — Size Limits and Minimums
Every implementation MUST be able to receive objects of at least these sizes.
Haraka — the address parser that enforces the 64-octet local-part, and the flag that relaxes it
TLS reporting advisory.tls_rpt
Whether the domain asks for reports when somebody fails to deliver to it over TLS. Pairs with MTA-STS: the policy without the reporting leaves you unable to tell whether it is working.
If it fails: Add the TXT record with an address that receives the daily reports.
Advisory. Costs nothing.
RFC 8460 §3 — Reporting Policy
A domain publishes a record to its DNS indicating that it wishes to receive reports.