Why your BIMI logo is not showing in Gmail: a debugging guide
The record is published, the SVG validates, and Gmail still shows an initial instead of your logo. Here is every reason that happens, in the order to check them, with the commands to check each one.
You published the record. The validator went green. You sent yourself a test, and Gmail shows a grey circle with the first letter of your company name.
BIMI fails silently. There is no bounce, no header, no "logo rejected because" — the receiver just does not render it. So debugging is a matter of walking the chain in the order the receiver walks it, and confirming each link on a real message rather than in a form. This guide does that for Gmail specifically, because Gmail is the strictest common receiver and the one people care most about.
If you have not set BIMI up yet, start with BIMI explained. This article assumes the record exists.
0. Are you looking at the right thing?
Before DNS, three things that are not bugs:
- Gmail only renders BIMI for messages that land in the inbox. Not Promotions? Yes, Promotions counts. Spam does not. If the test message went to spam, fix that first — Gmail's sender requirements are the checklist.
- Gmail caches. A logo that was invalid an hour ago may take a day or more to be re-evaluated after you fix it. Test with a fresh recipient or wait.
- Gmail needs some sending history on the domain. A brand-new domain with a perfect record and a VMC may still not show a logo for a while. This is not documented precisely and there is nothing to do about it but send legitimate mail.
If the message is in the inbox, the domain has been sending for a few weeks and you have waited a day since the last DNS change, continue.
1. Which domain is the receiver evaluating?
BIMI, like DMARC, is evaluated on the domain in the From: header — the one the recipient sees. Not the envelope sender (MAIL FROM), not the Return-Path, not the DKIM d=.
Look at the message as received. In Gmail: Show original. Or capture the same send in a sandbox and read the raw source. Find the From: line:
From: "Example Co" <hello@mail.example.com>Every check below is about mail.example.com — and, for the fallback lookups, example.com. Teams routinely publish everything on the apex and send from a subdomain the app was configured with two years ago. The receiver does not care what you meant.
2. Does DMARC pass, on that domain, with an enforcing policy?
This is the most common failure. Gmail requires, on the From domain (or its organizational domain if the From domain has no policy of its own):
p=quarantineorp=rejectpct=100(orpctabsent, which means 100)- and the message itself must pass DMARC — aligned SPF or aligned DKIM
Check the policy:
dig +short TXT _dmarc.mail.example.com dig +short TXT _dmarc.example.com
The disqualifiers:
| What you see | Why it fails |
|---|---|
p=none |
Monitoring mode. Not enforcing. |
p=quarantine; pct=10 |
Partial rollout. Gmail requires 100. |
No record on the subdomain, apex has sp=none |
The subdomain policy tag overrides for subdomains. |
A CNAME to a vendor's DMARC service pointing at p=none |
Same as p=none; the CNAME is invisible to the check. |
Then check the result on the received message. The Authentication-Results header written by the receiver is the ground truth:
Authentication-Results: mx.google.com; dkim=pass header.i=@mail.example.com header.s=s1; spf=pass smtp.mailfrom=bounce.example.com; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=mail.example.com
You want dmarc=pass. If you see dmarc=fail with SPF and DKIM both passing, it is an alignment problem: SPF passed on bounce.example.com and DKIM passed on esp-vendor.com, and neither aligns with mail.example.com. Fix by signing DKIM with a selector on your own domain — every serious provider supports custom DKIM.
3. Does the BIMI record resolve, on the right name?
dig +short TXT default._bimi.mail.example.com # fallback, if the above is empty: dig +short TXT default._bimi.example.com
Expected:
"v=BIMI1; l=https://example.com/brand/logo.svg; a=https://example.com/brand/vmc.pem"Failure modes:
- Nothing returned. The record is on a different name than the From domain and the fallback does not apply (fallback only goes to the organizational domain, never to another subdomain).
- Two TXT records at the same name. The lookup is ambiguous; receivers treat it as no record.
- Quotes split badly. Some DNS UIs split long TXT values into multiple quoted strings and insert a space at the split.
l=https://example.com/bra nd/logo.svgis not a URL. - Wrong selector. If you published at
brand._bimi.you must send aBIMI-Selector: v=BIMI1; s=brandheader — and DKIM-sign it. Almost nobody needs a non-default selector; if you used one by accident, move the record todefault.
4. Does the logo pass the Tiny P/S profile — as fetched?
Fetch it the way a receiver does: over HTTPS, following no redirects, without a browser user agent.
curl -sS -o logo.svg -w '%{http_code} %{content_type}\n' https://example.com/brand/logo.svgYou want 200 and image/svg+xml. Then:
301/302— many receivers do not follow redirects for the logo. Pointl=at the final URL.text/htmlorapplication/octet-stream— the server is not serving it as SVG. Fix the content type.403— a WAF or CDN rule blocking non-browser user agents. Receivers look like bots.- A certificate error on the host — the fetch fails outright.
Then validate the file itself, not the one in your repository. A common trap is a build step or CDN that "optimizes" SVGs: SVGO, for instance, strips <title> by default and may remove the baseProfile attribute. The file you validated locally is not the file being served.
The profile requirements, briefly: version="1.2", baseProfile="tiny-ps", a <title>, square viewBox, solid background, no scripts, no external references, no animation, no embedded raster, small. The full list is in BIMI explained.
5. Gmail requires a certificate
If steps 1 to 4 pass and the record has no a= tag: that is the reason. Gmail does not render BIMI logos on a record alone. Yahoo does; Gmail and Apple do not.
You need a Verified Mark Certificate (trademarked logo) or a Common Mark Certificate (logo in use for a year or more). Both are issued by a small number of certificate authorities, both take weeks, both cost money annually.
If the record does have a=, check the certificate:
curl -sSf https://example.com/brand/vmc.pem | openssl x509 -noout -subject -issuer -dates- Expired — VMCs are issued for one year. It is the most common reason a logo that used to show has stopped.
- Wrong domain. The certificate lists the domains it covers in its SAN. The From domain must be covered — a certificate issued for
example.comcovers subdomains only if it says so. - Logo mismatch. The certificate embeds the SVG. If you have updated the logo file since issuance, the hash no longer matches and the certificate is invalid for it. Reissue.
- Not the PEM chain. The
a=URL must serve the certificate and its intermediates, PEM-encoded. A DER file or a leaf-only PEM fails.
6. Everything passes and it still does not show
At this point the chain is correct and the remaining causes are on Gmail's side:
- Reputation. Gmail applies an undocumented reputation gate to BIMI. New domains, domains with recent spam complaints and domains that recently moved to enforcement can wait days to weeks.
- Cache. Re-test with a mailbox that has never received mail from the domain.
- The client. The Gmail web app and the mobile apps render BIMI; Gmail through a third-party IMAP client does not. Apple Mail renders it on its own terms (VMC required, iOS 16+).
There is no support channel for this. Keep sending legitimate mail, keep DMARC enforcing, and check again in a week.
Making this a check, not a ritual
The failures above are almost all drift: the record was right when it was published, and then someone changed the From address, rotated a DKIM selector, let the certificate lapse, or added an SVG optimizer to the build. None of those changes announce themselves as BIMI-breaking.
The durable fix is to check the chain on every message your staging environment sends — not once, at launch, in a browser form. Point staging at a Mailclutch sandbox and every capture reports the From domain's DMARC policy, whether the BIMI record and its logo and certificate resolve, and the SPF/DKIM/DMARC results for the message itself. When a pull request changes the sender, the deliverability score drops on the next staging send, and the diff tells you why — before a customer notices that the logo is gone.
The short version
- Message in the inbox, on a domain with history, tested against a fresh recipient.
- Identify the From domain. Everything is about that domain.
dmarc=passon the received message, andp=quarantine/rejectatpct=100on that domain.default._bimi.<from-domain>resolves to exactly one record, with an HTTPSl=that returns200 image/svg+xmlwith no redirect.- The served SVG — not the one in git — is Tiny P/S.
- For Gmail: an
a=pointing at a current, matching, full-chain VMC or CMC. - Then wait.